Hello community,

here is the log from the commit of package python-certbot-dns-route53 for 
openSUSE:Factory checked in at 2020-01-03 17:39:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-certbot-dns-route53 (Old)
 and      /work/SRC/openSUSE:Factory/.python-certbot-dns-route53.new.6675 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-certbot-dns-route53"

Fri Jan  3 17:39:25 2020 rev:15 rq:760666 version:1.0.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-certbot-dns-route53/python-certbot-dns-route53.changes
    2019-11-15 00:29:24.243760314 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-certbot-dns-route53.new.6675/python-certbot-dns-route53.changes
  2020-01-03 17:39:43.907380286 +0100
@@ -1,0 +2,6 @@
+Fri Jan  3 13:18:46 UTC 2020 - Marketa Calabkova <mcalabk...@suse.com>
+
+- update to version 1.0.0
+  * sync with main certbot package
+
+-------------------------------------------------------------------

Old:
----
  certbot-dns-route53-0.40.1.tar.gz

New:
----
  certbot-dns-route53-1.0.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-certbot-dns-route53.spec ++++++
--- /var/tmp/diff_new_pack.LU2AbC/_old  2020-01-03 17:39:44.547380615 +0100
+++ /var/tmp/diff_new_pack.LU2AbC/_new  2020-01-03 17:39:44.547380615 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-certbot-dns-route53
 #
-# Copyright (c) 2019 SUSE LLC.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,23 +18,24 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-certbot-dns-route53
-Version:        0.40.1
+Version:        1.0.0
 Release:        0
 Summary:        Route53 DNS Authenticator plugin for Certbot
 License:        Apache-2.0
 URL:            https://github.com/certbot/certbot
 Source:         
https://files.pythonhosted.org/packages/source/c/certbot-dns-route53/certbot-dns-route53-%{version}.tar.gz
-BuildRequires:  %{python_module acme >= 0.25.0}
+BuildRequires:  %{python_module acme >= 0.29.0}
 BuildRequires:  %{python_module boto3}
-BuildRequires:  %{python_module certbot >= 0.34.0}
+BuildRequires:  %{python_module certbot >= 1.0.0}
 BuildRequires:  %{python_module mock}
+BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  %{python_module zope.interface}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 Requires:       python-acme >= 0.29.0
 Requires:       python-boto3
-Requires:       python-certbot >= 0.34.0
+Requires:       python-certbot >= 1.0.0
 Requires:       python-zope.interface
 BuildArch:      noarch
 %python_subpackages

++++++ certbot-dns-route53-0.40.1.tar.gz -> certbot-dns-route53-1.0.0.tar.gz 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-dns-route53-0.40.1/MANIFEST.in 
new/certbot-dns-route53-1.0.0/MANIFEST.in
--- old/certbot-dns-route53-0.40.1/MANIFEST.in  2019-11-06 03:24:51.000000000 
+0100
+++ new/certbot-dns-route53-1.0.0/MANIFEST.in   2019-12-03 18:20:30.000000000 
+0100
@@ -1,3 +1,6 @@
 include LICENSE.txt
 include README
 recursive-include docs *
