From 660cf55ee2b1057b44cd5d7e4e5f922765e0800c Mon Sep 17 00:00:00 2001 From: Jovial Joe Jayarson Date: Sun, 12 Mar 2023 22:19:04 +0530 Subject: [PATCH] maint: update `email` module - email's domain part is now compliant to RFC 5321 - it can also accept simple hostname (like `localhost`) - fix missing `utf-8` comment **Related Items** *Issues* - Closes #108 - Closes #142 --- validators/domain.py | 1 + validators/email.py | 45 +++++++++++++++++++++++++++++++++++----- validators/ip_address.py | 1 + validators/uuid.py | 1 + 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/validators/domain.py b/validators/domain.py index a5d7ef08..779ea116 100644 --- a/validators/domain.py +++ b/validators/domain.py @@ -1,4 +1,5 @@ """Domain.""" +# -*- coding: utf-8 -*- # standard import re diff --git a/validators/email.py b/validators/email.py index 47f25c75..04fe8cab 100644 --- a/validators/email.py +++ b/validators/email.py @@ -5,12 +5,20 @@ import re # local +from .hostname import hostname from .utils import validator -from .domain import domain @validator -def email(value: str, /): +def email( + value: str, + /, + *, + simple_host: bool = False, + ip_address: bool = False, + rfc_1034: bool = False, + rfc_2782: bool = False, +): """Validate an email address. This was inspired from [Django's email validator][1]. @@ -30,6 +38,16 @@ def email(value: str, /): Args: value: eMail string to validate. + simple_host: + When the domain part is a simple hostname. + ip_address: + When the domain part is an IP address. + rfc_1034: + Allow trailing dot in domain name. + Ref: [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034). + rfc_2782: + Domain name is of type service record. + Ref: [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782). Returns: (Literal[True]): @@ -48,14 +66,31 @@ def email(value: str, /): # ref: RFC 1034 and 5231 return False + if ip_address: + if domain_part.startswith("[") and domain_part.endswith("]"): + # ref: RFC 5321 + domain_part = domain_part.lstrip("[").rstrip("]") + else: + return False + return ( - bool(domain(domain_part)) - if re.compile( + bool( + hostname( + domain_part, + skip_ip_addr=not ip_address, + may_have_port=False, + maybe_simple=simple_host, + rfc_1034=rfc_1034, + rfc_2782=rfc_2782, + ) + ) + if re.match( # dot-atom r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$" # quoted-string + r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"$)', + username_part, re.IGNORECASE, - ).match(username_part) + ) else False ) diff --git a/validators/ip_address.py b/validators/ip_address.py index 309bd674..0f2e5a6a 100644 --- a/validators/ip_address.py +++ b/validators/ip_address.py @@ -1,4 +1,5 @@ """IP Address.""" +# -*- coding: utf-8 -*- # standard from ipaddress import ( diff --git a/validators/uuid.py b/validators/uuid.py index aa484e20..69b943f7 100644 --- a/validators/uuid.py +++ b/validators/uuid.py @@ -1,4 +1,5 @@ """UUID.""" +# -*- coding: utf-8 -*- # standard from typing import Union