python-email-validator fails to build with Python 3.14.0b2. =================================== FAILURES =================================== _ test_pyisemail_tests[test@[IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255]-ISEMAIL_RFC5321_ADDRESSLITERAL] _ domain_literal = 'IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255' def validate_email_domain_literal(domain_literal: str) -> DomainLiteralValidationResult: # This is obscure domain-literal syntax. Parse it and return # a compressed/normalized address. # RFC 5321 4.1.3 and RFC 5322 3.4.1. addr: Union[ipaddress.IPv4Address, ipaddress.IPv6Address] # Try to parse the domain literal as an IPv4 address. # There is no tag for IPv4 addresses, so we can never # be sure if the user intends an IPv4 address. if re.match(r"^[0-9\.]+$", domain_literal): try: addr = ipaddress.IPv4Address(domain_literal) except ValueError as e: raise EmailSyntaxError(f"The address in brackets after the @-sign is not valid: It is not an IPv4 address ({e}) or is missing an address literal tag.") from e # Return the IPv4Address object and the domain back unchanged. return { "domain_address": addr, "domain": f"[{addr}]", } # If it begins with "IPv6:" it's an IPv6 address. if domain_literal.startswith("IPv6:"): try: > addr = ipaddress.IPv6Address(domain_literal[5:]) ../BUILDROOT/usr/lib/python3.14/site-packages/email_validator/syntax.py:729: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib64/python3.14/ipaddress.py:1952: in __init__ self._ip = self._ip_int_from_string(addr_str) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ cls = <class 'ipaddress.IPv6Address'> ip_str = '1111:2222:3333:4444:5555:6666:255.255.255.255' @classmethod def _ip_int_from_string(cls, ip_str): """Turn an IPv6 ip_str into an integer. Args: ip_str: A string, the IPv6 ip_str. Returns: An int, the IPv6 address Raises: AddressValueError: if ip_str isn't a valid IPv6 Address. """ if not ip_str: raise AddressValueError('Address cannot be empty') if len(ip_str) > 39: msg = ("At most 39 characters expected in " f"{ip_str[:14]!r}({len(ip_str)-28} chars elided){ip_str[-14:]!r}") > raise AddressValueError(msg) E ipaddress.AddressValueError: At most 39 characters expected in '1111:2222:3333'(17 chars elided)'55.255.255.255' /usr/lib64/python3.14/ipaddress.py:1666: AddressValueError The above exception was the direct cause of the following exception: email_input = 'test@[IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255]' status = 'ISEMAIL_RFC5321_ADDRESSLITERAL' @pytest.mark.parametrize( ('email_input', 'status'), [ ['test', 'ISEMAIL_ERR_NODOMAIN'], ['@', 'ISEMAIL_ERR_NOLOCALPART'], ['test@', 'ISEMAIL_ERR_NODOMAIN'], # ['test@io', 'ISEMAIL_VALID'], # we reject domains without a dot, knowing they are not deliverable ['@io', 'ISEMAIL_ERR_NOLOCALPART'], ['@iana.org', 'ISEMAIL_ERR_NOLOCALPART'], ['test', 'ISEMAIL_VALID'], ['test.uk', 'ISEMAIL_VALID'], ['test', 'ISEMAIL_VALID'], ['a', 'ISEMAIL_VALID'], ['test.test', 'ISEMAIL_VALID'], ['.test', 'ISEMAIL_ERR_DOT_START'], ['test.', 'ISEMAIL_ERR_DOT_END'], ['test..iana.org', 'ISEMAIL_ERR_CONSECUTIVEDOTS'], ['test_exa-mple.com', 'ISEMAIL_ERR_NODOMAIN'], ['!#$%&`*+/=?^`{|}~@iana.org', 'ISEMAIL_VALID'], ['test\\@test', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['123', 'ISEMAIL_VALID'], ['test', 'ISEMAIL_VALID'], ['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm', 'ISEMAIL_VALID'], ['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklmn', 'ISEMAIL_RFC5322_LOCAL_TOOLONG'], ['test', 'ISEMAIL_RFC5322_LABEL_TOOLONG'], ['test', 'ISEMAIL_VALID'], ['test', 'ISEMAIL_ERR_DOMAINHYPHENSTART'], ['test', 'ISEMAIL_ERR_DOMAINHYPHENEND'], ['test', 'ISEMAIL_VALID'], ['test@.iana.org', 'ISEMAIL_ERR_DOT_START'], ['test.', 'ISEMAIL_ERR_DOT_END'], ['test@iana..com', 'ISEMAIL_ERR_CONSECUTIVEDOTS'], ['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij', 'ISEMAIL_RFC5322_TOOLONG'], ['a.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.hij', 'ISEMAIL_RFC5322_TOOLONG'], ['a.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.hijk', 'ISEMAIL_RFC5322_DOMAIN_TOOLONG'], ['"test"@iana.org', 'ISEMAIL_RFC5321_QUOTEDSTRING'], # ['""@iana.org', 'ISEMAIL_RFC5321_QUOTEDSTRING'], # we think an empty quoted string should be invalid ['"""@iana.org', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['"\\a"@iana.org', 'ISEMAIL_RFC5321_QUOTEDSTRING'], ['"\\""@iana.org', 'ISEMAIL_RFC5321_QUOTEDSTRING'], ['"\\"@iana.org', 'ISEMAIL_ERR_UNCLOSEDQUOTEDSTR'], ['"\\\\"@iana.org', 'ISEMAIL_RFC5321_QUOTEDSTRING'], ['test"@iana.org', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['"test', 'ISEMAIL_ERR_UNCLOSEDQUOTEDSTR'], ['"test"test', 'ISEMAIL_ERR_ATEXT_AFTER_QS'], ['test"text"@iana.org', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['"test""test"@iana.org', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['"test"."test"@iana.org', 'ISEMAIL_DEPREC_LOCALPART'], ['"test\\ test"@iana.org', 'ISEMAIL_RFC5321_QUOTEDSTRING'], ['"test".test', 'ISEMAIL_DEPREC_LOCALPART'], ['"test\x00"@iana.org', 'ISEMAIL_ERR_EXPECTING_QTEXT'], ['"test\\\x00"@iana.org', 'ISEMAIL_DEPREC_QP'], ['"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghj"@iana.org', 'ISEMAIL_RFC5322_LOCAL_TOOLONG'], ['"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefg\\h"@iana.org', 'ISEMAIL_RFC5322_LOCAL_TOOLONG'], ['test@[255.255.255.255]', 'ISEMAIL_RFC5321_ADDRESSLITERAL'], ['test@a[255.255.255.255]', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['test@[255.255.255]', 'ISEMAIL_RFC5322_DOMAINLITERAL'], ['test@[255.255.255.255.255]', 'ISEMAIL_RFC5322_DOMAINLITERAL'], ['test@[255.255.255.256]', 'ISEMAIL_RFC5322_DOMAINLITERAL'], ['test@[1111:2222:3333:4444:5555:6666:7777:8888]', 'ISEMAIL_RFC5322_DOMAINLITERAL'], ['test@[IPv6:1111:2222:3333:4444:5555:6666:7777]', 'ISEMAIL_RFC5322_IPV6_GRPCOUNT'], ['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]', 'ISEMAIL_RFC5321_ADDRESSLITERAL'], ['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]', 'ISEMAIL_RFC5322_IPV6_GRPCOUNT'], ['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:888G]', 'ISEMAIL_RFC5322_IPV6_BADCHAR'], ['test@[IPv6:1111:2222:3333:4444:5555:6666::8888]', 'ISEMAIL_RFC5321_IPV6DEPRECATED'], ['test@[IPv6:1111:2222:3333:4444:5555::8888]', 'ISEMAIL_RFC5321_ADDRESSLITERAL'], ['test@[IPv6:1111:2222:3333:4444:5555:6666::7777:8888]', 'ISEMAIL_RFC5322_IPV6_MAXGRPS'], ['test@[IPv6::3333:4444:5555:6666:7777:8888]', 'ISEMAIL_RFC5322_IPV6_COLONSTRT'], ['test@[IPv6:::3333:4444:5555:6666:7777:8888]', 'ISEMAIL_RFC5321_ADDRESSLITERAL'], ['test@[IPv6:1111::4444:5555::8888]', 'ISEMAIL_RFC5322_IPV6_2X2XCOLON'], ['test@[IPv6:::]', 'ISEMAIL_RFC5321_ADDRESSLITERAL'], ['test@[IPv6:1111:2222:3333:4444:5555:255.255.255.255]', 'ISEMAIL_RFC5322_IPV6_GRPCOUNT'], ['test@[IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255]', 'ISEMAIL_RFC5321_ADDRESSLITERAL'], ['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:255.255.255.255]', 'ISEMAIL_RFC5322_IPV6_GRPCOUNT'], ['test@[IPv6:1111:2222:3333:4444::255.255.255.255]', 'ISEMAIL_RFC5321_ADDRESSLITERAL'], ['test@[IPv6:1111:2222:3333:4444:5555:6666::255.255.255.255]', 'ISEMAIL_RFC5322_IPV6_MAXGRPS'], ['test@[IPv6:1111:2222:3333:4444:::255.255.255.255]', 'ISEMAIL_RFC5322_IPV6_2X2XCOLON'], ['test@[IPv6::255.255.255.255]', 'ISEMAIL_RFC5322_IPV6_COLONSTRT'], [' test @iana.org', 'ISEMAIL_DEPREC_CFWS_NEAR_AT'], ['test@ iana .com', 'ISEMAIL_DEPREC_CFWS_NEAR_AT'], ['test . test', 'ISEMAIL_DEPREC_FWS'], ['\r\n test', 'ISEMAIL_CFWS_FWS'], ['\r\n \r\n test', 'ISEMAIL_DEPREC_FWS'], ['(comment)test', 'ISEMAIL_CFWS_COMMENT'], ['((comment)test', 'ISEMAIL_ERR_UNCLOSEDCOMMENT'], ['(comment(comment))test', 'ISEMAIL_CFWS_COMMENT'], ['test@(comment)iana.org', 'ISEMAIL_DEPREC_CFWS_NEAR_AT'], ['test(comment)test', 'ISEMAIL_ERR_ATEXT_AFTER_CFWS'], ['test@(comment)[255.255.255.255]', 'ISEMAIL_DEPREC_CFWS_NEAR_AT'], ['(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm', 'ISEMAIL_CFWS_COMMENT'], ['test@(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.com', 'ISEMAIL_DEPREC_CFWS_NEAR_AT'], ['(comment)test.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstu', 'ISEMAIL_CFWS_COMMENT'], ['test\n', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['test', 'ISEMAIL_VALID'], ['xn--test', 'ISEMAIL_VALID'], ['test-', 'ISEMAIL_ERR_DOMAINHYPHENEND'], ['"test', 'ISEMAIL_ERR_UNCLOSEDQUOTEDSTR'], ['(test', 'ISEMAIL_ERR_UNCLOSEDCOMMENT'], ['test@(iana.org', 'ISEMAIL_ERR_UNCLOSEDCOMMENT'], ['test@[1.2.3.4', 'ISEMAIL_ERR_UNCLOSEDDOMLIT'], ['"test\\"@iana.org', 'ISEMAIL_ERR_UNCLOSEDQUOTEDSTR'], ['(comment\\)test', 'ISEMAIL_ERR_UNCLOSEDCOMMENT'], ['test(comment\\)', 'ISEMAIL_ERR_UNCLOSEDCOMMENT'], ['test(comment\\', 'ISEMAIL_ERR_BACKSLASHEND'], ['test@[RFC-5322-domain-literal]', 'ISEMAIL_RFC5322_DOMAINLITERAL'], ['test@[RFC-5322]-domain-literal]', 'ISEMAIL_ERR_ATEXT_AFTER_DOMLIT'], ['test@[RFC-5322-[domain-literal]', 'ISEMAIL_ERR_EXPECTING_DTEXT'], ['test@[RFC-5322-\\\x07-domain-literal]', 'ISEMAIL_RFC5322_DOMLIT_OBSDTEXT'], ['test@[RFC-5322-\\\t-domain-literal]', 'ISEMAIL_RFC5322_DOMLIT_OBSDTEXT'], ['test@[RFC-5322-\\]-domain-literal]', 'ISEMAIL_RFC5322_DOMLIT_OBSDTEXT'], ['test@[RFC-5322-domain-literal\\]', 'ISEMAIL_ERR_UNCLOSEDDOMLIT'], ['test@[RFC-5322-domain-literal\\', 'ISEMAIL_ERR_BACKSLASHEND'], ['test@[RFC 5322 domain literal]', 'ISEMAIL_RFC5322_DOMAINLITERAL'], ['test@[RFC-5322-domain-literal] (comment)', 'ISEMAIL_RFC5322_DOMAINLITERAL'], ['\x7f', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['test@\x7f.org', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['"\x7f"@iana.org', 'ISEMAIL_DEPREC_QTEXT'], ['"\\\x7f"@iana.org', 'ISEMAIL_DEPREC_QP'], ['(\x7f)test', 'ISEMAIL_DEPREC_CTEXT'], ['test\r', 'ISEMAIL_ERR_CR_NO_LF'], ['\rtest', 'ISEMAIL_ERR_CR_NO_LF'], ['"\rtest"@iana.org', 'ISEMAIL_ERR_CR_NO_LF'], ['(\r)test', 'ISEMAIL_ERR_CR_NO_LF'], ['test(\r)', 'ISEMAIL_ERR_CR_NO_LF'], ['\ntest', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['"\n"@iana.org', 'ISEMAIL_ERR_EXPECTING_QTEXT'], ['"\\\n"@iana.org', 'ISEMAIL_DEPREC_QP'], ['(\n)test', 'ISEMAIL_ERR_EXPECTING_CTEXT'], ['\x07', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['test@\x07.org', 'ISEMAIL_ERR_EXPECTING_ATEXT'], ['"\x07"@iana.org', 'ISEMAIL_DEPREC_QTEXT'], ['"\\\x07"@iana.org', 'ISEMAIL_DEPREC_QP'], ['(\x07)test', 'ISEMAIL_DEPREC_CTEXT'], ['\r\ntest', 'ISEMAIL_ERR_FWS_CRLF_END'], ['\r\n \r\ntest', 'ISEMAIL_ERR_FWS_CRLF_END'], [' \r\ntest', 'ISEMAIL_ERR_FWS_CRLF_END'], [' \r\n test', 'ISEMAIL_CFWS_FWS'], [' \r\n \r\ntest', 'ISEMAIL_ERR_FWS_CRLF_END'], [' \r\n\r\ntest', 'ISEMAIL_ERR_FWS_CRLF_X2'], [' \r\n\r\n test', 'ISEMAIL_ERR_FWS_CRLF_X2'], ['test\r\n ', 'ISEMAIL_CFWS_FWS'], ['test\r\n \r\n ', 'ISEMAIL_DEPREC_FWS'], ['test\r\n', 'ISEMAIL_ERR_FWS_CRLF_END'], ['test\r\n \r\n', 'ISEMAIL_ERR_FWS_CRLF_END'], ['test \r\n', 'ISEMAIL_ERR_FWS_CRLF_END'], ['test \r\n ', 'ISEMAIL_CFWS_FWS'], ['test \r\n \r\n', 'ISEMAIL_ERR_FWS_CRLF_END'], ['test \r\n\r\n', 'ISEMAIL_ERR_FWS_CRLF_X2'], ['test \r\n\r\n ', 'ISEMAIL_ERR_FWS_CRLF_X2'], [' test', 'ISEMAIL_CFWS_FWS'], ['test ', 'ISEMAIL_CFWS_FWS'], ['test@[IPv6:1::2:]', 'ISEMAIL_RFC5322_IPV6_COLONEND'], ['"test\\©"@iana.org', 'ISEMAIL_ERR_EXPECTING_QPAIR'], ['test@iana/icann.org', 'ISEMAIL_RFC5322_DOMAIN'], ['test.(comment)test', 'ISEMAIL_DEPREC_COMMENT'] ] ) def test_pyisemail_tests(email_input: str, status: str) -> None: if status == "ISEMAIL_VALID": # All standard email address forms should not raise an exception # with any set of parsing options. validate_email(email_input, test_environment=True) validate_email(email_input, allow_quoted_local=True, allow_domain_literal=True, test_environment=True) elif status == "ISEMAIL_RFC5321_QUOTEDSTRING": # Quoted-literal local parts are only valid with an option. with pytest.raises(EmailSyntaxError): validate_email(email_input, test_environment=True) validate_email(email_input, allow_quoted_local=True, test_environment=True) elif "_ADDRESSLITERAL" in status or status == 'ISEMAIL_RFC5321_IPV6DEPRECATED': # Domain literals with IPv4 or IPv6 addresses are only valid with an option. # I am not sure if the ISEMAIL_RFC5321_IPV6DEPRECATED case should be rejected: # The Python ipaddress module accepts it. with pytest.raises(EmailSyntaxError): validate_email(email_input, test_environment=True) > validate_email(email_input, allow_domain_literal=True, test_environment=True) tests/test_syntax.py:732: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../BUILDROOT/usr/lib/python3.14/site-packages/email_validator/validate_email.py:128: in validate_email domain_literal_info = validate_email_domain_literal(domain_part[1:-1]) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ domain_literal = 'IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255' def validate_email_domain_literal(domain_literal: str) -> DomainLiteralValidationResult: # This is obscure domain-literal syntax. Parse it and return # a compressed/normalized address. # RFC 5321 4.1.3 and RFC 5322 3.4.1. addr: Union[ipaddress.IPv4Address, ipaddress.IPv6Address] # Try to parse the domain literal as an IPv4 address. # There is no tag for IPv4 addresses, so we can never # be sure if the user intends an IPv4 address. if re.match(r"^[0-9\.]+$", domain_literal): try: addr = ipaddress.IPv4Address(domain_literal) except ValueError as e: raise EmailSyntaxError(f"The address in brackets after the @-sign is not valid: It is not an IPv4 address ({e}) or is missing an address literal tag.") from e # Return the IPv4Address object and the domain back unchanged. return { "domain_address": addr, "domain": f"[{addr}]", } # If it begins with "IPv6:" it's an IPv6 address. if domain_literal.startswith("IPv6:"): try: addr = ipaddress.IPv6Address(domain_literal[5:]) except ValueError as e: > raise EmailSyntaxError(f"The IPv6 address in brackets after the @-sign is not valid ({e}).") from e E email_validator.exceptions_types.EmailSyntaxError: The IPv6 address in brackets after the @-sign is not valid (At most 39 characters expected in '1111:2222:3333'(17 chars elided)'55.255.255.255'). ../BUILDROOT/usr/lib/python3.14/site-packages/email_validator/syntax.py:731: EmailSyntaxError =========================== short test summary info ============================ FAILED tests/test_syntax.py::test_pyisemail_tests[test@[IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255]-ISEMAIL_RFC5321_ADDRESSLITERAL] ================= 1 failed, 301 passed, 1 deselected in 0.36s ================== https://docs.python.org/3.14/whatsnew/3.14.html For the build logs, see: https://copr-be.cloud.fedoraproject.org/results/@python/python3.14/fedora-rawhide-x86_64/09092266-python-email-validator/ For all our attempts to build python-email-validator with Python 3.14, see: https://copr.fedorainfracloud.org/coprs/g/python/python3.14/package/python-email-validator/ Testing and mass rebuild of packages is happening in copr. You can follow these instructions to test locally in mock if your package builds with Python 3.14: https://copr.fedorainfracloud.org/coprs/g/python/python3.14/ Let us know here if you have any questions. Python 3.14 is planned to be included in Fedora 43. To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.14. A build failure prevents us from testing all dependent packages (transitive [Build]Requires), so if this package is required a lot, it's important for us to get it fixed soon. We'd appreciate help from the people who know this package best, but if you don't want to work on this now, let us know so we can try to work around it on our side.
See also https://github.com/python/cpython/issues/128840#issuecomment-2914324533
PR to skip it: https://src.fedoraproject.org/rpms/python-email-validator/pull-request/6
PR merged and built; fixed in https://bodhi.fedoraproject.org/updates/FEDORA-2025-def77e59b5.