Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-email_validator for
openSUSE:Factory checked in at 2021-08-23 10:07:36
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-email_validator (Old)
and /work/SRC/openSUSE:Factory/.python-email_validator.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-email_validator"
Mon Aug 23 10:07:36 2021 rev:8 rq:912682 version:1.1.3
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-email_validator/python-email_validator.changes
2020-10-25 18:08:42.243463625 +0100
+++
/work/SRC/openSUSE:Factory/.python-email_validator.new.1899/python-email_validator.changes
2021-08-23 10:07:38.492283364 +0200
@@ -1,0 +2,18 @@
+Mon Aug 16 09:14:16 UTC 2021 - Fusion Future <[email protected]>
+
+- Update to 1.1.3:
+ * Add possibility to cache dns lookups (#58)
+ * Add py39 and setup_py to setup_cfg (#57)
+- Changes from 1.1.2:
+ * Refactor: Main refactored, tests added for main (#52)
+ * Simplify email equality check into return statement (#51)
+ * Dedupe length reason logic and declare magic numbers as
+ constants (#50)
+ * Fix: ValidatedEmail is not JSON serializable (#49)
+ * Use dnspython's resolve method when available (#46)
+ * Package name should have a dash not an underscore
+ * Mention Punycode normalization, re-do fields as a table
+- Drop fix-tests-strings.patch which is not needed.
+- Move skipped tests to spec file, drop skip-tests-using-network.patch.
+
+-------------------------------------------------------------------
Old:
----
fix-tests-strings.patch
skip-tests-using-network.patch
v1.1.1.tar.gz
New:
----
v1.1.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-email_validator.spec ++++++
--- /var/tmp/diff_new_pack.1bVCH4/_old 2021-08-23 10:07:39.932281684 +0200
+++ /var/tmp/diff_new_pack.1bVCH4/_new 2021-08-23 10:07:39.936281680 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-email_validator
#
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -19,15 +19,13 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-email_validator
-Version: 1.1.1
+Version: 1.1.3
Release: 0
Summary: A robust email syntax and deliverability validation library
for Python
License: CC0-1.0
Group: Development/Languages/Python
URL: https://github.com/JoshData/python-email-validator
Source:
https://github.com/JoshData/python-email-validator/archive/v%{version}.tar.gz
-Patch0: skip-tests-using-network.patch
-Patch1: fix-tests-strings.patch
BuildRequires: %{python_module dnspython >= 1.15.0}
BuildRequires: %{python_module idna >= 2.0.0}
BuildRequires: %{python_module pytest >= 5.0}
@@ -38,7 +36,7 @@
Requires: python-idna >= 2.0.0
Requires: python-setuptools
Requires(post): update-alternatives
-Requires(postun): update-alternatives
+Requires(postun):update-alternatives
BuildArch: noarch
%python_subpackages
@@ -59,10 +57,6 @@
%prep
%setup -q -n python-email-validator-%{version}
-%patch0 -p1
-%if %{?suse_version} <= 1500
-%patch1 -p1
-%endif
%build
%python_build
@@ -73,7 +67,7 @@
%python_expand %fdupes %{buildroot}%{$python_sitelib}
%check
-%pytest
+%pytest tests -k 'not (test_deliverability_no_records or
test_deliverability_found or test_deliverability_fails or
test_deliverability_dns_timeout or test_main_single_good_input or
test_main_multi_input or test_main_input_shim or
test_validate_email__with_caching_resolver or
test_validate_email__with_configured_resolver)'
%post
%python_install_alternative email_validator
++++++ v1.1.1.tar.gz -> v1.1.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-email-validator-1.1.1/.travis.yml
new/python-email-validator-1.1.3/.travis.yml
--- old/python-email-validator-1.1.1/.travis.yml 2020-05-19
13:15:08.000000000 +0200
+++ new/python-email-validator-1.1.3/.travis.yml 2021-06-12
13:01:42.000000000 +0200
@@ -10,6 +10,7 @@
- '3.6'
- '3.7'
- '3.8'
+- '3.9'
install:
- make install
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-email-validator-1.1.1/Makefile
new/python-email-validator-1.1.3/Makefile
--- old/python-email-validator-1.1.1/Makefile 2020-05-19 13:15:08.000000000
+0200
+++ new/python-email-validator-1.1.3/Makefile 2021-06-12 13:01:42.000000000
+0200
@@ -9,7 +9,7 @@
.PHONY: lint
lint:
#python setup.py check -rms
- flake8 --ignore=E501,E126 email_validator tests
+ flake8 --ignore=E501,E126,W503 email_validator tests
.PHONY: test
test:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-email-validator-1.1.1/README.md
new/python-email-validator-1.1.3/README.md
--- old/python-email-validator-1.1.1/README.md 2020-05-19 13:15:08.000000000
+0200
+++ new/python-email-validator-1.1.3/README.md 2021-06-12 13:01:42.000000000
+0200
@@ -1,19 +1,20 @@
-email\_validator
-================
+email-validator: Validate Email Addresses
+=========================================
A robust email address syntax and deliverability validation library for
-Python 2.7/3.4+ by [Joshua Tauberer](https://razor.occams.info).
+Python 2.7/3.4+ by [Joshua Tauberer](https://joshdata.me).
-This library validates that a string is of the form `[email protected]`. This is
+This library validates that a string is of the form `[email protected]`. This is
the sort of validation you would want for an email-based login form on
a website.
Key features:
-* Good for validating email addresses used for logins/identity.
-* Friendly error messages when validation fails (appropriate to show
+* Checks that an email address has the correct syntax --- good for
+ login forms or other uses related to identifying users.
+* Gives friendly error messages when validation fails (appropriate to show
to end users).
-* (optionally) Checks deliverability: Does the domain name resolve?
+* (optionally) Checks deliverability: Does the domain name resolve? And you
can override the default DNS resolver.
* Supports internationalized domain names and (optionally)
internationalized local parts.
* Normalizes email addresses (super important for internationalized
@@ -37,7 +38,7 @@
This package [is on PyPI](https://pypi.org/project/email-validator/), so:
```sh
-pip install email_validator
+pip install email-validator
```
`pip3` also works.
@@ -68,23 +69,27 @@
put the normalized form in your database and always normalize before
checking if an address is in your database.
-The validator will accept internationalized email addresses, but email
-addresses with non-ASCII characters in the *local* part of the address
-(before the @-sign) require the
-[SMTPUTF8](https://tools.ietf.org/html/rfc6531) extension which may not
-be supported by your mail submission library or your outbound mail
-server. If you know ahead of time that SMTPUTF8 is not supported then
-**add the keyword argument allow\_smtputf8=False to fail validation for
-addresses that would require SMTPUTF8**:
+When validating many email addresses or to control the timeout (the default is
15 seconds), create a caching
[dns.resolver.Resolver](https://dnspython.readthedocs.io/en/latest/resolver-class.html)
to reuse in each call:
```python
-valid = validate_email(email, allow_smtputf8=False)
+from email_validator import validate_email, caching_resolver
+
+resolver = caching_resolver(timeout=10)
+
+while True:
+ valid = validate_email(email, dns_resolver=resolver)
```
+The validator will accept internationalized email addresses, but not all
+mail systems can send email to an addresses with non-ASCII characters in
+the *local* part of the address (before the @-sign). See the `allow_smtputf8`
+option below.
+
+
Overview
--------
-The module provides a single function `validate_email(email_address)` which
+The module provides a function `validate_email(email_address)` which
takes an email address (either a `str` or ASCII `bytes`) and:
- Raises a `EmailNotValidError` with a helpful, human-readable error
@@ -127,6 +132,9 @@
`allow_empty_local=False`: Set to `True` to allow an empty local part (i.e.
`@example.com`), e.g. for validating Postfix aliases.
+
+`dns_resolver=None`: Pass an instance of
[dns.resolver.Resolver](https://dnspython.readthedocs.io/en/latest/resolver-class.html)
to control the DNS resolver including setting a timeout and [a
cache](https://dnspython.readthedocs.io/en/latest/resolver-caching.html). The
`caching_resolver` function shown above is a helper function to construct a
dns.resolver.Resolver with a
[LRUCache](https://dnspython.readthedocs.io/en/latest/resolver-caching.html#dns.resolver.LRUCache).
Reuse the same resolver instance across calls to `validate_email` to make use
of the cache.
+
Internationalized email addresses
---------------------------------
@@ -230,13 +238,12 @@
normalization](https://en.wikipedia.org/wiki/Unicode_equivalence) of the
whole address (which turns characters plus [combining
characters](https://en.wikipedia.org/wiki/Combining_character) into
-precomposed characters where possible and replaces certain Unicode
-characters (such as angstrom and ohm) with other equivalent code points
-(a-with-ring and omega, respectively)), replacement of [fullwidth and
+precomposed characters where possible, replacement of [fullwidth and
halfwidth
characters](https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms)
-in the domain part, and possibly other
-[UTS46](http://unicode.org/reports/tr46) mappings on the domain part.
+in the domain part, possibly other
+[UTS46](http://unicode.org/reports/tr46) mappings on the domain part,
+and conversion from Punycode to Unicode characters.
(See [RFC 6532 (internationalized email) section
3.1](https://tools.ietf.org/html/rfc6532#section-3.1) and [RFC 5895
@@ -283,6 +290,10 @@
fields provide a normalized form of the email address and domain name
(casefolding and Unicode normalization as required by IDNA 2008).
+Calling `validate_email` with the ASCII form of the above email address,
+`[email protected]`, returns the exact same information (i.e., the
+`email` field always will contain Unicode characters, not Punycode).
+
For the fictitious address `[email protected]`, which has an
internationalized local part, the returned object is:
@@ -309,55 +320,17 @@
When an email address passes validation, the fields in the returned object
are:
-`email`: The canonical form of the email address, mostly useful for
- display purposes. This merely combines the `local_part` and `domain`
- fields (see below).
-
-`ascii_email`: If set, an ASCII-only form of the email address by replacing the
- domain part with [IDNA](https://tools.ietf.org/html/rfc5891)
- [Punycode](https://www.rfc-editor.org/rfc/rfc3492.txt).
- This field will be present when an ASCII-only form of the email
- address exists (including if the email address is already ASCII). If
- the local part of the email address contains internationalized
- characters, `ascii_email` will be `None`. If set, it merely combines
- `ascii_local_part` and `ascii_domain`.
-
-`local_part`: The local part of the given email address (before the @-sign)
with
- Unicode NFC normalization applied.
-
-`ascii_local_part`: If set, the local part, which is composed of ASCII
characters only.
-
-`domain`: The canonical internationalized Unicode form of the domain part of
the
- email address. If the returned string contains non-ASCII characters,
either the
- [SMTPUTF8](https://tools.ietf.org/html/rfc6531) feature of your
- mail relay will be required to transmit the message or else the
- email address's domain part must be converted to IDNA ASCII first: Use
- `ascii_domain` field instead.
-
-`ascii_domain`: The [IDNA](https://tools.ietf.org/html/rfc5891)
- [Punycode](https://www.rfc-editor.org/rfc/rfc3492.txt)-encoded
- form of the domain part of the given email address, as
- it would be transmitted on the wire.
-
-`smtputf8`: A boolean indicating that the
- [SMTPUTF8](https://tools.ietf.org/html/rfc6531) feature of your
- mail relay will be required to transmit messages to this address
- because the local part of the address has non-ASCII characters (the
- local part cannot be IDNA-encoded). If `allow_smtputf8=False` is
- passed as an argument, this flag will always be false because an
- exception is raised if it would have been true.
-
-`mx`: A list of (priority, domain) tuples of MX records specified in the
- DNS for the domain (see [RFC 5321 section
- 5](https://tools.ietf.org/html/rfc5321#section-5)). May be `None` if
- the deliverability check could not be completed because of a temporary
- issue like a timeout.
-
-`mx_fallback_type`: `None` if an `MX` record is found. If no MX records are
actually
- specified in DNS and instead are inferred, through an obsolete
- mechanism, from A or AAAA records, the value is the type of DNS
- record used instead (`A` or `AAAA`). May be `None` if the deliverability
check
- could not be completed because of a temporary issue like a timeout.
+| Field | Value |
+| -----:|-------|
+| `email` | The normalized form of the email address that you should put in
your database. This merely combines the `local_part` and `domain` fields (see
below). |
+| `ascii_email` | If set, an ASCII-only form of the email address by replacing
the domain part with [IDNA](https://tools.ietf.org/html/rfc5891)
[Punycode](https://www.rfc-editor.org/rfc/rfc3492.txt). This field will be
present when an ASCII-only form of the email address exists (including if the
email address is already ASCII). If the local part of the email address
contains internationalized characters, `ascii_email` will be `None`. If set, it
merely combines `ascii_local_part` and `ascii_domain`. |
+| `local_part` | The local part of the given email address (before the @-sign)
with Unicode NFC normalization applied. |
+| `ascii_local_part` | If set, the local part, which is composed of ASCII
characters only. |
+| `domain` | The canonical internationalized Unicode form of the domain part
of the email address. If the returned string contains non-ASCII characters,
either the [SMTPUTF8](https://tools.ietf.org/html/rfc6531) feature of your mail
relay will be required to transmit the message or else the email address's
domain part must be converted to IDNA ASCII first: Use `ascii_domain` field
instead. |
+| `ascii_domain` | The [IDNA](https://tools.ietf.org/html/rfc5891)
[Punycode](https://www.rfc-editor.org/rfc/rfc3492.txt)-encoded form of the
domain part of the given email address, as it would be transmitted on the wire.
|
+| `smtputf8` | A boolean indicating that the
[SMTPUTF8](https://tools.ietf.org/html/rfc6531) feature of your mail relay will
be required to transmit messages to this address because the local part of the
address has non-ASCII characters (the local part cannot be IDNA-encoded). If
`allow_smtputf8=False` is passed as an argument, this flag will always be false
because an exception is raised if it would have been true. |
+| `mx` | A list of (priority, domain) tuples of MX records specified in the
DNS for the domain (see [RFC 5321 section
5](https://tools.ietf.org/html/rfc5321#section-5)). May be `None` if the
deliverability check could not be completed because of a temporary issue like a
timeout. |
+| `mx_fallback_type` | `None` if an `MX` record is found. If no MX records are
actually specified in DNS and instead are inferred, through an obsolete
mechanism, from A or AAAA records, the value is the type of DNS record used
instead (`A` or `AAAA`). May be `None` if the deliverability check could not be
completed because of a temporary issue like a timeout. |
Assumptions
-----------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-email-validator-1.1.1/email_validator/__init__.py
new/python-email-validator-1.1.3/email_validator/__init__.py
--- old/python-email-validator-1.1.1/email_validator/__init__.py
2020-05-19 13:15:08.000000000 +0200
+++ new/python-email-validator-1.1.3/email_validator/__init__.py
2021-06-12 13:01:42.000000000 +0200
@@ -29,6 +29,13 @@
# the beginning or end of a *dot-atom component* of a hostname either.
ATEXT_HOSTNAME = r'(?:(?:[a-zA-Z0-9][a-zA-Z0-9\-]*)?[a-zA-Z0-9])'
+# Length constants
+# RFC 3696 + errata 1003 + errata 1690
(https://www.rfc-editor.org/errata_search.php?rfc=3696&eid=1690)
+# explains the maximum length of an email address is 254 octets.
+EMAIL_MAX_LENGTH = 254
+LOCAL_PART_MAX_LENGTH = 64
+DOMAIN_MAX_LENGTH = 255
+
# ease compatibility in type checking
if sys.version_info >= (3,):
unicode_class = str
@@ -135,14 +142,18 @@
"""Tests use this."""
def __eq__(self, other):
- if self.email == other.email and self.local_part == other.local_part
and self.domain == other.domain \
- and self.ascii_email == other.ascii_email and self.ascii_local_part
== other.ascii_local_part \
- and self.ascii_domain == other.ascii_domain \
- and self.smtputf8 == other.smtputf8 \
- and repr(sorted(self.mx) if self.mx else self.mx) ==
repr(sorted(other.mx) if other.mx else other.mx) \
- and self.mx_fallback_type == other.mx_fallback_type:
- return True
- return False
+ return (
+ self.email == other.email
+ and self.local_part == other.local_part
+ and self.domain == other.domain
+ and self.ascii_email == other.ascii_email
+ and self.ascii_local_part == other.ascii_local_part
+ and self.ascii_domain == other.ascii_domain
+ and self.smtputf8 == other.smtputf8
+ and repr(sorted(self.mx) if self.mx else self.mx)
+ == repr(sorted(other.mx) if other.mx else other.mx)
+ and self.mx_fallback_type == other.mx_fallback_type
+ )
"""This helps producing the README."""
def as_constructor(self):
@@ -156,6 +167,25 @@
) \
+ ")"
+ """Convenience method for accessing ValidatedEmail as a dict"""
+ def as_dict(self):
+ return self.__dict__
+
+
+def __get_length_reason(addr, utf8=False, limit=EMAIL_MAX_LENGTH):
+ diff = len(addr) - limit
+ reason = "({}{} character{} too many)"
+ prefix = "at least " if utf8 else ""
+ suffix = "s" if diff > 1 else ""
+ return reason.format(prefix, diff, suffix)
+
+
+def caching_resolver(timeout=DEFAULT_TIMEOUT, cache=None):
+ resolver = dns.resolver.Resolver()
+ resolver.cache = cache or dns.resolver.LRUCache()
+ resolver.lifetime = timeout # timeout, in seconds
+ return resolver
+
def validate_email(
email,
@@ -163,6 +193,7 @@
allow_empty_local=False,
check_deliverability=True,
timeout=DEFAULT_TIMEOUT,
+ dns_resolver=None
):
"""
Validates an email address, raising an EmailNotValidError if the address
is not valid or returning a dict of
@@ -208,9 +239,6 @@
if not ret.smtputf8:
ret.ascii_email = ret.ascii_local_part + "@" + ret.ascii_domain
- # RFC 3696 + errata 1003 + errata 1690
(https://www.rfc-editor.org/errata_search.php?rfc=3696&eid=1690)
- # explains the maximum length of an email address is 254 octets.
- #
# If the email address has an ASCII representation, then we assume it may
be
# transmitted in ASCII (we can't assume SMTPUTF8 will be used on all hops
to
# the destination) and the length limit applies to ASCII characters (which
is
@@ -231,38 +259,31 @@
# longer than the number of characters.
#
# See the length checks on the local part and the domain.
- if ret.ascii_email and len(ret.ascii_email) > 254:
+ if ret.ascii_email and len(ret.ascii_email) > EMAIL_MAX_LENGTH:
if ret.ascii_email == ret.email:
- reason = " ({} character{} too many)".format(
- len(ret.ascii_email) - 254,
- "s" if (len(ret.ascii_email) - 254 != 1) else ""
- )
- elif len(ret.email) > 254:
+ reason = __get_length_reason(ret.ascii_email)
+ elif len(ret.email) > EMAIL_MAX_LENGTH:
# If there are more than 254 characters, then the ASCII
# form is definitely going to be too long.
- reason = " (at least {} character{} too many)".format(
- len(ret.email) - 254,
- "s" if (len(ret.email) - 254 != 1) else ""
- )
+ reason = __get_length_reason(ret.email, utf8=True)
else:
- reason = " (when converted to IDNA ASCII)"
- raise EmailSyntaxError("The email address is too
long{}.".format(reason))
- if len(ret.email.encode("utf8")) > 254:
- if len(ret.email) > 254:
+ reason = "(when converted to IDNA ASCII)"
+ raise EmailSyntaxError("The email address is too long
{}.".format(reason))
+ if len(ret.email.encode("utf8")) > EMAIL_MAX_LENGTH:
+ if len(ret.email) > EMAIL_MAX_LENGTH:
# If there are more than 254 characters, then the UTF-8
# encoding is definitely going to be too long.
- reason = " (at least {} character{} too many)".format(
- len(ret.email) - 254,
- "s" if (len(ret.email) - 254 != 1) else ""
- )
+ reason = __get_length_reason(ret.email, utf8=True)
else:
- reason = " (when encoded in bytes)"
- raise EmailSyntaxError("The email address is too
long{}.".format(reason))
+ reason = "(when encoded in bytes)"
+ raise EmailSyntaxError("The email address is too long
{}.".format(reason))
if check_deliverability:
# Validate the email address's deliverability and update the
# return dict with metadata.
- deliverability_info = validate_email_deliverability(ret["domain"],
ret["domain_i18n"], timeout)
+ deliverability_info = validate_email_deliverability(
+ ret["domain"], ret["domain_i18n"], timeout, dns_resolver
+ )
if "mx" in deliverability_info:
ret.mx = deliverability_info["mx"]
ret.mx_fallback_type = deliverability_info["mx-fallback"]
@@ -291,11 +312,9 @@
# internationalized, then the UTF-8 encoding may be longer, but
# that may not be relevant. We will check the total address length
# instead.
- if len(local) > 64:
- raise EmailSyntaxError("The email address is too long before the
@-sign ({} character{} too many).".format(
- len(local) - 64,
- "s" if (len(local) - 64 != 1) else ""
- ))
+ if len(local) > LOCAL_PART_MAX_LENGTH:
+ reason = __get_length_reason(local, limit=LOCAL_PART_MAX_LENGTH)
+ raise EmailSyntaxError("The email address is too long before the
@-sign {}.".format(reason))
# Check the local part against the regular expression for the older ASCII
requirements.
m = re.match(DOT_ATOM_TEXT + "\\Z", local)
@@ -400,7 +419,7 @@
# on the assumption that the domain may be transmitted without SMTPUTF8
# as IDNA ASCII. This is also checked by idna.encode, so this exception
# is never reached.
- if len(ascii_domain) > 255:
+ if len(ascii_domain) > DOMAIN_MAX_LENGTH:
raise EmailSyntaxError("The email address is too long after the
@-sign.")
# A "dot atom text", per RFC 2822 3.2.4, but using the restricted
@@ -434,12 +453,31 @@
}
-def validate_email_deliverability(domain, domain_i18n,
timeout=DEFAULT_TIMEOUT):
+def validate_email_deliverability(domain, domain_i18n,
timeout=DEFAULT_TIMEOUT, dns_resolver=None):
# Check that the domain resolves to an MX record. If there is no MX record,
# try an A or AAAA record which is a deprecated fallback for
deliverability.
- # Add a trailing period to ensure the domain name is treated as fully
qualified.
- domain += '.'
+ # If no dns.resolver.Resolver was given, get dnspython's default resolver.
+ # Override the default resolver's timeout. This may affect other uses of
+ # dnspython in this process.
+ if dns_resolver is None:
+ dns_resolver = dns.resolver.get_default_resolver()
+ dns_resolver.lifetime = timeout
+
+ def dns_resolver_resolve_shim(domain, record):
+ try:
+ # dns.resolver.Resolver.resolve is new to dnspython 2.x.
+ #
https://dnspython.readthedocs.io/en/latest/resolver-class.html#dns.resolver.Resolver.resolve
+ return dns_resolver.resolve(domain, record)
+ except AttributeError:
+ # dnspython 2.x is only available in Python 3.6 and later. For
earlier versions
+ # of Python, we maintain compatibility with dnspython 1.x which
has a
+ # dnspython.resolver.Resolver.query method instead. The only
difference is that
+ # query may treat the domain as relative and use the system's
search domains,
+ # which we prevent by adding a "." to the domain name to make it
absolute.
+ # dns.resolver.Resolver.query is deprecated in dnspython version
2.x.
+ #
https://dnspython.readthedocs.io/en/latest/resolver-class.html#dns.resolver.Resolver.query
+ return dns_resolver.query(domain + ".", record)
try:
# We need a way to check how timeouts are handled in the tests. So we
@@ -448,28 +486,23 @@
if getattr(validate_email_deliverability, 'TEST_CHECK_TIMEOUT', False):
raise dns.exception.Timeout()
- resolver = dns.resolver.get_default_resolver()
-
- if timeout:
- resolver.lifetime = timeout
-
try:
# Try resolving for MX records and get them in sorted priority
order.
- response = dns.resolver.query(domain, "MX")
+ response = dns_resolver_resolve_shim(domain, "MX")
mtas = sorted([(r.preference, str(r.exchange).rstrip('.')) for r
in response])
mx_fallback = None
except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN,
dns.resolver.NoAnswer):
# If there was no MX record, fall back to an A record.
try:
- response = dns.resolver.query(domain, "A")
+ response = dns_resolver_resolve_shim(domain, "A")
mtas = [(0, str(r)) for r in response]
mx_fallback = "A"
except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN,
dns.resolver.NoAnswer):
# If there was no A record, fall back to an AAAA record.
try:
- response = dns.resolver.query(domain, "AAAA")
+ response = dns_resolver_resolve_shim(domain, "AAAA")
mtas = [(0, str(r)) for r in response]
mx_fallback = "AAAA"
except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN,
dns.resolver.NoAnswer):
@@ -504,32 +537,31 @@
import sys
import json
+ def __utf8_input_shim(input_str):
+ if sys.version_info < (3,):
+ return input_str.decode("utf-8")
+ return input_str
+
+ def __utf8_output_shim(output_str):
+ if sys.version_info < (3,):
+ return unicode_class(output_str).encode("utf-8")
+ return output_str
+
if len(sys.argv) == 1:
- # Read lines for STDIN and validate the email address on each line.
- allow_smtputf8 = True
for line in sys.stdin:
+ email = __utf8_input_shim(line.strip())
try:
- email = line.strip()
- if sys.version_info < (3,):
- email = email.decode("utf8") # assume utf8 in input
- validate_email(email, allow_smtputf8=allow_smtputf8)
+ validate_email(email)
except EmailNotValidError as e:
- print(email, e)
+ print(__utf8_output_shim("{} {}".format(email, e)))
else:
# Validate the email address passed on the command line.
- email = sys.argv[1]
- allow_smtputf8 = True
- check_deliverability = True
- if sys.version_info < (3,):
- email = email.decode("utf8") # assume utf8 in input
+ email = __utf8_input_shim(sys.argv[1])
try:
- result = validate_email(email, allow_smtputf8=allow_smtputf8,
check_deliverability=check_deliverability)
- print(json.dumps(result, indent=2, sort_keys=True,
ensure_ascii=False))
+ result = validate_email(email)
+ print(json.dumps(result.as_dict(), indent=2, sort_keys=True,
ensure_ascii=False))
except EmailNotValidError as e:
- if sys.version_info < (3,):
- print(unicode_class(e).encode("utf8"))
- else:
- print(e)
+ print(__utf8_output_shim(e))
if __name__ == "__main__":
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-email-validator-1.1.1/setup.cfg
new/python-email-validator-1.1.3/setup.cfg
--- old/python-email-validator-1.1.1/setup.cfg 2020-05-19 13:15:08.000000000
+0200
+++ new/python-email-validator-1.1.3/setup.cfg 2021-06-12 13:01:42.000000000
+0200
@@ -1,8 +1,42 @@
-[bdist_wheel]
-universal = 1
-
[metadata]
+name = email_validator
+version = 1.1.3
+description = A robust email syntax and deliverability validation library for
Python 2.x/3.x.
+long_description = file: README.md
+long_description_content_type = text/markdown
+url = https://github.com/JoshData/python-email-validator
+author = Joshua Tauberer
+author_email = [email protected]
+license = CC0 (copyright waived)
license_file = LICENSE
+classifiers =
+ Development Status :: 5 - Production/Stable
+ Intended Audience :: Developers
+ License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
+ Programming Language :: Python :: 2
+ Programming Language :: Python :: 2.7
+ Programming Language :: Python :: 3
+ Programming Language :: Python :: 3.5
+ Programming Language :: Python :: 3.6
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+ Programming Language :: Python :: 3.9
+ Topic :: Software Development :: Libraries :: Python Modules
+keywords = email address validator
+
+[options]
+packages = find:
+install_requires =
+ dnspython>=1.15.0
+ idna>=2.0.0
+python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
+
+[options.entry_points]
+console_scripts =
+ email_validator=email_validator:main
+
+[bdist_wheel]
+universal = 1
[flake8]
max-line-length = 120
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-email-validator-1.1.1/setup.py
new/python-email-validator-1.1.3/setup.py
--- old/python-email-validator-1.1.1/setup.py 2020-05-19 13:15:08.000000000
+0200
+++ new/python-email-validator-1.1.3/setup.py 2021-06-12 13:01:42.000000000
+0200
@@ -1,49 +1,2 @@
-# -*- coding: utf-8 -*-
-
-from setuptools import setup, find_packages
-from codecs import open
-
-setup(
- name='email_validator',
- version='1.1.1',
-
- description='A robust email syntax and deliverability validation library
for Python 2.x/3.x.',
- long_description=open("README.md", encoding='utf-8').read(),
- long_description_content_type="text/markdown",
- url='https://github.com/JoshData/python-email-validator',
-
- author=u'Joshua Tauberer',
- author_email=u'[email protected]',
- license='CC0 (copyright waived)',
-
- # See https://pypi.org/pypi?%3Aaction=list_classifiers
- classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication',
-
- 'Intended Audience :: Developers',
- 'Topic :: Software Development :: Libraries :: Python Modules',
-
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.4',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: 3.8',
- ],
-
- keywords="email address validator",
-
- packages=find_packages(),
- install_requires=[
- "idna>=2.0.0",
- "dnspython>=1.15.0"],
-
- entry_points={
- 'console_scripts': [
- 'email_validator=email_validator:main',
- ],
- },
-)
+from setuptools import setup
+setup()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-email-validator-1.1.1/tests/test_main.py
new/python-email-validator-1.1.3/tests/test_main.py
--- old/python-email-validator-1.1.1/tests/test_main.py 2020-05-19
13:15:08.000000000 +0200
+++ new/python-email-validator-1.1.3/tests/test_main.py 2021-06-12
13:01:42.000000000 +0200
@@ -1,7 +1,11 @@
+from unittest import mock
+import dns.resolver
import pytest
from email_validator import EmailSyntaxError, EmailUndeliverableError, \
validate_email, validate_email_deliverability, \
- ValidatedEmail
+ caching_resolver, ValidatedEmail
+# Let's test main but rename it to be clear
+from email_validator import main as validator_main
@pytest.mark.parametrize(
@@ -250,6 +254,13 @@
assert str(exc_info.value) == error_msg
+def test_dict_accessor():
+ input_email = "[email protected]"
+ valid_email = validate_email(input_email, check_deliverability=False)
+ assert isinstance(valid_email.as_dict(), dict)
+ assert valid_email.as_dict()["original_email"] == input_email
+
+
def test_deliverability_no_records():
assert validate_email_deliverability('example.com', 'example.com') ==
{'mx': [(0, '')], 'mx-fallback': None}
@@ -277,3 +288,85 @@
assert response.get("unknown-deliverability") == "timeout"
validate_email('[email protected]')
del validate_email_deliverability.TEST_CHECK_TIMEOUT
+
+
+def test_main_single_good_input(monkeypatch, capsys):
+ import json
+ test_email = "[email protected]"
+ monkeypatch.setattr('sys.argv', ['email_validator', test_email])
+ validator_main()
+ stdout, _ = capsys.readouterr()
+ output = json.loads(str(stdout))
+ assert isinstance(output, dict)
+ assert validate_email(test_email).original_email ==
output["original_email"]
+
+
+def test_main_single_bad_input(monkeypatch, capsys):
+ bad_email = '[email protected]'
+ monkeypatch.setattr('sys.argv', ['email_validator', bad_email])
+ validator_main()
+ stdout, _ = capsys.readouterr()
+ assert stdout == 'An email address cannot have a period immediately after
the @-sign.\n'
+
+
+def test_main_multi_input(monkeypatch, capsys):
+ import io
+ test_cases = ["[email protected]", "[email protected]", "[email protected]",
"[email protected]"]
+ test_input = io.StringIO("\n".join(test_cases))
+ monkeypatch.setattr('sys.stdin', test_input)
+ monkeypatch.setattr('sys.argv', ['email_validator'])
+ validator_main()
+ stdout, _ = capsys.readouterr()
+ assert test_cases[0] not in stdout
+ assert test_cases[1] not in stdout
+ assert test_cases[2] in stdout
+ assert test_cases[3] in stdout
+
+
+def test_main_input_shim(monkeypatch, capsys):
+ import json
+ monkeypatch.setattr('sys.version_info', (2, 7))
+ test_email = b"[email protected]"
+ monkeypatch.setattr('sys.argv', ['email_validator', test_email])
+ validator_main()
+ stdout, _ = capsys.readouterr()
+ output = json.loads(str(stdout))
+ assert isinstance(output, dict)
+ assert validate_email(test_email).original_email ==
output["original_email"]
+
+
+def test_main_output_shim(monkeypatch, capsys):
+ monkeypatch.setattr('sys.version_info', (2, 7))
+ test_email = b"[email protected]"
+ monkeypatch.setattr('sys.argv', ['email_validator', test_email])
+ validator_main()
+ stdout, _ = capsys.readouterr()
+
+ # This looks bad but it has to do with the way python 2.7 prints vs py3
+ # The \n is part of the print statement, not part of the string, which is
what the b'...' is
+ # Since we're mocking py 2.7 here instead of actually using 2.7, this was
the closest I could get
+ assert stdout == "b'An email address cannot have a period immediately
after the @-sign.'\n"
+
+
[email protected]("dns.resolver.LRUCache.put")
+def test_validate_email__with_caching_resolver(mocked_put):
+ dns_resolver = caching_resolver()
+ validate_email("[email protected]", dns_resolver=dns_resolver)
+ assert mocked_put.called
+
+ with mock.patch("dns.resolver.LRUCache.get") as mocked_get:
+ validate_email("[email protected]", dns_resolver=dns_resolver)
+ assert mocked_get.called
+
+
[email protected]("dns.resolver.LRUCache.put")
+def test_validate_email__with_configured_resolver(mocked_put):
+ dns_resolver = dns.resolver.Resolver()
+ dns_resolver.lifetime = 10
+ dns_resolver.cache = dns.resolver.LRUCache(max_size=1000)
+ validate_email("[email protected]", dns_resolver=dns_resolver)
+ assert mocked_put.called
+
+ with mock.patch("dns.resolver.LRUCache.get") as mocked_get:
+ validate_email("[email protected]", dns_resolver=dns_resolver)
+ assert mocked_get.called