Coverage for centralnicreseller/apiconnector/idnaprocessor.py: 85%
27 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-19 19:53 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-19 19:53 +0000
1import idna
2import re
5class IDNAProcessor:
6 NON_TRANSITIONAL_TLDS = re.compile(
7 r"\.(?:art|be|ca|de|swiss|fr|pm|re|tf|wf|yt)\.?$", re.IGNORECASE
8 )
10 @staticmethod
11 def is_transitional_processing(domain_name: str) -> bool:
12 """
13 Returns True when the domain name should use transitional processing, which
14 is every TLD except those in NON_TRANSITIONAL_TLDS (matched case-insensitively
15 at the end of the name). Those keep the deviation characters (ß, ς, ZWJ,
16 ZWNJ) instead of mapping them.
17 """
18 return not bool(IDNAProcessor.NON_TRANSITIONAL_TLDS.search(domain_name))
20 @staticmethod
21 def to_ascii(domain_name, use_transitional=None):
22 if use_transitional is None:
23 use_transitional = IDNAProcessor.is_transitional_processing(domain_name)
24 try:
25 if use_transitional:
26 domain_name = idna.uts46_remap(domain_name, transitional=True)
27 return idna.encode(domain_name).decode("ascii")
28 except idna.IDNAError as e:
29 raise ValueError(f"Unable to translate {domain_name} to ASCII: {e}")
31 @staticmethod
32 def to_unicode(domain_name, use_transitional=None):
33 if use_transitional is None:
34 use_transitional = IDNAProcessor.is_transitional_processing(domain_name)
35 try:
36 if use_transitional:
37 return idna.decode(domain_name, uts46=True)
38 else:
39 return idna.decode(domain_name)
40 except idna.IDNAError as e:
41 raise ValueError(f"Unable to translate {domain_name} to Unicode: {e}")