Browse Source

Removed support for Python 3.3.

Tim Graham 9 years ago
parent
commit
7f1168e387

+ 1 - 1
django/apps/config.py

@@ -55,7 +55,7 @@ class AppConfig(object):
         """Attempt to determine app's filesystem path from its module."""
         # See #21874 for extended discussion of the behavior of this method in
         # various cases.
-        # Convert paths to list because Python 3.3 _NamespacePath does not
+        # Convert paths to list because Python 3's _NamespacePath does not
         # support indexing.
         paths = list(getattr(module, '__path__', []))
         if len(paths) != 1:

+ 1 - 8
django/core/mail/message.py

@@ -3,7 +3,6 @@ from __future__ import unicode_literals
 import mimetypes
 import os
 import random
-import sys
 import time
 from email import (
     charset as Charset, encoders as Encoders, generator, message_from_string,
@@ -170,13 +169,7 @@ class SafeMIMEText(MIMEMixin, MIMEText):
             # We do it manually and trigger re-encoding of the payload.
             MIMEText.__init__(self, _text, _subtype, None)
             del self['Content-Transfer-Encoding']
-            # Workaround for versions without http://bugs.python.org/issue19063
-            if (3, 2) < sys.version_info < (3, 3, 4):
-                payload = _text.encode(utf8_charset.output_charset)
-                self._payload = payload.decode('ascii', 'surrogateescape')
-                self.set_charset(utf8_charset)
-            else:
-                self.set_payload(_text, utf8_charset)
+            self.set_payload(_text, utf8_charset)
             self.replace_header('Content-Type', 'text/%s; charset="%s"' % (_subtype, _charset))
         elif _charset is None:
             # the default value of '_charset' is 'us-ascii' on Python 2

+ 2 - 3
django/db/backends/sqlite3/features.py

@@ -1,9 +1,8 @@
 from __future__ import unicode_literals
 
-import sys
-
 from django.db import utils
 from django.db.backends.base.features import BaseDatabaseFeatures
+from django.utils import six
 from django.utils.functional import cached_property
 
 from .base import Database
@@ -50,7 +49,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     @cached_property
     def can_share_in_memory_db(self):
         return (
-            sys.version_info[:2] >= (3, 4) and
+            six.PY3 and
             Database.__name__ == 'sqlite3.dbapi2' and
             Database.sqlite_version_info >= (3, 7, 13)
         )

+ 3 - 2
django/dispatch/dispatcher.py

@@ -3,11 +3,12 @@ import threading
 import warnings
 import weakref
 
+from django.utils import six
 from django.utils.deprecation import RemovedInDjango21Warning
 from django.utils.inspect import func_accepts_kwargs
 from django.utils.six.moves import range
 
-if sys.version_info < (3, 4):
+if six.PY2:
     from .weakref_backports import WeakMethod
 else:
     from weakref import WeakMethod
@@ -108,7 +109,7 @@ class Signal(object):
             if hasattr(receiver, '__self__') and hasattr(receiver, '__func__'):
                 ref = WeakMethod
                 receiver_object = receiver.__self__
-            if sys.version_info >= (3, 4):
+            if six.PY3:
                 receiver = ref(receiver)
                 weakref.finalize(receiver_object, self._remove_receiver)
             else:

+ 1 - 1
django/utils/functional.py

@@ -251,7 +251,7 @@ class LazyObject(object):
             self._setup()
         return self._wrapped.__dict__
 
-    # Python 3.3 will call __reduce__ when pickling; this method is needed
+    # Python 3 will call __reduce__ when pickling; this method is needed
     # to serialize and deserialize correctly.
     @classmethod
     def __newobj__(cls, *args):

+ 9 - 24
django/utils/glob.py

@@ -7,30 +7,15 @@ from django.utils import six
 
 # backport of Python 3.4's glob.escape
 
-try:
+if six.PY3:
     from glob import escape as glob_escape
-except ImportError:
+else:
     _magic_check = re.compile('([*?[])')
 
-    if six.PY3:
-        _magic_check_bytes = re.compile(b'([*?[])')
-
-        def glob_escape(pathname):
-            """
-            Escape all special characters.
-            """
-            drive, pathname = os.path.splitdrive(pathname)
-            if isinstance(pathname, bytes):
-                pathname = _magic_check_bytes.sub(br'[\1]', pathname)
-            else:
-                pathname = _magic_check.sub(r'[\1]', pathname)
-            return drive + pathname
-
-    else:
-        def glob_escape(pathname):
-            """
-            Escape all special characters.
-            """
-            drive, pathname = os.path.splitdrive(pathname)
-            pathname = _magic_check.sub(r'[\1]', pathname)
-            return drive + pathname
+    def glob_escape(pathname):
+        """
+        Escape all special characters.
+        """
+        drive, pathname = os.path.splitdrive(pathname)
+        pathname = _magic_check.sub(r'[\1]', pathname)
+        return drive + pathname

+ 2 - 1
django/utils/html_parser.py

@@ -1,6 +1,7 @@
 import re
 import sys
 
+from django.utils import six
 from django.utils.six.moves import html_parser as _html_parser
 
 current_version = sys.version_info
@@ -15,7 +16,7 @@ except AttributeError:
         pass
 
 if not use_workaround:
-    if current_version >= (3, 4):
+    if six.PY3:
         class HTMLParser(_html_parser.HTMLParser):
             """Explicitly set convert_charrefs to be False.
 

+ 2 - 5
django/utils/module_loading.py

@@ -63,11 +63,8 @@ def autodiscover_modules(*args, **kwargs):
                     raise
 
 
-if sys.version_info[:2] >= (3, 3):
-    if sys.version_info[:2] >= (3, 4):
-        from importlib.util import find_spec as importlib_find
-    else:
-        from importlib import find_loader as importlib_find
+if six.PY3:
+    from importlib.util import find_spec as importlib_find
 
     def module_has_submodule(package, module_name):
         """See if 'module' is in 'package'."""

+ 10 - 4
docs/faq/install.txt

@@ -16,9 +16,9 @@ How do I get started?
 What are Django's prerequisites?
 --------------------------------
 
-Django requires Python, specifically Python 2.7 or 3.3 and above. Other Python
-libraries may be required for some uses, but you'll receive an error about it
-as they're needed.
+Django requires Python. See the table in the next question for the versions of
+Python that work with each version of Django. Other Python libraries may be
+required for some uses, but you'll receive an error about it as they're needed.
 
 For a development environment -- if you just want to experiment with Django --
 you don't need to have a separate Web server installed; Django comes with its
@@ -47,13 +47,19 @@ Django version Python versions
 ============== ===============
 1.4            2.5, 2.6, 2.7
 **1.7, 1.8**   **2.7** and **3.2, 3.3, 3.4**
-1.9            2.7, 3.3, 3.4, 3.5
+1.9            2.7, 3.4, 3.5
 ============== ===============
 
 For each version of Python, only the latest micro release (A.B.C) is officially
 supported. You can find the latest micro version for each series on the `Python
 download page <https://www.python.org/downloads/>`_.
 
+Typically, we will support a Python version up to and including the first
+Django LTS release that will receive security updates until after security
+support for that version of Python ends. For example, Python 3.3 security
+support ends September 2017 and Django 1.8 LTS security support ends April
+2018. Therefore Django 1.8 is the last version to support Python 3.3.
+
 What Python version should I use with Django?
 ---------------------------------------------
 

+ 2 - 2
docs/internals/contributing/writing-code/unit-tests.txt

@@ -21,8 +21,8 @@ Running the unit tests
 Quickstart
 ~~~~~~~~~~
 
-If you are on Python < 3.3, you'll first need to install a backport of the
-``unittest.mock`` module that's available in Python 3.3+. See
+If you are on Python 2, you'll first need to install a backport of the
+``unittest.mock`` module that's available in Python 3. See
 :ref:`running-unit-tests-dependencies` for details on installing `mock`_ and
 the other optional test dependencies.
 

+ 3 - 3
docs/intro/install.txt

@@ -9,9 +9,9 @@ that'll work while you walk through the introduction.
 Install Python
 --------------
 
-Being a Python Web framework, Django requires Python. It works with Python 2.7
-and Python 3.3+. All these versions of Python include a lightweight database called
-SQLite_ so you won't need to set up a database just yet.
+Being a Python Web framework, Django requires Python. See
+:ref:`faq-python-version-support` for details. Python includes a lightweight
+database called SQLite_ so you won't need to set up a database just yet.
 
 .. _sqlite: http://sqlite.org/
 

+ 1 - 1
docs/intro/tutorial01.txt

@@ -22,7 +22,7 @@ tell Django is installed and which version by running the following command:
 If Django is installed, you should see the version of your installation. If it
 isn't, you'll get an error telling "No module named django".
 
-This tutorial is written for Django |version| and Python 3.3 or later. If the
+This tutorial is written for Django |version| and Python 3.4 or later. If the
 Django version doesn't match, you can refer to the tutorial for your version
 of Django by using the version switcher at the bottom right corner of this
 page, or update Django to the newest version. If you are still using Python

+ 1 - 1
docs/releases/1.9.txt

@@ -20,7 +20,7 @@ Python compatibility
 
 Like Django 1.8, Django 1.9 requires Python 2.7 or above, though we
 **highly recommend** the latest minor release. We've dropped support for
-Python 3.2 and added support for Python 3.5.
+Python 3.2 and 3.3, and added support for Python 3.5.
 
 What's new in Django 1.9
 ========================

+ 1 - 4
tests/apps/tests.py

@@ -1,7 +1,6 @@
 from __future__ import unicode_literals
 
 import os
-import sys
 import warnings
 from unittest import skipUnless
 
@@ -367,9 +366,7 @@ class AppConfigTests(SimpleTestCase):
             AppConfig('label', Stub(__path__=['a', 'b']))
 
 
-@skipUnless(
-    sys.version_info > (3, 3, 0),
-    "Namespace packages sans __init__.py were added in Python 3.3")
+@skipUnless(six.PY3, "Namespace packages sans __init__.py were added in Python 3.3")
 class NamespacePackageAppTests(SimpleTestCase):
     # We need nsapp to be top-level so our multiple-paths tests can add another
     # location for it (if its inside a normal package with an __init__.py that

+ 1 - 1
tests/auth_tests/test_hashers.py

@@ -353,7 +353,7 @@ class TestUtilsHashPass(SimpleTestCase):
     def test_load_library_importerror(self):
         PlainHasher = type(str('PlainHasher'), (BasePasswordHasher,),
                            {'algorithm': 'plain', 'library': 'plain'})
-        # Python 3.3 adds quotes around module name
+        # Python 3 adds quotes around module name
         with six.assertRaisesRegex(self, ValueError,
                 "Couldn't load 'PlainHasher' algorithm library: No module named '?plain'?"):
             PlainHasher()._load_library()

+ 1 - 1
tests/migrations/test_commands.py

@@ -843,7 +843,7 @@ class MakeMigrationsTests(MigrationTestBase):
             content = cmd("0001", migration_name_0001)
             self.assertIn("dependencies=[\n]", content)
 
-            # Python 3.3+ importlib caches os.listdir() on some platforms like
+            # Python 3 importlib caches os.listdir() on some platforms like
             # Mac OS X (#23850).
             if hasattr(importlib, 'invalidate_caches'):
                 importlib.invalidate_caches()

+ 3 - 3
tests/project_template/test_settings.py

@@ -1,11 +1,11 @@
-import sys
 import unittest
 
 from django.test import TestCase
+from django.utils import six
 
 
-@unittest.skipIf(sys.version_info < (3, 3),
-    'Python < 3.3 cannot import the project template because '
+@unittest.skipIf(six.PY2,
+    'Python 2 cannot import the project template because '
     'django/conf/project_template doesn\'t have an __init__.py file.')
 class TestStartProjectSettings(TestCase):