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 <qydwhotm...@gmail.com>
+
+- 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 `x...@y.com`. This is
+This library validates that a string is of the form `n...@example.com`. 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,
+`exam...@xn--bdk.life`, returns the exact same information (i.e., the
+`email` field always will contain Unicode characters, not Punycode).
+
 For the fictitious address `???-t...@joshdata.me`, 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 = j...@occams.info
+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'j...@occams.info',
-    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 = "testa...@example.com"
+    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('t...@gmail.com')
     del validate_email_deliverability.TEST_CHECK_TIMEOUT
+
+
+def test_main_single_good_input(monkeypatch, capsys):
+    import json
+    test_email = "t...@example.com"
+    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 = 't...@..com'
+    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 = ["t...@example.com", "te...@example.com", "test@.com", 
"test3@.com"]
+    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"t...@example.com"
+    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"test@.com"
+    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"
+
+
+@mock.patch("dns.resolver.LRUCache.put")
+def test_validate_email__with_caching_resolver(mocked_put):
+    dns_resolver = caching_resolver()
+    validate_email("t...@gmail.com", dns_resolver=dns_resolver)
+    assert mocked_put.called
+
+    with mock.patch("dns.resolver.LRUCache.get") as mocked_get:
+        validate_email("t...@gmail.com", dns_resolver=dns_resolver)
+        assert mocked_get.called
+
+
+@mock.patch("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("t...@gmail.com", dns_resolver=dns_resolver)
+    assert mocked_put.called
+
+    with mock.patch("dns.resolver.LRUCache.get") as mocked_get:
+        validate_email("t...@gmail.com", dns_resolver=dns_resolver)
+        assert mocked_get.called

Reply via email to