Internationalized Domain Names in Applications (IDNA)
Support for Internationalized Domain Names in Applications
(IDNA) and Unicode IDNA
Compatibility Processing. It
supersedes the standard library's encodings.idna, which only
implements the 2003 specification, offering broader script coverage and
limiting domains with known security vulnerabilities.
Usage
Package may be installed from PyPI via
the typical methods (e.g. python3 -m pip install idna)
For typical usage, the encode and decode functions will take a
domain name argument and perform a conversion to ASCII-compatible encoding
(known as A-labels), or to Unicode strings (known as U-labels)
respectively.
>>> import idna >>> idna.encode('ドメイン.テスト') b'xn--eckwd4c7c.xn--zckzah' >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) ドメイン.テスト
Conversions can be applied at a per-label basis using the ulabel or
alabel functions for specialized use cases.
Compatibility Mapping (UTS #46)
This library provides support for Unicode IDNA Compatibility Processing which normalizes input from different potential ways a user may input a domain prior to performing the IDNA conversion operations. This functionality, known as a mapping, is considered by the specification to be a local user-interface issue distinct from IDNA conversion functionality.
For example, "Königsgäßchen" is not a permissible label as capital letters are not allowed. UTS 46 will convert this into lower case prior to applying the IDNA conversion.
>>> import idna >>> idna.encode('Königsgäßchen') ... idna.core.InvalidCodepoint: Codepoint U+004B at position 1 of 'Königsgäßchen' not allowed >>> idna.encode('Königsgäßchen', uts46=True) b'xn--knigsgchen-b4a3dun' >>> idna.decode('xn--knigsgchen-b4a3dun') 'königsgäßchen'
When performing a decode operation for display purposes, decode()
accepts a display=True argument that leaves any xn-- label that
fails to decode unchanged. This is useful for user interface display
where a domain is in use, the A-label form can be presented when it
is not a valid IDN.
Exceptions
All errors raised during conversion derive from the idna.IDNAError
base class. The more specific exceptions are:
idna.IDNABidiError— raised when a label contains an illegal combination of left-to-right and right-to-left characters.idna.InvalidCodepoint— raised when a label contains a codepoint that is INVALID for IDNA.idna.InvalidCodepointContext— raised when a CONTEXTO or CONTEXTJ codepoint appears in a position whose contextual requirements are not satisfied.
Exceptions carry machine-readable attributes so that applications
do not need to parse the message: code is a short, stable identifier
for the rule that failed (listed below); and, when the failure can be
attributed to a particular character, text (the label, or domain for
UTS 46 processing, being validated), codepoint (the offending
codepoint as an integer) and position (its 1-based index within
text, as quoted in the message) are set. Each is None when it does
not apply. Message wording is not part of the API and may change.
>>> try: ... idna.encode('Königsgäßchen') ... except idna.IDNAError as err: ... print(err.code, err.codepoint, err.position, err.text) disallowed_codepoint 75 1 Königsgäßchen
code |
Meaning |
|---|---|
input_too_long |
Input exceeds the library's defensive length limit and was not processed |
label_too_long |
A label exceeds 63 octets |
domain_too_long |
The domain exceeds 253 octets |
empty_label |
A label is empty (e.g. consecutive dots) |
empty_domain |
The domain is empty |
not_nfc |
The label is not in Unicode Normalization Form C |
hyphen_3_4 |
The label has hyphens in the 3rd and 4th positions |
hyphen_start_end |
The label starts or ends with a hyphen |
leading_combiner |
The label starts with a combining mark |
disallowed_codepoint |
A codepoint is DISALLOWED or UNASSIGNED under IDNA 2008 |
contextj |
A CONTEXTJ codepoint (joiner) appears in an invalid context |
contexto |
A CONTEXTO codepoint appears in an invalid context |
unknown_codepoint |
A codepoint next to a joiner is unknown to this Python's Unicode database |
bidi_rule_1 … bidi_rule_6 |
The corresponding rule of RFC 5893 (the Bidi Rule) is violated |
bidi_unknown_direction |
A codepoint's directionality is unknown to this Python's Unicode database |
invalid_alabel |
An xn-- label is malformed or is not valid Punycode |
non_canonical_alabel |
An xn-- label is not the canonical Punycode encoding of its U-label (a "fake A-label") |
invalid_ascii |
Byte input is not ASCII |
invalid_utf8 |
Byte input is not UTF-8 |
uts46_disallowed |
A codepoint is disallowed by the UTS 46 mapping table |
uts46_std3 |
An ASCII character is rejected by the UTS 46 STD3 rules |
unsupported_errors |
The codec was given an errors handler other than strict |
Command-line tool
The package supports command-line usage to convert domain names
between their Unicode and ASCII-compatible forms. It can be run either
as a module (python3 -m idna) or, once installed (such as with uv tool or pipx), via the idna script:
$ uv tool install idna $ idna xn--e1afmkfd.xn--p1ai пример.рф $ idna пример.рф xn--e1afmkfd.xn--p1ai
Mode can be specified with -e/--encode or -d/--decode, otherwise
it will be chosen automatically based on the first input. Multiple
domains can be supplied either as arguments or through standard input.
UTS #46 mapping is applied by default, which lets the tool accept
inputs that aren't strictly valid IDNA 2008 by normalising them first,
pass --strict to disable UTS #46.
Conversion failures are reported on stderr together with the offending input; processing continues with the remaining domains and the tool exits with a non-zero status if any conversion failed.
Additional Notes
-
Version support. This library supports Python 3.9 and higher. As this library serves as a low-level toolkit for a variety of applications, we strive to support all versions of Python that are not beyond end-of-life.
-
Unicode version. The IDNA and UTS #46 lookup tables are generated from a specific Unicode release, available as
idna.unicode_version(and shown byidna --version). Some checks — NFC normalisation, bidirectional classes and combining classes — still come from the running Python'sunicodedatamodule, so on an older Python a character new to Unicode may be rejected (typically with theunknown_codepointorbidi_unknown_directionerror codes) even though the tables know about it. -
Thread safety and free-threaded Python. The library holds no mutable global state — the lookup tables are read-only — so all functions may be called concurrently from multiple threads, and the incremental codec classes keep their state per instance. The test suite runs on free-threaded CPython builds (
3.14t) with the GIL disabled and includes a concurrency test. -
Emoji. It is an occasional request to support emoji domains in this library. Encoding of symbols like emoji is expressly prohibited by the IDNA technical standard, and emoji domains are broadly phased out across the domain industry due to associated security risks.
-
Regenerating lookup tables. The IDNA and UTS 46 functionality relies upon pre-calculated lookup tables, generated using the
idna-datascript intools/.