summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/apps/config.py4
-rw-r--r--django/contrib/auth/hashers.py3
-rw-r--r--django/contrib/auth/views.py4
-rw-r--r--django/core/mail/message.py4
-rw-r--r--django/core/management/commands/shell.py2
-rw-r--r--django/db/backends/oracle/base.py3
-rw-r--r--django/db/migrations/serializer.py22
-rw-r--r--django/test/runner.py3
-rw-r--r--docs/internals/howto-release-django.txt2
-rw-r--r--docs/ref/contrib/gis/install/geodjango_setup.bat8
-rw-r--r--docs/ref/contrib/gis/install/index.txt11
-rw-r--r--setup.cfg3
-rw-r--r--setup.py2
-rw-r--r--tests/README.rst2
-rw-r--r--tests/auth_tests/test_hashers.py1
-rw-r--r--tests/cache/tests.py4
-rw-r--r--tests/i18n/test_extraction.py41
-rw-r--r--tests/mail/tests.py5
-rw-r--r--tests/migrations/test_commands.py8
-rw-r--r--tests/migrations/test_writer.py25
-rw-r--r--tests/test_client/test_conditional_content_removal.py11
-rw-r--r--tox.ini9
22 files changed, 62 insertions, 115 deletions
diff --git a/django/apps/config.py b/django/apps/config.py
index 1bc684b3ca..4845557051 100644
--- a/django/apps/config.py
+++ b/django/apps/config.py
@@ -57,8 +57,8 @@ class AppConfig:
"""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's _NamespacePath does not
- # support indexing.
+ # Convert paths to list because Python's _NamespacePath doesn't support
+ # indexing.
paths = list(getattr(module, '__path__', []))
if len(paths) != 1:
filename = getattr(module, '__file__', None)
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
index c52f31db59..49b4fa5b14 100644
--- a/django/contrib/auth/hashers.py
+++ b/django/contrib/auth/hashers.py
@@ -419,8 +419,7 @@ class BCryptSHA256PasswordHasher(BasePasswordHasher):
# Hash the password prior to using bcrypt to prevent password
# truncation as described in #20138.
if self.digest is not None:
- # Use binascii.hexlify() because a hex encoded bytestring is
- # Unicode on Python 3.
+ # Use binascii.hexlify() because a hex encoded bytestring is str.
password = binascii.hexlify(self.digest(force_bytes(password)).digest())
else:
password = force_bytes(password)
diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py
index 6208b5fe41..c0e102234d 100644
--- a/django/contrib/auth/views.py
+++ b/django/contrib/auth/views.py
@@ -298,7 +298,7 @@ def password_reset_confirm(request, uidb64=None, token=None,
else:
post_reset_redirect = resolve_url(post_reset_redirect)
try:
- # urlsafe_base64_decode() decodes to bytestring on Python 3
+ # urlsafe_base64_decode() decodes to bytestring
uid = force_text(urlsafe_base64_decode(uidb64))
user = UserModel._default_manager.get(pk=uid)
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
@@ -442,7 +442,7 @@ class PasswordResetConfirmView(PasswordContextMixin, FormView):
def get_user(self, uidb64):
try:
- # urlsafe_base64_decode() decodes to bytestring on Python 3
+ # urlsafe_base64_decode() decodes to bytestring
uid = force_text(urlsafe_base64_decode(uidb64))
user = UserModel._default_manager.get(pk=uid)
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
diff --git a/django/core/mail/message.py b/django/core/mail/message.py
index f4f3eb1352..ae2e017b6e 100644
--- a/django/core/mail/message.py
+++ b/django/core/mail/message.py
@@ -324,8 +324,8 @@ class EmailMessage:
try:
content = content.decode('utf-8')
except UnicodeDecodeError:
- # If mimetype suggests the file is text but it's actually
- # binary, read() will raise a UnicodeDecodeError on Python 3.
+ # If mimetype suggests the file is text but it's
+ # actually binary, read() raises a UnicodeDecodeError.
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
self.attachments.append((filename, content, mimetype))
diff --git a/django/core/management/commands/shell.py b/django/core/management/commands/shell.py
index ce4d9daa7e..4b91c1b977 100644
--- a/django/core/management/commands/shell.py
+++ b/django/core/management/commands/shell.py
@@ -53,7 +53,7 @@ class Command(BaseCommand):
import rlcompleter
readline.set_completer(rlcompleter.Completer(imported_objects).complete)
# Enable tab completion on systems using libedit (e.g. Mac OSX).
- # These lines are copied from Lib/site.py on Python 3.4.
+ # These lines are copied from Python's Lib/site.py.
readline_doc = getattr(readline, '__doc__', '')
if readline_doc is not None and 'libedit' in readline_doc:
readline.parse_and_bind("bind ^I rl_complete")
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index 0cc21b639b..d19f189358 100644
--- a/django/db/backends/oracle/base.py
+++ b/django/db/backends/oracle/base.py
@@ -322,8 +322,7 @@ class OracleParam:
param = Oracle_datetime.from_datetime(param)
string_size = 0
- # Oracle doesn't recognize True and False correctly in Python 3.
- # The conversion done below works both in 2 and 3.
+ # Oracle doesn't recognize True and False correctly.
if param is True:
param = 1
elif param is False:
diff --git a/django/db/migrations/serializer.py b/django/db/migrations/serializer.py
index fac8e4c189..f56b505381 100644
--- a/django/db/migrations/serializer.py
+++ b/django/db/migrations/serializer.py
@@ -8,7 +8,6 @@ import math
import re
import types
import uuid
-from importlib import import_module
from django.db import models
from django.db.migrations.operations.base import Operation
@@ -155,20 +154,15 @@ class FunctionTypeSerializer(BaseSerializer):
raise ValueError("Cannot serialize function: lambda")
if self.value.__module__ is None:
raise ValueError("Cannot serialize function %r: No module" % self.value)
- # Python 3 is a lot easier, and only uses this branch if it's not local.
- if getattr(self.value, "__qualname__", None) and getattr(self.value, "__module__", None):
- if "<" not in self.value.__qualname__: # Qualname can include <locals>
- return "%s.%s" % \
- (self.value.__module__, self.value.__qualname__), {"import %s" % self.value.__module__}
- # Fallback version
+
module_name = self.value.__module__
- # Make sure it's actually there
- module = import_module(module_name)
- if not hasattr(module, self.value.__name__):
- raise ValueError(
- "Could not find function %s in %s.\n" % (self.value.__name__, module_name)
- )
- return "%s.%s" % (module_name, self.value.__name__), {"import %s" % module_name}
+
+ if '<' not in self.value.__qualname__: # Qualname can include <locals>
+ return '%s.%s' % (module_name, self.value.__qualname__), {'import %s' % self.value.__module__}
+
+ raise ValueError(
+ 'Could not find function %s in %s.\n' % (self.value.__name__, module_name)
+ )
class FunctoolsPartialSerializer(BaseSerializer):
diff --git a/django/test/runner.py b/django/test/runner.py
index 38578e7e0c..cb1893c56a 100644
--- a/django/test/runner.py
+++ b/django/test/runner.py
@@ -258,8 +258,7 @@ def default_test_processes():
"""
# The current implementation of the parallel test runner requires
# multiprocessing to start subprocesses with fork().
- # On Python 3.4+: if multiprocessing.get_start_method() != 'fork':
- if not hasattr(os, 'fork'):
+ if multiprocessing.get_start_method() != 'fork':
return 1
try:
return int(os.environ['DJANGO_TEST_PROCESSES'])
diff --git a/docs/internals/howto-release-django.txt b/docs/internals/howto-release-django.txt
index 6a91069abc..8316beea75 100644
--- a/docs/internals/howto-release-django.txt
+++ b/docs/internals/howto-release-django.txt
@@ -303,7 +303,7 @@ Now you're ready to actually put the release out there. To do this:
$ pip install https://www.djangoproject.com/m/releases/$MAJOR_VERSION/Django-$RELEASE_VERSION.tar.gz
$ deactivate
$ mktmpenv
- $ pip install https://www.djangoproject.com/m/releases/$MAJOR_VERSION/Django-$RELEASE_VERSION-py2.py3-none-any.whl
+ $ pip install https://www.djangoproject.com/m/releases/$MAJOR_VERSION/Django-$RELEASE_VERSION-py3-none-any.whl
$ deactivate
This just tests that the tarballs are available (i.e. redirects are up) and
diff --git a/docs/ref/contrib/gis/install/geodjango_setup.bat b/docs/ref/contrib/gis/install/geodjango_setup.bat
deleted file mode 100644
index b3e6cc6822..0000000000
--- a/docs/ref/contrib/gis/install/geodjango_setup.bat
+++ /dev/null
@@ -1,8 +0,0 @@
-set OSGEO4W_ROOT=C:\OSGeo4W
-set PYTHON_ROOT=C:\Python27
-set GDAL_DATA=%OSGEO4W_ROOT%\share\gdal
-set PROJ_LIB=%OSGEO4W_ROOT%\share\proj
-set PATH=%PATH%;%PYTHON_ROOT%;%OSGEO4W_ROOT%\bin
-reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /f /d "%PATH%"
-reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v GDAL_DATA /t REG_EXPAND_SZ /f /d "%GDAL_DATA%"
-reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v PROJ_LIB /t REG_EXPAND_SZ /f /d "%PROJ_LIB%"
diff --git a/docs/ref/contrib/gis/install/index.txt b/docs/ref/contrib/gis/install/index.txt
index 06990943ef..53cee2920a 100644
--- a/docs/ref/contrib/gis/install/index.txt
+++ b/docs/ref/contrib/gis/install/index.txt
@@ -463,7 +463,7 @@ executable with ``cmd.exe``, will set this up:
.. code-block:: bat
set OSGEO4W_ROOT=C:\OSGeo4W
- set PYTHON_ROOT=C:\Python27
+ set PYTHON_ROOT=C:\Python3X
set GDAL_DATA=%OSGEO4W_ROOT%\share\gdal
set PROJ_LIB=%OSGEO4W_ROOT%\share\proj
set PATH=%PATH%;%PYTHON_ROOT%;%OSGEO4W_ROOT%\bin
@@ -471,15 +471,12 @@ executable with ``cmd.exe``, will set this up:
reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v GDAL_DATA /t REG_EXPAND_SZ /f /d "%GDAL_DATA%"
reg ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v PROJ_LIB /t REG_EXPAND_SZ /f /d "%PROJ_LIB%"
-For your convenience, these commands are available in the executable batch
-script, :download:`geodjango_setup.bat`.
-
.. note::
Administrator privileges are required to execute these commands.
- To do this, right-click on :download:`geodjango_setup.bat` and select
- :menuselection:`Run as administrator`. You need to log out and log back in again
- for the settings to take effect.
+ To do this, create a ``bat`` script with the commands, right-click it, and
+ select :menuselection:`Run as administrator`. You need to log out and log
+ back in again for the settings to take effect.
.. note::
diff --git a/setup.cfg b/setup.cfg
index d84a4aefc7..5b37a54c11 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -18,6 +18,3 @@ not_skip = __init__.py
[metadata]
license-file = LICENSE
-
-[wheel]
-universal = 1
diff --git a/setup.py b/setup.py
index d8dfa58a17..e9cfa4f093 100644
--- a/setup.py
+++ b/setup.py
@@ -61,8 +61,6 @@ setup(
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
diff --git a/tests/README.rst b/tests/README.rst
index 7d4ddb513a..7f64afe6fc 100644
--- a/tests/README.rst
+++ b/tests/README.rst
@@ -3,7 +3,7 @@ install some requirements and run the tests::
$ cd tests
$ pip install -e ..
- $ pip install -r requirements/py3.txt # or py2.txt
+ $ pip install -r requirements/py3.txt
$ ./runtests.py
For more information about the test suite, see
diff --git a/tests/auth_tests/test_hashers.py b/tests/auth_tests/test_hashers.py
index 4e7bae280d..aec7021cab 100644
--- a/tests/auth_tests/test_hashers.py
+++ b/tests/auth_tests/test_hashers.py
@@ -434,7 +434,6 @@ class TestUtilsHashPass(SimpleTestCase):
def test_load_library_importerror(self):
PlainHasher = type('PlainHasher', (BasePasswordHasher,), {'algorithm': 'plain', 'library': 'plain'})
- # Python 3 adds quotes around module name
msg = "Couldn't load 'PlainHasher' algorithm library: No module named 'plain'"
with self.assertRaisesMessage(ValueError, msg):
PlainHasher()._load_library()
diff --git a/tests/cache/tests.py b/tests/cache/tests.py
index d519080c9a..6b462f29c2 100644
--- a/tests/cache/tests.py
+++ b/tests/cache/tests.py
@@ -1912,10 +1912,6 @@ class CacheI18nTest(TestCase):
get_cache_data = FetchFromCacheMiddleware().process_request(request)
self.assertIsNone(get_cache_data)
- # This test passes on Python < 3.3 even without the corresponding code
- # in UpdateCacheMiddleware, because pickling a StreamingHttpResponse
- # fails (http://bugs.python.org/issue14288). LocMemCache silently
- # swallows the exception and doesn't store the response in cache.
content = ['Check for cache with streaming content.']
response = StreamingHttpResponse(content)
UpdateCacheMiddleware().process_response(request, response)
diff --git a/tests/i18n/test_extraction.py b/tests/i18n/test_extraction.py
index 69d0236fad..c0acd3f9f0 100644
--- a/tests/i18n/test_extraction.py
+++ b/tests/i18n/test_extraction.py
@@ -16,6 +16,7 @@ from django.core.management.commands.makemessages import \
from django.core.management.utils import find_command
from django.test import SimpleTestCase, override_settings
from django.test.utils import captured_stderr, captured_stdout
+from django.utils._os import symlinks_supported
from django.utils.translation import TranslatorCommentWarning
from .utils import POFileAssertionMixin, RunInTmpDirMixin, copytree
@@ -382,7 +383,10 @@ class BasicExtractorTests(ExtractorTests):
cmd.gettext_version
def test_po_file_encoding_when_updating(self):
- """Update of PO file doesn't corrupt it with non-UTF-8 encoding on Python3+Windows (#23271)"""
+ """
+ Update of PO file doesn't corrupt it with non-UTF-8 encoding on Windows
+ (#23271).
+ """
BR_PO_BASE = 'locale/pt_BR/LC_MESSAGES/django'
shutil.copyfile(BR_PO_BASE + '.pristine', BR_PO_BASE + '.po')
management.call_command('makemessages', locale=['pt_BR'], verbosity=0)
@@ -472,29 +476,20 @@ class SymlinkExtractorTests(ExtractorTests):
self.symlinked_dir = os.path.join(self.test_dir, 'templates_symlinked')
def test_symlink(self):
- # On Python < 3.2 os.symlink() exists only on Unix
- if hasattr(os, 'symlink'):
- if os.path.exists(self.symlinked_dir):
- self.assertTrue(os.path.islink(self.symlinked_dir))
- else:
- # On Python >= 3.2) os.symlink() exists always but then can
- # fail at runtime when user hasn't the needed permissions on
- # Windows versions that support symbolink links (>= 6/Vista).
- # See Python issue 9333 (http://bugs.python.org/issue9333).
- # Skip the test in that case
- try:
- os.symlink(os.path.join(self.test_dir, 'templates'), self.symlinked_dir)
- except (OSError, NotImplementedError):
- self.skipTest("os.symlink() is available on this OS but can't be used by this user.")
- os.chdir(self.test_dir)
- management.call_command('makemessages', locale=[LOCALE], verbosity=0, symlinks=True)
- self.assertTrue(os.path.exists(self.PO_FILE))
- with open(self.PO_FILE, 'r') as fp:
- po_contents = fp.read()
- self.assertMsgId('This literal should be included.', po_contents)
- self.assertLocationCommentPresent(self.PO_FILE, None, 'templates_symlinked', 'test.html')
+ if os.path.exists(self.symlinked_dir):
+ self.assertTrue(os.path.islink(self.symlinked_dir))
else:
- self.skipTest("os.symlink() not available on this OS + Python version combination.")
+ if symlinks_supported():
+ os.symlink(os.path.join(self.test_dir, 'templates'), self.symlinked_dir)
+ else:
+ self.skipTest("os.symlink() not available on this OS + Python version combination.")
+ os.chdir(self.test_dir)
+ management.call_command('makemessages', locale=[LOCALE], verbosity=0, symlinks=True)
+ self.assertTrue(os.path.exists(self.PO_FILE))
+ with open(self.PO_FILE, 'r') as fp:
+ po_contents = fp.read()
+ self.assertMsgId('This literal should be included.', po_contents)
+ self.assertLocationCommentPresent(self.PO_FILE, None, 'templates_symlinked', 'test.html')
class CopyPluralFormsExtractorTests(ExtractorTests):
diff --git a/tests/mail/tests.py b/tests/mail/tests.py
index 60758a637b..a902e5435c 100644
--- a/tests/mail/tests.py
+++ b/tests/mail/tests.py
@@ -192,7 +192,6 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
'Content', 'from@example.com', ['to@example.com']
)
message = email.message()
- # Note that in Python 3, maximum line length has increased from 76 to 78
self.assertEqual(
message['Subject'].encode(),
b'Long subject lines that get wrapped should contain a space continuation\n'
@@ -1157,8 +1156,8 @@ class FakeSMTPServer(smtpd.SMTPServer, threading.Thread):
if mailfrom != maddr:
# According to the spec, mailfrom does not necessarily match the
- # From header - on Python 3 this is the case where the local part
- # isn't encoded, so try to correct that.
+ # From header - this is the case where the local part isn't
+ # encoded, so try to correct that.
lp, domain = mailfrom.split('@', 1)
lp = Header(lp, 'utf-8').encode()
mailfrom = '@'.join([lp, domain])
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py
index d5d31b7c7c..af83eb0a6a 100644
--- a/tests/migrations/test_commands.py
+++ b/tests/migrations/test_commands.py
@@ -672,8 +672,8 @@ class MakeMigrationsTests(MigrationTestBase):
module = 'migrations.test_migrations_order'
with self.temporary_migration_module(module=module) as migration_dir:
if hasattr(importlib, 'invalidate_caches'):
- # Python 3 importlib caches os.listdir() on some platforms like
- # Mac OS X (#23850).
+ # importlib caches os.listdir() on some platforms like Mac OS X
+ # (#23850).
importlib.invalidate_caches()
call_command('makemigrations', 'migrations', '--empty', '-n', 'a', '-v', '0')
self.assertTrue(os.path.exists(os.path.join(migration_dir, '0002_a.py')))
@@ -1202,8 +1202,8 @@ class MakeMigrationsTests(MigrationTestBase):
content = cmd("0001", migration_name_0001)
self.assertIn("dependencies=[\n]", content)
- # Python 3 importlib caches os.listdir() on some platforms like
- # Mac OS X (#23850).
+ # importlib caches os.listdir() on some platforms like Mac OS X
+ # (#23850).
if hasattr(importlib, 'invalidate_caches'):
importlib.invalidate_caches()
diff --git a/tests/migrations/test_writer.py b/tests/migrations/test_writer.py
index 1de0fec0aa..32751d8923 100644
--- a/tests/migrations/test_writer.py
+++ b/tests/migrations/test_writer.py
@@ -40,6 +40,12 @@ class Money(decimal.Decimal):
)
+class TestModel1(object):
+ def upload_to(self):
+ return '/somewhere/dynamic/'
+ thing = models.FileField(upload_to=upload_to)
+
+
class OperationWriterTests(SimpleTestCase):
def test_empty_signature(self):
@@ -472,21 +478,12 @@ class WriterTests(SimpleTestCase):
self.assertEqual(string, 'range')
self.assertEqual(imports, set())
- def test_serialize_local_function_reference(self):
- """
- Neither py2 or py3 can serialize a reference in a local scope.
- """
- class TestModel2:
- def upload_to(self):
- return "somewhere dynamic"
- thing = models.FileField(upload_to=upload_to)
- with self.assertRaises(ValueError):
- self.serialize_round_trip(TestModel2.thing)
+ def test_serialize_unbound_method_reference(self):
+ """An unbound method used within a class body can be serialized."""
+ self.serialize_round_trip(TestModel1.thing)
- def test_serialize_local_function_reference_message(self):
- """
- Make sure user is seeing which module/function is the issue
- """
+ def test_serialize_local_function_reference(self):
+ """A reference in a local scope can't be serialized."""
class TestModel2:
def upload_to(self):
return "somewhere dynamic"
diff --git a/tests/test_client/test_conditional_content_removal.py b/tests/test_client/test_conditional_content_removal.py
index 72bf7f238b..bd26b8fb52 100644
--- a/tests/test_client/test_conditional_content_removal.py
+++ b/tests/test_client/test_conditional_content_removal.py
@@ -1,19 +1,10 @@
import gzip
-import io
from django.http import HttpRequest, HttpResponse, StreamingHttpResponse
from django.test import SimpleTestCase
from django.test.client import conditional_content_removal
-# based on Python 3.3's gzip.compress
-def gzip_compress(data):
- buf = io.BytesIO()
- with gzip.GzipFile(fileobj=buf, mode='wb', compresslevel=0) as f:
- f.write(data)
- return buf.getvalue()
-
-
class ConditionalContentTests(SimpleTestCase):
def test_conditional_content_removal(self):
@@ -43,7 +34,7 @@ class ConditionalContentTests(SimpleTestCase):
self.assertEqual(b''.join(res), b'')
# Issue #20472
- abc = gzip_compress(b'abc')
+ abc = gzip.compress(b'abc')
res = HttpResponse(abc, status=304)
res['Content-Encoding'] = 'gzip'
conditional_content_removal(req, res)
diff --git a/tox.ini b/tox.ini
index e9892a75a4..b9ed6c9db9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -11,10 +11,7 @@ envlist =
docs
isort
-# Add environments to use default python2 and python3 installations
-[testenv:py2]
-basepython = python2
-
+# Add environment to use the default python3 installation
[testenv:py3]
basepython = python3
@@ -24,7 +21,6 @@ passenv = DJANGO_SETTINGS_MODULE PYTHONPATH HOME DISPLAY
setenv =
PYTHONDONTWRITEBYTECODE=1
deps =
- py{2,27}: -rtests/requirements/py2.txt
py{3,34,35,36}: -rtests/requirements/py3.txt
postgres: -rtests/requirements/postgres.txt
mysql: -rtests/requirements/mysql.txt
@@ -41,8 +37,7 @@ changedir = {toxinidir}
commands = flake8 .
[testenv:docs]
-# On OS X, as of pyenchant 1.6.6, the docs build only works under Python 2.
-basepython = python2
+basepython = python3
usedevelop = false
whitelist_externals =
make