+recursive-include tests *
+global-exclude __pycache__
+global-exclude *.py[cod]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-dns-route53-0.40.1/PKG-INFO 
new/certbot-dns-route53-1.0.0/PKG-INFO
--- old/certbot-dns-route53-0.40.1/PKG-INFO     2019-11-06 03:25:26.000000000 
+0100
+++ new/certbot-dns-route53-1.0.0/PKG-INFO      2019-12-03 18:21:17.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: certbot-dns-route53
-Version: 0.40.1
+Version: 1.0.0
 Summary: Route53 DNS Authenticator plugin for Certbot
 Home-page: https://github.com/certbot/certbot
 Author: Certbot Project
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-route53-0.40.1/certbot_dns_route53/_internal/__init__.py 
new/certbot-dns-route53-1.0.0/certbot_dns_route53/_internal/__init__.py
--- old/certbot-dns-route53-0.40.1/certbot_dns_route53/_internal/__init__.py    
1970-01-01 01:00:00.000000000 +0100
+++ new/certbot-dns-route53-1.0.0/certbot_dns_route53/_internal/__init__.py     
2019-12-03 18:20:30.000000000 +0100
@@ -0,0 +1 @@
+"""Internal implementation of `~certbot_dns_route53.dns_route53` plugin."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-route53-0.40.1/certbot_dns_route53/_internal/dns_route53.py 
new/certbot-dns-route53-1.0.0/certbot_dns_route53/_internal/dns_route53.py
--- old/certbot-dns-route53-0.40.1/certbot_dns_route53/_internal/dns_route53.py 
1970-01-01 01:00:00.000000000 +0100
+++ new/certbot-dns-route53-1.0.0/certbot_dns_route53/_internal/dns_route53.py  
2019-12-03 18:20:30.000000000 +0100
@@ -0,0 +1,151 @@
+"""Certbot Route53 authenticator plugin."""
+import collections
+import logging
+import time
+
+import boto3
+import zope.interface
+from botocore.exceptions import NoCredentialsError, ClientError
+
+from certbot import errors
+from certbot import interfaces
+from certbot.plugins import dns_common
+
+from acme.magic_typing import DefaultDict, List, Dict # pylint: 
disable=unused-import, no-name-in-module
+
+logger = logging.getLogger(__name__)
+
+INSTRUCTIONS = (
+    "To use certbot-dns-route53, configure credentials as described at "
+    
"https://boto3.readthedocs.io/en/latest/guide/configuration.html#best-practices-for-configuring-credentials
 "  # pylint: disable=line-too-long
+    "and add the necessary permissions for Route53 access.")
+
+@zope.interface.implementer(interfaces.IAuthenticator)
+@zope.interface.provider(interfaces.IPluginFactory)
+class Authenticator(dns_common.DNSAuthenticator):
+    """Route53 Authenticator
+
+    This authenticator solves a DNS01 challenge by uploading the answer to AWS
+    Route53.
+    """
+
+    description = ("Obtain certificates using a DNS TXT record (if you are 
using AWS Route53 for "
+                   "DNS).")
+    ttl = 10
+
+    def __init__(self, *args, **kwargs):
+        super(Authenticator, self).__init__(*args, **kwargs)
+        self.r53 = boto3.client("route53")
+        self._resource_records = collections.defaultdict(list) # type: 
DefaultDict[str, List[Dict[str, str]]]
+
+    def more_info(self):  # pylint: disable=missing-docstring,no-self-use
+        return "Solve a DNS01 challenge using AWS Route53"
+
+    def _setup_credentials(self):
+        pass
+
+    def _perform(self, domain, validation_name, validation): # pylint: 
disable=missing-docstring
+        pass
+
+    def perform(self, achalls):
+        self._attempt_cleanup = True
+
+        try:
+            change_ids = [
+                self._change_txt_record("UPSERT",
+                  achall.validation_domain_name(achall.domain),
+                  achall.validation(achall.account_key))
+                for achall in achalls
+            ]
+
+            for change_id in change_ids:
+                self._wait_for_change(change_id)
+        except (NoCredentialsError, ClientError) as e:
+            logger.debug('Encountered error during perform: %s', e, 
exc_info=True)
+            raise errors.PluginError("\n".join([str(e), INSTRUCTIONS]))
+        return [achall.response(achall.account_key) for achall in achalls]
+
+    def _cleanup(self, domain, validation_name, validation):
+        try:
+            self._change_txt_record("DELETE", validation_name, validation)
+        except (NoCredentialsError, ClientError) as e:
+            logger.debug('Encountered error during cleanup: %s', e, 
exc_info=True)
+
+    def _find_zone_id_for_domain(self, domain):
+        """Find the zone id responsible a given FQDN.
+
+           That is, the id for the zone whose name is the longest parent of the
+           domain.
+        """
+        paginator = self.r53.get_paginator("list_hosted_zones")
+        zones = []
+        target_labels = domain.rstrip(".").split(".")
+        for page in paginator.paginate():
+            for zone in page["HostedZones"]:
+                if zone["Config"]["PrivateZone"]:
+                    continue
+
+                candidate_labels = zone["Name"].rstrip(".").split(".")
+                if candidate_labels == target_labels[-len(candidate_labels):]:
+                    zones.append((zone["Name"], zone["Id"]))
+
+        if not zones:
+            raise errors.PluginError(
+                "Unable to find a Route53 hosted zone for {0}".format(domain)
+            )
+
+        # Order the zones that are suffixes for our desired to domain by
+        # length, this puts them in an order like:
+        # ["foo.bar.baz.com", "bar.baz.com", "baz.com", "com"]
+        # And then we choose the first one, which will be the most specific.
+        zones.sort(key=lambda z: len(z[0]), reverse=True)
+        return zones[0][1]
+
+    def _change_txt_record(self, action, validation_domain_name, validation):
+        zone_id = self._find_zone_id_for_domain(validation_domain_name)
+
+        rrecords = self._resource_records[validation_domain_name]
+        challenge = {"Value": '"{0}"'.format(validation)}
+        if action == "DELETE":
+            # Remove the record being deleted from the list of tracked records
+            rrecords.remove(challenge)
+            if rrecords:
+                # Need to update instead, as we're not deleting the rrset
+                action = "UPSERT"
+            else:
+                # Create a new list containing the record to use with DELETE
+                rrecords = [challenge]
+        else:
+            rrecords.append(challenge)
+
+        response = self.r53.change_resource_record_sets(
+            HostedZoneId=zone_id,
+            ChangeBatch={
+                "Comment": "certbot-dns-route53 certificate validation " + 
action,
+                "Changes": [
+                    {
+                        "Action": action,
+                        "ResourceRecordSet": {
+                            "Name": validation_domain_name,
+                            "Type": "TXT",
+                            "TTL": self.ttl,
+                            "ResourceRecords": rrecords,
+                        }
+                    }
+                ]
+            }
+        )
+        return response["ChangeInfo"]["Id"]
+
+    def _wait_for_change(self, change_id):
+        """Wait for a change to be propagated to all Route53 DNS servers.
+           
https://docs.aws.amazon.com/Route53/latest/APIReference/API_GetChange.html
+        """
+        for unused_n in range(0, 120):
+            response = self.r53.get_change(Id=change_id)
+            if response["ChangeInfo"]["Status"] == "INSYNC":
+                return
+            time.sleep(5)
+        raise errors.PluginError(
+            "Timed out waiting for Route53 change. Current status: %s" %
+            response["ChangeInfo"]["Status"])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-route53-0.40.1/certbot_dns_route53/authenticator.py 
new/certbot-dns-route53-1.0.0/certbot_dns_route53/authenticator.py
--- old/certbot-dns-route53-0.40.1/certbot_dns_route53/authenticator.py 
2019-11-06 03:24:51.000000000 +0100
+++ new/certbot-dns-route53-1.0.0/certbot_dns_route53/authenticator.py  
2019-12-03 18:20:30.000000000 +0100
@@ -1,16 +1,17 @@
-"""Shim around `~certbot_dns_route53.dns_route53` for backwards 
compatibility."""
+"""Shim around `~certbot_dns_route53._internal.dns_route53` for backwards 
compatibility."""
 import warnings
 
 import zope.interface
 
 from certbot import interfaces
-from certbot_dns_route53 import dns_route53
+from certbot_dns_route53._internal import dns_route53
 
 
 @zope.interface.implementer(interfaces.IAuthenticator)
 @zope.interface.provider(interfaces.IPluginFactory)
 class Authenticator(dns_route53.Authenticator):
-    """Shim around `~certbot_dns_route53.dns_route53.Authenticator` for 
backwards compatibility."""
+    """Shim around `~certbot_dns_route53._internal.dns_route53.Authenticator`
+       for backwards compatibility."""
 
     hidden = True
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-route53-0.40.1/certbot_dns_route53/dns_route53.py 
new/certbot-dns-route53-1.0.0/certbot_dns_route53/dns_route53.py
--- old/certbot-dns-route53-0.40.1/certbot_dns_route53/dns_route53.py   
2019-11-06 03:24:51.000000000 +0100
+++ new/certbot-dns-route53-1.0.0/certbot_dns_route53/dns_route53.py    
1970-01-01 01:00:00.000000000 +0100
@@ -1,151 +0,0 @@
-"""Certbot Route53 authenticator plugin."""
-import collections
-import logging
-import time
-
-import boto3
-import zope.interface
-from botocore.exceptions import NoCredentialsError, ClientError
-
-from certbot import errors
-from certbot import interfaces
-from certbot.plugins import dns_common
-
-from acme.magic_typing import DefaultDict, List, Dict # pylint: 
disable=unused-import, no-name-in-module
-
-logger = logging.getLogger(__name__)
-
-INSTRUCTIONS = (
-    "To use certbot-dns-route53, configure credentials as described at "
-    
"https://boto3.readthedocs.io/en/latest/guide/configuration.html#best-practices-for-configuring-credentials
 "  # pylint: disable=line-too-long
-    "and add the necessary permissions for Route53 access.")
-
-@zope.interface.implementer(interfaces.IAuthenticator)
-@zope.interface.provider(interfaces.IPluginFactory)
-class Authenticator(dns_common.DNSAuthenticator):
-    """Route53 Authenticator
-
-    This authenticator solves a DNS01 challenge by uploading the answer to AWS
-    Route53.
-    """
-
-    description = ("Obtain certificates using a DNS TXT record (if you are 
using AWS Route53 for "
-                   "DNS).")
-    ttl = 10
-
-    def __init__(self, *args, **kwargs):
-        super(Authenticator, self).__init__(*args, **kwargs)
-        self.r53 = boto3.client("route53")
-        self._resource_records = collections.defaultdict(list) # type: 
DefaultDict[str, List[Dict[str, str]]]
-
-    def more_info(self):  # pylint: disable=missing-docstring,no-self-use
-        return "Solve a DNS01 challenge using AWS Route53"
-
-    def _setup_credentials(self):
-        pass
-
-    def _perform(self, domain, validation_name, validation): # pylint: 
disable=missing-docstring
-        pass
-
-    def perform(self, achalls):
-        self._attempt_cleanup = True
-
-        try:
-            change_ids = [
-                self._change_txt_record("UPSERT",
-                  achall.validation_domain_name(achall.domain),
-                  achall.validation(achall.account_key))
-                for achall in achalls
-            ]
-
-            for change_id in change_ids:
-                self._wait_for_change(change_id)
-        except (NoCredentialsError, ClientError) as e:
-            logger.debug('Encountered error during perform: %s', e, 
exc_info=True)
-            raise errors.PluginError("\n".join([str(e), INSTRUCTIONS]))
-        return [achall.response(achall.account_key) for achall in achalls]
-
-    def _cleanup(self, domain, validation_name, validation):
-        try:
-            self._change_txt_record("DELETE", validation_name, validation)
-        except (NoCredentialsError, ClientError) as e:
-            logger.debug('Encountered error during cleanup: %s', e, 
exc_info=True)
-
-    def _find_zone_id_for_domain(self, domain):
-        """Find the zone id responsible a given FQDN.
-
-           That is, the id for the zone whose name is the longest parent of the
-           domain.
-        """
-        paginator = self.r53.get_paginator("list_hosted_zones")
-        zones = []
-        target_labels = domain.rstrip(".").split(".")
-        for page in paginator.paginate():
-            for zone in page["HostedZones"]:
-                if zone["Config"]["PrivateZone"]:
-                    continue
-
-                candidate_labels = zone["Name"].rstrip(".").split(".")
-                if candidate_labels == target_labels[-len(candidate_labels):]:
-                    zones.append((zone["Name"], zone["Id"]))
-
-        if not zones:
-            raise errors.PluginError(
-                "Unable to find a Route53 hosted zone for {0}".format(domain)
-            )
-
-        # Order the zones that are suffixes for our desired to domain by
-        # length, this puts them in an order like:
-        # ["foo.bar.baz.com", "bar.baz.com", "baz.com", "com"]
-        # And then we choose the first one, which will be the most specific.
-        zones.sort(key=lambda z: len(z[0]), reverse=True)
-        return zones[0][1]
-
-    def _change_txt_record(self, action, validation_domain_name, validation):
-        zone_id = self._find_zone_id_for_domain(validation_domain_name)
-
-        rrecords = self._resource_records[validation_domain_name]
-        challenge = {"Value": '"{0}"'.format(validation)}
-        if action == "DELETE":
-            # Remove the record being deleted from the list of tracked records
-            rrecords.remove(challenge)
-            if rrecords:
-                # Need to update instead, as we're not deleting the rrset
-                action = "UPSERT"
-            else:
-                # Create a new list containing the record to use with DELETE
-                rrecords = [challenge]
-        else:
-            rrecords.append(challenge)
-
-        response = self.r53.change_resource_record_sets(
-            HostedZoneId=zone_id,
-            ChangeBatch={
-                "Comment": "certbot-dns-route53 certificate validation " + 
action,
-                "Changes": [
-                    {
-                        "Action": action,
-                        "ResourceRecordSet": {
-                            "Name": validation_domain_name,
-                            "Type": "TXT",
-                            "TTL": self.ttl,
-                            "ResourceRecords": rrecords,
-                        }
-                    }
-                ]
-            }
-        )
-        return response["ChangeInfo"]["Id"]
-
-    def _wait_for_change(self, change_id):
-        """Wait for a change to be propagated to all Route53 DNS servers.
-           
https://docs.aws.amazon.com/Route53/latest/APIReference/API_GetChange.html
-        """
-        for unused_n in range(0, 120):
-            response = self.r53.get_change(Id=change_id)
-            if response["ChangeInfo"]["Status"] == "INSYNC":
-                return
-            time.sleep(5)
-        raise errors.PluginError(
-            "Timed out waiting for Route53 change. Current status: %s" %
-            response["ChangeInfo"]["Status"])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-route53-0.40.1/certbot_dns_route53/dns_route53_test.py 
new/certbot-dns-route53-1.0.0/certbot_dns_route53/dns_route53_test.py
--- old/certbot-dns-route53-0.40.1/certbot_dns_route53/dns_route53_test.py      
2019-11-06 03:24:51.000000000 +0100
+++ new/certbot-dns-route53-1.0.0/certbot_dns_route53/dns_route53_test.py       
1970-01-01 01:00:00.000000000 +0100
@@ -1,263 +0,0 @@
-"""Tests for certbot_dns_route53.dns_route53.Authenticator"""
-
-import unittest
-
-import mock
-from botocore.exceptions import NoCredentialsError, ClientError
-
-from certbot import errors
-from certbot.compat import os
-from certbot.plugins import dns_test_common
-from certbot.plugins.dns_test_common import DOMAIN
-
-
-class AuthenticatorTest(unittest.TestCase, 
dns_test_common.BaseAuthenticatorTest):
-    # pylint: disable=protected-access
-
-    def setUp(self):
-        from certbot_dns_route53.dns_route53 import Authenticator
-
-        super(AuthenticatorTest, self).setUp()
-
-        self.config = mock.MagicMock()
-
-        # Set up dummy credentials for testing
-        os.environ["AWS_ACCESS_KEY_ID"] = "dummy_access_key"
-        os.environ["AWS_SECRET_ACCESS_KEY"] = "dummy_secret_access_key"
-
-        self.auth = Authenticator(self.config, "route53")
-
-    def tearDown(self):
-        # Remove the dummy credentials from env vars
-        del os.environ["AWS_ACCESS_KEY_ID"]
-        del os.environ["AWS_SECRET_ACCESS_KEY"]
-        super(AuthenticatorTest, self).tearDown()
-
-    def test_perform(self):
-        self.auth._change_txt_record = mock.MagicMock()
-        self.auth._wait_for_change = mock.MagicMock()
-
-        self.auth.perform([self.achall])
-
-        self.auth._change_txt_record.assert_called_once_with("UPSERT",
-                                                             
'_acme-challenge.' + DOMAIN,
-                                                             mock.ANY)
-        self.assertEqual(self.auth._wait_for_change.call_count, 1)
-
-    def test_perform_no_credentials_error(self):
-        self.auth._change_txt_record = 
mock.MagicMock(side_effect=NoCredentialsError)
-
-        self.assertRaises(errors.PluginError,
-                          self.auth.perform,
-                          [self.achall])
-
-    def test_perform_client_error(self):
-        self.auth._change_txt_record = mock.MagicMock(
-            side_effect=ClientError({"Error": {"Code": "foo"}}, "bar"))
-
-        self.assertRaises(errors.PluginError,
-                          self.auth.perform,
-                          [self.achall])
-
-    def test_cleanup(self):
-        self.auth._attempt_cleanup = True
-
-        self.auth._change_txt_record = mock.MagicMock()
-
-        self.auth.cleanup([self.achall])
-
-        self.auth._change_txt_record.assert_called_once_with("DELETE",
-                                                             
'_acme-challenge.'+DOMAIN,
-                                                             mock.ANY)
-
-    def test_cleanup_no_credentials_error(self):
-        self.auth._attempt_cleanup = True
-
-        self.auth._change_txt_record = 
mock.MagicMock(side_effect=NoCredentialsError)
-
-        self.auth.cleanup([self.achall])
-
-    def test_cleanup_client_error(self):
-        self.auth._attempt_cleanup = True
-
-        self.auth._change_txt_record = mock.MagicMock(
-            side_effect=ClientError({"Error": {"Code": "foo"}}, "bar"))
-
-        self.auth.cleanup([self.achall])
-
-
-class ClientTest(unittest.TestCase):
-    # pylint: disable=protected-access
-
-    PRIVATE_ZONE = {
-                        "Id": "BAD-PRIVATE",
-                        "Name": "example.com",
-                        "Config": {
-                            "PrivateZone": True
-                        }
-                    }
-
-    EXAMPLE_NET_ZONE = {
-                            "Id": "BAD-WRONG-TLD",
-                            "Name": "example.net",
-                            "Config": {
-                                "PrivateZone": False
-                            }
-                        }
-
-    EXAMPLE_COM_ZONE = {
-                            "Id": "EXAMPLE",
-                            "Name": "example.com",
-                            "Config": {
-                                "PrivateZone": False
-                            }
-                        }
-
-    FOO_EXAMPLE_COM_ZONE = {
-                                "Id": "FOO",
-                                "Name": "foo.example.com",
-                                "Config": {
-                                    "PrivateZone": False
-                                }
-                            }
-
-    def setUp(self):
-        from certbot_dns_route53.dns_route53 import Authenticator
-
-        super(ClientTest, self).setUp()
-
-        self.config = mock.MagicMock()
-
-        # Set up dummy credentials for testing
-        os.environ["AWS_ACCESS_KEY_ID"] = "dummy_access_key"
-        os.environ["AWS_SECRET_ACCESS_KEY"] = "dummy_secret_access_key"
-
-        self.client = Authenticator(self.config, "route53")
-
-    def tearDown(self):
-        # Remove the dummy credentials from env vars
-        del os.environ["AWS_ACCESS_KEY_ID"]
-        del os.environ["AWS_SECRET_ACCESS_KEY"]
-        super(ClientTest, self).tearDown()
-
-    def test_find_zone_id_for_domain(self):
-        self.client.r53.get_paginator = mock.MagicMock()
-        self.client.r53.get_paginator().paginate.return_value = [
-            {
-                "HostedZones": [
-                    self.EXAMPLE_NET_ZONE,
-                    self.EXAMPLE_COM_ZONE,
-                ]
-            }
-        ]
-
-        result = self.client._find_zone_id_for_domain("foo.example.com")
-        self.assertEqual(result, "EXAMPLE")
-
-    def test_find_zone_id_for_domain_pagination(self):
-        self.client.r53.get_paginator = mock.MagicMock()
-        self.client.r53.get_paginator().paginate.return_value = [
-            {
-                "HostedZones": [
-                    self.PRIVATE_ZONE,
-                    self.EXAMPLE_COM_ZONE,
-                ]
-            },
-            {
-                "HostedZones": [
-                    self.PRIVATE_ZONE,
-                    self.FOO_EXAMPLE_COM_ZONE,
-                ]
-            }
-        ]
-
-        result = self.client._find_zone_id_for_domain("foo.example.com")
-        self.assertEqual(result, "FOO")
-
-    def test_find_zone_id_for_domain_no_results(self):
-        self.client.r53.get_paginator = mock.MagicMock()
-        self.client.r53.get_paginator().paginate.return_value = []
-
-        self.assertRaises(errors.PluginError,
-                          self.client._find_zone_id_for_domain,
-                          "foo.example.com")
-
-    def test_find_zone_id_for_domain_no_correct_results(self):
-        self.client.r53.get_paginator = mock.MagicMock()
-        self.client.r53.get_paginator().paginate.return_value = [
-            {
-                "HostedZones": [
-                    self.PRIVATE_ZONE,
-                    self.EXAMPLE_NET_ZONE,
-                ]
-            },
-        ]
-
-        self.assertRaises(errors.PluginError,
-                          self.client._find_zone_id_for_domain,
-                          "foo.example.com")
-
-    def test_change_txt_record(self):
-        self.client._find_zone_id_for_domain = mock.MagicMock()
-        self.client.r53.change_resource_record_sets = mock.MagicMock(
-            return_value={"ChangeInfo": {"Id": 1}})
-
-        self.client._change_txt_record("FOO", DOMAIN, "foo")
-
-        call_count = self.client.r53.change_resource_record_sets.call_count
-        self.assertEqual(call_count, 1)
-
-    def test_change_txt_record_delete(self):
-        self.client._find_zone_id_for_domain = mock.MagicMock()
-        self.client.r53.change_resource_record_sets = mock.MagicMock(
-            return_value={"ChangeInfo": {"Id": 1}})
-
-        validation = "some-value"
-        validation_record = {"Value": '"{0}"'.format(validation)}
-        self.client._resource_records[DOMAIN] = [validation_record]
-
-        self.client._change_txt_record("DELETE", DOMAIN, validation)
-
-        call_count = self.client.r53.change_resource_record_sets.call_count
-        self.assertEqual(call_count, 1)
-        call_args = 
self.client.r53.change_resource_record_sets.call_args_list[0][1]
-        call_args_batch = call_args["ChangeBatch"]["Changes"][0]
-        self.assertEqual(call_args_batch["Action"], "DELETE")
-        self.assertEqual(
-            call_args_batch["ResourceRecordSet"]["ResourceRecords"],
-            [validation_record])
-
-    def test_change_txt_record_multirecord(self):
-        self.client._find_zone_id_for_domain = mock.MagicMock()
-        self.client._get_validation_rrset = mock.MagicMock()
-        self.client._resource_records[DOMAIN] = [
-            {"Value": "\"pre-existing-value\""},
-            {"Value": "\"pre-existing-value-two\""},
-        ]
-        self.client.r53.change_resource_record_sets = mock.MagicMock(
-            return_value={"ChangeInfo": {"Id": 1}})
-
-        self.client._change_txt_record("DELETE", DOMAIN, "pre-existing-value")
-
-        call_count = self.client.r53.change_resource_record_sets.call_count
-        call_args = 
self.client.r53.change_resource_record_sets.call_args_list[0][1]
-        call_args_batch = call_args["ChangeBatch"]["Changes"][0]
-        self.assertEqual(call_args_batch["Action"], "UPSERT")
-        self.assertEqual(
-            call_args_batch["ResourceRecordSet"]["ResourceRecords"],
-            [{"Value": "\"pre-existing-value-two\""}])
-
-        self.assertEqual(call_count, 1)
-
-    def test_wait_for_change(self):
-        self.client.r53.get_change = mock.MagicMock(
-            side_effect=[{"ChangeInfo": {"Status": "PENDING"}},
-                         {"ChangeInfo": {"Status": "INSYNC"}}])
-
-        self.client._wait_for_change(1)
-
-        self.assertTrue(self.client.r53.get_change.called)
-
-
-if __name__ == "__main__":
-    unittest.main()  # pragma: no cover
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-route53-0.40.1/certbot_dns_route53.egg-info/PKG-INFO 
new/certbot-dns-route53-1.0.0/certbot_dns_route53.egg-info/PKG-INFO
--- old/certbot-dns-route53-0.40.1/certbot_dns_route53.egg-info/PKG-INFO        
2019-11-06 03:25:26.000000000 +0100
+++ new/certbot-dns-route53-1.0.0/certbot_dns_route53.egg-info/PKG-INFO 
2019-12-03 18:21:17.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: certbot-dns-route53
-Version: 0.40.1
+Version: 1.0.0
 Summary: Route53 DNS Authenticator plugin for Certbot
 Home-page: https://github.com/certbot/certbot
 Author: Certbot Project
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-route53-0.40.1/certbot_dns_route53.egg-info/SOURCES.txt 
new/certbot-dns-route53-1.0.0/certbot_dns_route53.egg-info/SOURCES.txt
--- old/certbot-dns-route53-0.40.1/certbot_dns_route53.egg-info/SOURCES.txt     
2019-11-06 03:25:26.000000000 +0100
+++ new/certbot-dns-route53-1.0.0/certbot_dns_route53.egg-info/SOURCES.txt      
2019-12-03 18:21:17.000000000 +0100
@@ -5,19 +5,18 @@
 setup.py
 certbot_dns_route53/__init__.py
 certbot_dns_route53/authenticator.py
-certbot_dns_route53/dns_route53.py
-certbot_dns_route53/dns_route53_test.py
 certbot_dns_route53.egg-info/PKG-INFO
 certbot_dns_route53.egg-info/SOURCES.txt
 certbot_dns_route53.egg-info/dependency_links.txt
 certbot_dns_route53.egg-info/entry_points.txt
 certbot_dns_route53.egg-info/requires.txt
 certbot_dns_route53.egg-info/top_level.txt
+certbot_dns_route53/_internal/__init__.py
+certbot_dns_route53/_internal/dns_route53.py
 docs/.gitignore
 docs/Makefile
 docs/api.rst
 docs/conf.py
 docs/index.rst
 docs/make.bat
-docs/api/authenticator.rst
-docs/api/dns_route53.rst
\ No newline at end of file
+tests/dns_route53_test.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-route53-0.40.1/certbot_dns_route53.egg-info/entry_points.txt 
new/certbot-dns-route53-1.0.0/certbot_dns_route53.egg-info/entry_points.txt
--- 
old/certbot-dns-route53-0.40.1/certbot_dns_route53.egg-info/entry_points.txt    
    2019-11-06 03:25:26.000000000 +0100
+++ new/certbot-dns-route53-1.0.0/certbot_dns_route53.egg-info/entry_points.txt 
2019-12-03 18:21:17.000000000 +0100
@@ -1,4 +1,4 @@
 [certbot.plugins]
 certbot-route53:auth = certbot_dns_route53.authenticator:Authenticator
-dns-route53 = certbot_dns_route53.dns_route53:Authenticator
+dns-route53 = certbot_dns_route53._internal.dns_route53:Authenticator
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-route53-0.40.1/docs/api/authenticator.rst 
new/certbot-dns-route53-1.0.0/docs/api/authenticator.rst
--- old/certbot-dns-route53-0.40.1/docs/api/authenticator.rst   2019-11-06 
03:24:51.000000000 +0100
+++ new/certbot-dns-route53-1.0.0/docs/api/authenticator.rst    1970-01-01 
01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-:mod:`certbot_dns_route53.authenticator`
-----------------------------------------
-
-.. automodule:: certbot_dns_route53.authenticator
-   :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-dns-route53-0.40.1/docs/api/dns_route53.rst 
new/certbot-dns-route53-1.0.0/docs/api/dns_route53.rst
--- old/certbot-dns-route53-0.40.1/docs/api/dns_route53.rst     2019-11-06 
03:24:51.000000000 +0100
+++ new/certbot-dns-route53-1.0.0/docs/api/dns_route53.rst      1970-01-01 
01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-:mod:`certbot_dns_route53.dns_route53`
---------------------------------------
-
-.. automodule:: certbot_dns_route53.dns_route53
-   :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-dns-route53-0.40.1/docs/api.rst 
new/certbot-dns-route53-1.0.0/docs/api.rst
--- old/certbot-dns-route53-0.40.1/docs/api.rst 2019-11-06 03:24:51.000000000 
+0100
+++ new/certbot-dns-route53-1.0.0/docs/api.rst  2019-12-03 18:20:30.000000000 
+0100
@@ -2,7 +2,4 @@
 API Documentation
 =================
 
-.. toctree::
-   :glob:
-
-   api/**
+Certbot plugins implement the Certbot plugins API, and do not otherwise have 
an external API.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-dns-route53-0.40.1/setup.py 
new/certbot-dns-route53-1.0.0/setup.py
--- old/certbot-dns-route53-0.40.1/setup.py     2019-11-06 03:24:52.000000000 
+0100
+++ new/certbot-dns-route53-1.0.0/setup.py      2019-12-03 18:20:32.000000000 
+0100
@@ -1,7 +1,9 @@
 from setuptools import setup
 from setuptools import find_packages
+from setuptools.command.test import test as TestCommand
+import sys
 
-version = '0.40.1'
+version = '1.0.0'
 
 # Remember to update local-oldest-requirements.txt when changing the minimum
 # acme/certbot version.
@@ -14,6 +16,20 @@
     'zope.interface',
 ]
 
+class PyTest(TestCommand):
+    user_options = []
+
+    def initialize_options(self):
+        TestCommand.initialize_options(self)
+        self.pytest_args = ''
+
+    def run_tests(self):
+        import shlex
+        # import here, cause outside the eggs aren't loaded
+        import pytest
+        errno = pytest.main(shlex.split(self.pytest_args))
+        sys.exit(errno)
+
 setup(
     name='certbot-dns-route53',
     version=version,
@@ -51,9 +67,11 @@
     keywords=['certbot', 'route53', 'aws'],
     entry_points={
         'certbot.plugins': [
-            'dns-route53 = certbot_dns_route53.dns_route53:Authenticator',
+            'dns-route53 = 
certbot_dns_route53._internal.dns_route53:Authenticator',
             'certbot-route53:auth = 
certbot_dns_route53.authenticator:Authenticator'
         ],
     },
+    tests_require=["pytest"],
     test_suite='certbot_dns_route53',
+    cmdclass={"test": PyTest},
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-dns-route53-0.40.1/tests/dns_route53_test.py 
new/certbot-dns-route53-1.0.0/tests/dns_route53_test.py
--- old/certbot-dns-route53-0.40.1/tests/dns_route53_test.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/certbot-dns-route53-1.0.0/tests/dns_route53_test.py     2019-12-03 
18:20:30.000000000 +0100
@@ -0,0 +1,263 @@
+"""Tests for certbot_dns_route53._internal.dns_route53.Authenticator"""
+
+import unittest
+
+import mock
+from botocore.exceptions import NoCredentialsError, ClientError
+
+from certbot import errors
+from certbot.compat import os
+from certbot.plugins import dns_test_common
+from certbot.plugins.dns_test_common import DOMAIN
+
+
+class AuthenticatorTest(unittest.TestCase, 
dns_test_common.BaseAuthenticatorTest):
+    # pylint: disable=protected-access
+
+    def setUp(self):
+        from certbot_dns_route53._internal.dns_route53 import Authenticator
+
+        super(AuthenticatorTest, self).setUp()
+
+        self.config = mock.MagicMock()
+
+        # Set up dummy credentials for testing
+        os.environ["AWS_ACCESS_KEY_ID"] = "dummy_access_key"
+        os.environ["AWS_SECRET_ACCESS_KEY"] = "dummy_secret_access_key"
+
+        self.auth = Authenticator(self.config, "route53")
+
+    def tearDown(self):
+        # Remove the dummy credentials from env vars
+        del os.environ["AWS_ACCESS_KEY_ID"]
+        del os.environ["AWS_SECRET_ACCESS_KEY"]
+        super(AuthenticatorTest, self).tearDown()
+
+    def test_perform(self):
+        self.auth._change_txt_record = mock.MagicMock()
+        self.auth._wait_for_change = mock.MagicMock()
+
+        self.auth.perform([self.achall])
+
+        self.auth._change_txt_record.assert_called_once_with("UPSERT",
+                                                             
'_acme-challenge.' + DOMAIN,
+                                                             mock.ANY)
+        self.assertEqual(self.auth._wait_for_change.call_count, 1)
+
+    def test_perform_no_credentials_error(self):
+        self.auth._change_txt_record = 
mock.MagicMock(side_effect=NoCredentialsError)
+
+        self.assertRaises(errors.PluginError,
+                          self.auth.perform,
+                          [self.achall])
+
+    def test_perform_client_error(self):
+        self.auth._change_txt_record = mock.MagicMock(
+            side_effect=ClientError({"Error": {"Code": "foo"}}, "bar"))
+
+        self.assertRaises(errors.PluginError,
+                          self.auth.perform,
+                          [self.achall])
+
+    def test_cleanup(self):
+        self.auth._attempt_cleanup = True
+
+        self.auth._change_txt_record = mock.MagicMock()
+
+        self.auth.cleanup([self.achall])
+
+        self.auth._change_txt_record.assert_called_once_with("DELETE",
+                                                             
'_acme-challenge.'+DOMAIN,
+                                                             mock.ANY)
+
+    def test_cleanup_no_credentials_error(self):
+        self.auth._attempt_cleanup = True
+
+        self.auth._change_txt_record = 
mock.MagicMock(side_effect=NoCredentialsError)
+
+        self.auth.cleanup([self.achall])
+
+    def test_cleanup_client_error(self):
+        self.auth._attempt_cleanup = True
+
+        self.auth._change_txt_record = mock.MagicMock(
+            side_effect=ClientError({"Error": {"Code": "foo"}}, "bar"))
+
+        self.auth.cleanup([self.achall])
+
+
+class ClientTest(unittest.TestCase):
+    # pylint: disable=protected-access
+
+    PRIVATE_ZONE = {
+                        "Id": "BAD-PRIVATE",
+                        "Name": "example.com",
+                        "Config": {
+                            "PrivateZone": True
+                        }
+                    }
+
+    EXAMPLE_NET_ZONE = {
+                            "Id": "BAD-WRONG-TLD",
+                            "Name": "example.net",
+                            "Config": {
+                                "PrivateZone": False
+                            }
+                        }
+
+    EXAMPLE_COM_ZONE = {
+                            "Id": "EXAMPLE",
+                            "Name": "example.com",
+                            "Config": {
+                                "PrivateZone": False
+                            }
+                        }
+
+    FOO_EXAMPLE_COM_ZONE = {
+                                "Id": "FOO",
+                                "Name": "foo.example.com",
+                                "Config": {
+                                    "PrivateZone": False
+                                }
+                            }
+
+    def setUp(self):
+        from certbot_dns_route53._internal.dns_route53 import Authenticator
+
+        super(ClientTest, self).setUp()
+
+        self.config = mock.MagicMock()
+
+        # Set up dummy credentials for testing
+        os.environ["AWS_ACCESS_KEY_ID"] = "dummy_access_key"
+        os.environ["AWS_SECRET_ACCESS_KEY"] = "dummy_secret_access_key"
+
+        self.client = Authenticator(self.config, "route53")
+
+    def tearDown(self):
+        # Remove the dummy credentials from env vars
+        del os.environ["AWS_ACCESS_KEY_ID"]
+        del os.environ["AWS_SECRET_ACCESS_KEY"]
+        super(ClientTest, self).tearDown()
+
+    def test_find_zone_id_for_domain(self):
+        self.client.r53.get_paginator = mock.MagicMock()
+        self.client.r53.get_paginator().paginate.return_value = [
+            {
+                "HostedZones": [
+                    self.EXAMPLE_NET_ZONE,
+                    self.EXAMPLE_COM_ZONE,
+                ]
+            }
+        ]
+
+        result = self.client._find_zone_id_for_domain("foo.example.com")
+        self.assertEqual(result, "EXAMPLE")
+
+    def test_find_zone_id_for_domain_pagination(self):
+        self.client.r53.get_paginator = mock.MagicMock()
+        self.client.r53.get_paginator().paginate.return_value = [
+            {
+                "HostedZones": [
+                    self.PRIVATE_ZONE,
+                    self.EXAMPLE_COM_ZONE,
+                ]
+            },
+            {
+                "HostedZones": [
+                    self.PRIVATE_ZONE,
+                    self.FOO_EXAMPLE_COM_ZONE,
+                ]
+            }
+        ]
+
+        result = self.client._find_zone_id_for_domain("foo.example.com")
+        self.assertEqual(result, "FOO")
+
+    def test_find_zone_id_for_domain_no_results(self):
+        self.client.r53.get_paginator = mock.MagicMock()
+        self.client.r53.get_paginator().paginate.return_value = []
+
+        self.assertRaises(errors.PluginError,
+                          self.client._find_zone_id_for_domain,
+                          "foo.example.com")
+
+    def test_find_zone_id_for_domain_no_correct_results(self):
+        self.client.r53.get_paginator = mock.MagicMock()
+        self.client.r53.get_paginator().paginate.return_value = [
+            {
+                "HostedZones": [
+                    self.PRIVATE_ZONE,
+                    self.EXAMPLE_NET_ZONE,
+                ]
+            },
+        ]
+
+        self.assertRaises(errors.PluginError,
+                          self.client._find_zone_id_for_domain,
+                          "foo.example.com")
+
+    def test_change_txt_record(self):
+        self.client._find_zone_id_for_domain = mock.MagicMock()
+        self.client.r53.change_resource_record_sets = mock.MagicMock(
+            return_value={"ChangeInfo": {"Id": 1}})
+
+        self.client._change_txt_record("FOO", DOMAIN, "foo")
+
+        call_count = self.client.r53.change_resource_record_sets.call_count
+        self.assertEqual(call_count, 1)
+
+    def test_change_txt_record_delete(self):
+        self.client._find_zone_id_for_domain = mock.MagicMock()
+        self.client.r53.change_resource_record_sets = mock.MagicMock(
+            return_value={"ChangeInfo": {"Id": 1}})
+
+        validation = "some-value"
+        validation_record = {"Value": '"{0}"'.format(validation)}
+        self.client._resource_records[DOMAIN] = [validation_record]
+
+        self.client._change_txt_record("DELETE", DOMAIN, validation)
+
+        call_count = self.client.r53.change_resource_record_sets.call_count
+        self.assertEqual(call_count, 1)
+        call_args = 
self.client.r53.change_resource_record_sets.call_args_list[0][1]
+        call_args_batch = call_args["ChangeBatch"]["Changes"][0]
+        self.assertEqual(call_args_batch["Action"], "DELETE")
+        self.assertEqual(
+            call_args_batch["ResourceRecordSet"]["ResourceRecords"],
+            [validation_record])
+
+    def test_change_txt_record_multirecord(self):
+        self.client._find_zone_id_for_domain = mock.MagicMock()
+        self.client._get_validation_rrset = mock.MagicMock()
+        self.client._resource_records[DOMAIN] = [
+            {"Value": "\"pre-existing-value\""},
+            {"Value": "\"pre-existing-value-two\""},
+        ]
+        self.client.r53.change_resource_record_sets = mock.MagicMock(
+            return_value={"ChangeInfo": {"Id": 1}})
+
+        self.client._change_txt_record("DELETE", DOMAIN, "pre-existing-value")
+
+        call_count = self.client.r53.change_resource_record_sets.call_count
+        call_args = 
self.client.r53.change_resource_record_sets.call_args_list[0][1]
+        call_args_batch = call_args["ChangeBatch"]["Changes"][0]
+        self.assertEqual(call_args_batch["Action"], "UPSERT")
+        self.assertEqual(
+            call_args_batch["ResourceRecordSet"]["ResourceRecords"],
+            [{"Value": "\"pre-existing-value-two\""}])
+
+        self.assertEqual(call_count, 1)
+
+    def test_wait_for_change(self):
+        self.client.r53.get_change = mock.MagicMock(
+            side_effect=[{"ChangeInfo": {"Status": "PENDING"}},
+                         {"ChangeInfo": {"Status": "INSYNC"}}])
+
+        self.client._wait_for_change(1)
+
+        self.assertTrue(self.client.r53.get_change.called)
+
+
+if __name__ == "__main__":
+    unittest.main()  # pragma: no cover


Reply via email to