summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/apps/config.py2
-rw-r--r--django/core/mail/message.py9
-rw-r--r--django/db/backends/sqlite3/features.py5
-rw-r--r--django/dispatch/dispatcher.py5
-rw-r--r--django/utils/functional.py2
-rw-r--r--django/utils/glob.py33
-rw-r--r--django/utils/html_parser.py3
-rw-r--r--django/utils/module_loading.py7
-rw-r--r--docs/faq/install.txt14
-rw-r--r--docs/internals/contributing/writing-code/unit-tests.txt4
-rw-r--r--docs/intro/install.txt6
-rw-r--r--docs/intro/tutorial01.txt2
-rw-r--r--docs/releases/1.9.txt2
-rw-r--r--tests/apps/tests.py5
-rw-r--r--tests/auth_tests/test_hashers.py2
-rw-r--r--tests/migrations/test_commands.py2
-rw-r--r--tests/project_template/test_settings.py6
17 files changed, 44 insertions, 65 deletions
diff --git a/django/apps/config.py b/django/apps/config.py
index 76b3014d9d..98070e62c8 100644
--- a/django/apps/config.py
+++ b/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:
diff --git a/django/core/mail/message.py b/django/core/mail/message.py
index 70a7fda1d4..e8d209c9da 100644
--- a/django/core/mail/message.py
+++ b/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
diff --git a/django/db/backends/sqlite3/features.py b/django/db/backends/sqlite3/features.py
index ee86469177..5697b8b7eb 100644
--- a/django/db/backends/sqlite3/features.py
+++ b/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)
)
diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py
index b2d774bda6..73213afe94 100644
--- a/django/dispatch/dispatcher.py
+++ b/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:
diff --git a/django/utils/functional.py b/django/utils/functional.py
index bade67de46..c0d19093fc 100644
--- a/django/utils/functional.py
+++ b/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):
diff --git a/django/utils/glob.py b/django/utils/glob.py
index a3138b09dc..d3f9e08138 100644
--- a/django/utils/glob.py
+++ b/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
diff --git a/django/utils/html_parser.py b/django/utils/html_parser.py
index e7f7c11571..a69f914921 100644
--- a/django/utils/html_parser.py
+++ b/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.
diff --git a/django/utils/module_loading.py b/django/utils/module_loading.py
index c42d208178..4a2c500321 100644
--- a/django/utils/module_loading.py
+++ b/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'."""
diff --git a/docs/faq/install.txt b/docs/faq/install.txt
index 05906b2a18..38b01a4d6b 100644
--- a/docs/faq/install.txt
+++ b/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?
---------------------------------------------
diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt
index 694bec7845..e1797c8e3b 100644
--- a/docs/internals/contributing/writing-code/unit-tests.txt
+++ b/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.
diff --git a/docs/intro/install.txt b/docs/intro/install.txt
index ffdad3c4c2..b4f250afc9 100644
--- a/docs/intro/install.txt
+++ b/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/
diff --git a/docs/intro/tutorial01.txt b/docs/intro/tutorial01.txt
index 6db12d118b..ca96ae54df 100644
--- a/docs/intro/tutorial01.txt
+++ b/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
diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt
index 2cd2ad018a..4b7ef5184a 100644
--- a/docs/releases/1.9.txt
+++ b/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
========================
diff --git a/tests/apps/tests.py b/tests/apps/tests.py
index 2837e78aff..c199fa156d 100644
--- a/tests/apps/tests.py
+++ b/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
diff --git a/tests/auth_tests/test_hashers.py b/tests/auth_tests/test_hashers.py
index 993010b2f4..58fbf2a0c7 100644
--- a/tests/auth_tests/test_hashers.py
+++ b/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()
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py
index 3077dd9e61..58344e50ce 100644
--- a/tests/migrations/test_commands.py
+++ b/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()
diff --git a/tests/project_template/test_settings.py b/tests/project_template/test_settings.py
index 8998a844c7..ac115f7dc2 100644
--- a/tests/project_template/test_settings.py
+++ b/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):