Repository: certbot/certbot

Issue:
Dropping support for Pythons in fetch.py
If we drop support for a version of Python previously supported by fetch.py, existing certbot-auto installations can fail. If we're unable to reboostrap because we don't have the user's permission, when certbot-auto is run again during phase 1 it will call `DeterminePythonVersion` and if we can't find an appropriate Python, we exit with an error. Instead, we should print a message about being unable to check for upgrades.


Discussion:

Resolving patch:
diff --git a/acme/acme/__init__.py b/acme/acme/__init__.py
--- a/acme/acme/__init__.py
+++ b/acme/acme/__init__.py
@@ -13,9 +13,10 @@
 import sys
 import warnings
 
-if sys.version_info[:2] == (3, 3):
-    warnings.warn(
-            "Python 3.3 support will be dropped in the next release of "
-            "acme. Please upgrade your Python version.",
-            PendingDeprecationWarning,
-    ) #pragma: no cover
+for (major, minor) in [(2, 6), (3, 3)]:
+    if sys.version_info[:2] == (major, minor):
+        warnings.warn(
+                "Python {0}.{1} support will be dropped in the next release of "
+                "acme. Please upgrade your Python version.".format(major, minor),
+                DeprecationWarning,
+        ) #pragma: no cover
diff --git a/certbot/main.py b/certbot/main.py
--- a/certbot/main.py
+++ b/certbot/main.py
@@ -4,6 +4,7 @@
 import logging.handlers
 import os
 import sys
+import warnings
 
 import configobj
 import josepy as jose
@@ -1217,9 +1218,17 @@ def main(cli_args=sys.argv[1:]):
         # Let plugins_cmd be run as un-privileged user.
         if config.func != plugins_cmd:
             raise
-    if sys.version_info[:2] == (3, 3):
-        logger.warning("Python 3.3 support will be dropped in the next release "
-                    "of Certbot - please upgrade your Python version.")
+    deprecation_fmt = (
+        "Python %s.%s support will be dropped in the next "
+        "release of Certbot - please upgrade your Python version.")
+    # We use the warnings system for Python 2.6 and logging for Python 3
+    # because DeprecationWarnings are only reported by default in Python <= 2.6
+    # and warnings can be disabled by the user.
+    if sys.version_info[:2] == (2, 6):
+        warning = deprecation_fmt % sys.version_info[:2]
+        warnings.warn(warning, DeprecationWarning)
+    elif sys.version_info[:2] == (3, 3):
+        logger.warning(deprecation_fmt, *sys.version_info[:2])
 
     set_displayer(config)
 
diff --git a/letsencrypt-auto-source/pieces/fetch.py b/letsencrypt-auto-source/pieces/fetch.py
--- a/letsencrypt-auto-source/pieces/fetch.py
+++ b/letsencrypt-auto-source/pieces/fetch.py
@@ -50,7 +50,7 @@ def __init__(self):
         # Based on pip 1.4.1's URLOpener
         # This verifies certs on only Python >=2.7.9, and when NO_CERT_VERIFY isn't set.
         if environ.get('NO_CERT_VERIFY') == '1' and hasattr(ssl, 'SSLContext'):
-            self._opener = build_opener(HTTPSHandler(context=create_CERT_NONE_context()))
+            self._opener = build_opener(HTTPSHandler(context=cert_none_context()))
         else:
             self._opener = build_opener(HTTPSHandler())
         # Strip out HTTPHandler to prevent MITM spoof:
@@ -88,7 +88,7 @@ def latest_stable_version(get):
     # The regex is a sufficient regex for picking out prereleases for most
     # packages, LE included.
     return str(max(LooseVersion(r) for r
-                   in iter(metadata['releases'].keys())
+                   in metadata['releases'].keys()
                    if re.match('^[0-9.]+$', r)))
 
 
@@ -120,7 +120,7 @@ def verified_new_le_auto(get, tag, temp_dir):
                             "certbot-auto.", exc)
 
 
-def create_CERT_NONE_context():
+def cert_none_context():
     """Create a SSLContext object to not check hostname."""
     # PROTOCOL_TLS isn't available before 2.7.13 but this code is for 2.7.9+, so use this.
     context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)


Test patch:
diff --git a/letsencrypt-auto-source/tests/centos6_tests.sh b/letsencrypt-auto-source/tests/centos6_tests.sh
--- a/letsencrypt-auto-source/tests/centos6_tests.sh
+++ b/letsencrypt-auto-source/tests/centos6_tests.sh
@@ -1,9 +1,11 @@
 #!/bin/bash
 # Start by making sure your system is up-to-date:
-yum update > /dev/null
+yum update -y > /dev/null
 yum install -y centos-release-scl > /dev/null
 yum install -y python27 > /dev/null 2> /dev/null
 
+LE_AUTO="certbot/letsencrypt-auto-source/letsencrypt-auto"
+
 # we're going to modify env variables, so do this in a subshell
 (
 source /opt/rh/python27/enable
@@ -25,7 +27,7 @@ if [ $RESULT -ne 0 ]; then
 fi
 
 # bootstrap, but don't install python 3.
-certbot/letsencrypt-auto-source/letsencrypt-auto --no-self-upgrade -n > /dev/null 2> /dev/null
+"$LE_AUTO" --no-self-upgrade -n > /dev/null 2> /dev/null
 
 # ensure python 3 isn't installed
 python3 --version 2> /dev/null
@@ -47,8 +49,14 @@ if [ $RESULT -eq 0 ]; then
   exit 1
 fi
 
+# Skip self upgrade due to Python 3 not being available.
+if ! "$LE_AUTO" 2>&1 | grep -q "WARNING: couldn't find Python"; then
+  echo "Python upgrade failure warning not printed!"
+  exit 1
+fi
+
 # bootstrap, this time installing python3
-certbot/letsencrypt-auto-source/letsencrypt-auto --no-self-upgrade -n > /dev/null 2> /dev/null
+"$LE_AUTO" --no-self-upgrade -n > /dev/null 2> /dev/null
 
 # ensure python 3 is installed
 python3 --version > /dev/null