FQDN Validation Library
The `fqdn` Python library, currently at version 1.5.1, provides RFC-compliant validation and manipulation of Fully Qualified Domain Names (FQDNs). Its primary purpose is to ensure that domain names adhere to Internet Engineering Task Force specifications like RFC 1123, making them suitable for traditional internet hostname usage. This is often a stricter subset of what modern web browsers accept. The library typically sees updates in response to specification clarifications or bug fixes, though major releases are infrequent.
Common errors
-
ModuleNotFoundError: No module named 'fqdn'
cause The `fqdn` library has not been installed in your Python environment.fixInstall the library using pip: `pip install fqdn` -
fqdn.FQDN validation fails for domain with underscore
cause The `fqdn` library, by default, enforces strict RFC compliance (e.g., RFC 1123) for FQDNs, which prohibits underscores in domain labels.fixTo allow underscores, you need to instantiate `FQDN` with the `allow_underscore` parameter set to `True`: `from fqdn import FQDN; domain = FQDN('my_host.example.com', allow_underscore=True); print(domain.is_valid)` -
fqdn.FQDN is_valid returns False for short hostname like 'localhost'
cause The `fqdn` library, adhering to RFCs, requires a fully qualified domain name with at least two labels (e.g., 'hostname.domain.com'). A single-label hostname or a hostname without a top-level domain (TLD) is considered invalid by default.fixTo allow short hostnames (single-label or without a TLD), instantiate `FQDN` with the `allow_cached_without_dot` or `allow_non_canonical` (for broader relaxations) parameters set to `True`: `from fqdn import FQDN; domain = FQDN('localhost', allow_cached_without_dot=True); print(domain.is_valid)` -
fqdn.FQDN validation fails for numeric TLD (e.g., 'example.123')
cause RFC specifications for FQDNs typically require the top-level domain (TLD) to contain only alphabetic characters, not numbers.fixEnsure the TLD of your domain name consists solely of alphabetic characters to comply with strict RFC standards. If numeric TLDs are needed for specific internal or non-standard uses, consider using the `allow_non_canonical` flag, but be aware this deviates from strict RFC compliance: `from fqdn import FQDN; domain = FQDN('example.123', allow_non_canonical=True); print(domain.is_valid)`
Warnings
- gotcha The `fqdn` library validates against strict RFC standards (e.g., RFC 1123, 1035), which are often more restrictive than what modern web browsers or certain Certificate Authorities (like Let's Encrypt) might accept as a valid domain name. This can lead to domains that work in browsers being rejected by `fqdn`.
- gotcha By default, the `fqdn` library requires FQDNs to have a minimum of two labels (e.g., 'example.com' is valid, but 'example' is not). This is an explicit default constraint enabled to prevent breaking backwards compatibility with earlier versions.
- gotcha Do not confuse this library (`fqdn`) with Python's built-in `socket.getfqdn()`. The `fqdn` library is designed for *validating arbitrary string inputs* as FQDNs, whereas `socket.getfqdn()` is used for *retrieving the Fully Qualified Domain Name of the local machine*.
- gotcha The `fqdn` library primarily validates the *syntactic structure* of an FQDN according to RFCs. It does not perform live DNS lookups or validate against dynamic lists like IANA TLDs or the Public Suffix List. Therefore, a syntactically valid FQDN might not correspond to a *registrable* or *existing* domain on the internet.
Install
-
pip install fqdn
Imports
- FQDN
import fqdn
from fqdn import FQDN
Quickstart
from fqdn import FQDN
domain_name_valid = 'example.com'
domain_name_invalid = 'localhost'
fqdn_obj_valid = FQDN(domain_name_valid)
fqdn_obj_invalid = FQDN(domain_name_invalid)
print(f"'{domain_name_valid}' is valid: {fqdn_obj_valid.is_valid}")
print(f"Absolute form: {fqdn_obj_valid.absolute}")
print(f"'{domain_name_invalid}' is valid: {fqdn_obj_invalid.is_valid}")
# Example with relaxed constraints (though specific params aren't directly exposed in quickstart)
# fqdn_obj_relaxed = FQDN('example', allow_single_label=True) # Illustrative, actual param might differ or be via a different method
# print(f"'example' is valid (relaxed): {fqdn_obj_relaxed.is_valid}")