Fixed #20746 -- Removed Python 2.6 specific code/docs
This commit is contained in:
parent
0d81fd0e5f
commit
2456ffa42c
|
@ -3,7 +3,6 @@ from __future__ import unicode_literals
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
from email import charset as Charset, encoders as Encoders
|
from email import charset as Charset, encoders as Encoders
|
||||||
from email.generator import Generator
|
from email.generator import Generator
|
||||||
|
@ -139,9 +138,6 @@ class SafeMIMEText(MIMEText):
|
||||||
"""
|
"""
|
||||||
fp = six.StringIO()
|
fp = six.StringIO()
|
||||||
g = Generator(fp, mangle_from_ = False)
|
g = Generator(fp, mangle_from_ = False)
|
||||||
if sys.version_info < (2, 6, 6) and isinstance(self._payload, six.text_type):
|
|
||||||
# Workaround for http://bugs.python.org/issue1368247
|
|
||||||
self._payload = self._payload.encode(self._charset.output_charset)
|
|
||||||
g.flatten(self, unixfrom=unixfrom)
|
g.flatten(self, unixfrom=unixfrom)
|
||||||
return fp.getvalue()
|
return fp.getvalue()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import collections
|
||||||
import copy
|
import copy
|
||||||
import datetime
|
import datetime
|
||||||
import decimal
|
import decimal
|
||||||
|
@ -17,7 +18,6 @@ from django.core import exceptions, validators
|
||||||
from django.utils.datastructures import DictWrapper
|
from django.utils.datastructures import DictWrapper
|
||||||
from django.utils.dateparse import parse_date, parse_datetime, parse_time
|
from django.utils.dateparse import parse_date, parse_datetime, parse_time
|
||||||
from django.utils.functional import curry, total_ordering
|
from django.utils.functional import curry, total_ordering
|
||||||
from django.utils.itercompat import is_iterator
|
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -585,7 +585,7 @@ class Field(object):
|
||||||
return bound_field_class(self, fieldmapping, original)
|
return bound_field_class(self, fieldmapping, original)
|
||||||
|
|
||||||
def _get_choices(self):
|
def _get_choices(self):
|
||||||
if is_iterator(self._choices):
|
if isinstance(self._choices, collections.Iterator):
|
||||||
choices, self._choices = tee(self._choices)
|
choices, self._choices = tee(self._choices)
|
||||||
return choices
|
return choices
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -4,6 +4,7 @@ Code to manage the creation and SQL rendering of 'where' constraints.
|
||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import collections
|
||||||
import datetime
|
import datetime
|
||||||
from itertools import repeat
|
from itertools import repeat
|
||||||
|
|
||||||
|
@ -11,7 +12,6 @@ from django.conf import settings
|
||||||
from django.db.models.fields import DateTimeField, Field
|
from django.db.models.fields import DateTimeField, Field
|
||||||
from django.db.models.sql.datastructures import EmptyResultSet, Empty
|
from django.db.models.sql.datastructures import EmptyResultSet, Empty
|
||||||
from django.db.models.sql.aggregates import Aggregate
|
from django.db.models.sql.aggregates import Aggregate
|
||||||
from django.utils.itercompat import is_iterator
|
|
||||||
from django.utils.six.moves import xrange
|
from django.utils.six.moves import xrange
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils import tree
|
from django.utils import tree
|
||||||
|
@ -61,7 +61,7 @@ class WhereNode(tree.Node):
|
||||||
if not isinstance(data, (list, tuple)):
|
if not isinstance(data, (list, tuple)):
|
||||||
return data
|
return data
|
||||||
obj, lookup_type, value = data
|
obj, lookup_type, value = data
|
||||||
if is_iterator(value):
|
if isinstance(value, collections.Iterator):
|
||||||
# Consume any generators immediately, so that we can determine
|
# Consume any generators immediately, so that we can determine
|
||||||
# emptiness and transform any non-empty values correctly.
|
# emptiness and transform any non-empty values correctly.
|
||||||
value = list(value)
|
value = list(value)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import select
|
|
||||||
import socket
|
import socket
|
||||||
import threading
|
import threading
|
||||||
import unittest
|
import unittest
|
||||||
|
@ -924,104 +923,6 @@ class QuietWSGIRequestHandler(WSGIRequestHandler):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info >= (3, 3, 0):
|
|
||||||
_ImprovedEvent = threading.Event
|
|
||||||
elif sys.version_info >= (2, 7, 0):
|
|
||||||
_ImprovedEvent = threading._Event
|
|
||||||
else:
|
|
||||||
class _ImprovedEvent(threading._Event):
|
|
||||||
"""
|
|
||||||
Does the same as `threading.Event` except it overrides the wait() method
|
|
||||||
with some code borrowed from Python 2.7 to return the set state of the
|
|
||||||
event (see: http://hg.python.org/cpython/rev/b5aa8aa78c0f/). This allows
|
|
||||||
to know whether the wait() method exited normally or because of the
|
|
||||||
timeout. This class can be removed when Django supports only Python >= 2.7.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def wait(self, timeout=None):
|
|
||||||
self._Event__cond.acquire()
|
|
||||||
try:
|
|
||||||
if not self._Event__flag:
|
|
||||||
self._Event__cond.wait(timeout)
|
|
||||||
return self._Event__flag
|
|
||||||
finally:
|
|
||||||
self._Event__cond.release()
|
|
||||||
|
|
||||||
|
|
||||||
class StoppableWSGIServer(WSGIServer):
|
|
||||||
"""
|
|
||||||
The code in this class is borrowed from the `SocketServer.BaseServer` class
|
|
||||||
in Python 2.6. The important functionality here is that the server is non-
|
|
||||||
blocking and that it can be shut down at any moment. This is made possible
|
|
||||||
by the server regularly polling the socket and checking if it has been
|
|
||||||
asked to stop.
|
|
||||||
Note for the future: Once Django stops supporting Python 2.6, this class
|
|
||||||
can be removed as `WSGIServer` will have this ability to shutdown on
|
|
||||||
demand and will not require the use of the _ImprovedEvent class whose code
|
|
||||||
is borrowed from Python 2.7.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(StoppableWSGIServer, self).__init__(*args, **kwargs)
|
|
||||||
self.__is_shut_down = _ImprovedEvent()
|
|
||||||
self.__serving = False
|
|
||||||
|
|
||||||
def serve_forever(self, poll_interval=0.5):
|
|
||||||
"""
|
|
||||||
Handle one request at a time until shutdown.
|
|
||||||
|
|
||||||
Polls for shutdown every poll_interval seconds.
|
|
||||||
"""
|
|
||||||
self.__serving = True
|
|
||||||
self.__is_shut_down.clear()
|
|
||||||
while self.__serving:
|
|
||||||
r, w, e = select.select([self], [], [], poll_interval)
|
|
||||||
if r:
|
|
||||||
self._handle_request_noblock()
|
|
||||||
self.__is_shut_down.set()
|
|
||||||
|
|
||||||
def shutdown(self):
|
|
||||||
"""
|
|
||||||
Stops the serve_forever loop.
|
|
||||||
|
|
||||||
Blocks until the loop has finished. This must be called while
|
|
||||||
serve_forever() is running in another thread, or it will
|
|
||||||
deadlock.
|
|
||||||
"""
|
|
||||||
self.__serving = False
|
|
||||||
if not self.__is_shut_down.wait(2):
|
|
||||||
raise RuntimeError(
|
|
||||||
"Failed to shutdown the live test server in 2 seconds. The "
|
|
||||||
"server might be stuck or generating a slow response.")
|
|
||||||
|
|
||||||
def handle_request(self):
|
|
||||||
"""Handle one request, possibly blocking.
|
|
||||||
"""
|
|
||||||
fd_sets = select.select([self], [], [], None)
|
|
||||||
if not fd_sets[0]:
|
|
||||||
return
|
|
||||||
self._handle_request_noblock()
|
|
||||||
|
|
||||||
def _handle_request_noblock(self):
|
|
||||||
"""
|
|
||||||
Handle one request, without blocking.
|
|
||||||
|
|
||||||
I assume that select.select has returned that the socket is
|
|
||||||
readable before this function was called, so there should be
|
|
||||||
no risk of blocking in get_request().
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
request, client_address = self.get_request()
|
|
||||||
except socket.error:
|
|
||||||
return
|
|
||||||
if self.verify_request(request, client_address):
|
|
||||||
try:
|
|
||||||
self.process_request(request, client_address)
|
|
||||||
except Exception:
|
|
||||||
self.handle_error(request, client_address)
|
|
||||||
self.close_request(request)
|
|
||||||
|
|
||||||
|
|
||||||
class _MediaFilesHandler(StaticFilesHandler):
|
class _MediaFilesHandler(StaticFilesHandler):
|
||||||
"""
|
"""
|
||||||
Handler for serving the media files. This is a private class that is
|
Handler for serving the media files. This is a private class that is
|
||||||
|
@ -1071,7 +972,7 @@ class LiveServerThread(threading.Thread):
|
||||||
# one that is free to use for the WSGI server.
|
# one that is free to use for the WSGI server.
|
||||||
for index, port in enumerate(self.possible_ports):
|
for index, port in enumerate(self.possible_ports):
|
||||||
try:
|
try:
|
||||||
self.httpd = StoppableWSGIServer(
|
self.httpd = WSGIServer(
|
||||||
(self.host, port), QuietWSGIRequestHandler)
|
(self.host, port), QuietWSGIRequestHandler)
|
||||||
except WSGIServerException as e:
|
except WSGIServerException as e:
|
||||||
if (index + 1 < len(self.possible_ports) and
|
if (index + 1 < len(self.possible_ports) and
|
||||||
|
|
|
@ -398,9 +398,8 @@ def partition(predicate, values):
|
||||||
if sys.version_info >= (2, 7, 2):
|
if sys.version_info >= (2, 7, 2):
|
||||||
from functools import total_ordering
|
from functools import total_ordering
|
||||||
else:
|
else:
|
||||||
# For Python < 2.7.2. Python 2.6 does not have total_ordering, and
|
# For Python < 2.7.2. total_ordering in versions prior to 2.7.2 is buggy.
|
||||||
# total_ordering in 2.7 versions prior to 2.7.2 is buggy. See
|
# See http://bugs.python.org/issue10042 for details. For these versions use
|
||||||
# http://bugs.python.org/issue10042 for details. For these versions use
|
|
||||||
# code borrowed from Python 2.7.3.
|
# code borrowed from Python 2.7.3.
|
||||||
def total_ordering(cls):
|
def total_ordering(cls):
|
||||||
"""Class decorator that fills in missing ordering methods"""
|
"""Class decorator that fills in missing ordering methods"""
|
||||||
|
|
|
@ -4,9 +4,6 @@ Where possible, we try to use the system-native version and only fall back to
|
||||||
these implementations if necessary.
|
these implementations if necessary.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import collections
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def is_iterable(x):
|
def is_iterable(x):
|
||||||
"A implementation independent way of checking for iterables"
|
"A implementation independent way of checking for iterables"
|
||||||
|
@ -16,14 +13,3 @@ def is_iterable(x):
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def is_iterator(x):
|
|
||||||
"""An implementation independent way of checking for iterators
|
|
||||||
|
|
||||||
Python 2.6 has a different implementation of collections.Iterator which
|
|
||||||
accepts anything with a `next` method. 2.7+ requires and `__iter__` method
|
|
||||||
as well.
|
|
||||||
"""
|
|
||||||
if sys.version_info >= (2, 7):
|
|
||||||
return isinstance(x, collections.Iterator)
|
|
||||||
return isinstance(x, collections.Iterator) and hasattr(x, '__iter__')
|
|
||||||
|
|
|
@ -217,9 +217,9 @@ This setting is required if you're using the :ttag:`ssi` template tag.
|
||||||
Python Options
|
Python Options
|
||||||
==============
|
==============
|
||||||
|
|
||||||
If you're using Python 2.6.8+, it's strongly recommended that you invoke the
|
It's strongly recommended that you invoke the Python process running your
|
||||||
Python process running your Django application using the `-R`_ option or with
|
Django application using the `-R`_ option or with the
|
||||||
the :envvar:`PYTHONHASHSEED` environment variable set to ``random``.
|
:envvar:`PYTHONHASHSEED` environment variable set to ``random``.
|
||||||
|
|
||||||
These options help protect your site from denial-of-service (DoS)
|
These options help protect your site from denial-of-service (DoS)
|
||||||
attacks triggered by carefully crafted inputs. Such an attack can
|
attacks triggered by carefully crafted inputs. Such an attack can
|
||||||
|
|
|
@ -4,13 +4,6 @@ Running Django on Jython
|
||||||
|
|
||||||
.. index:: Jython, Java, JVM
|
.. index:: Jython, Java, JVM
|
||||||
|
|
||||||
.. admonition:: Python 2.6 support
|
|
||||||
|
|
||||||
Django 1.5 has dropped support for Python 2.5. Therefore, you have to use
|
|
||||||
a Jython 2.7 alpha release if you want to use Django 1.5 with Jython.
|
|
||||||
Please use Django 1.4 if you want to keep using Django on a stable Jython
|
|
||||||
version.
|
|
||||||
|
|
||||||
Jython_ is an implementation of Python that runs on the Java platform (JVM).
|
Jython_ is an implementation of Python that runs on the Java platform (JVM).
|
||||||
Django runs cleanly on Jython version 2.5 or later, which means you can deploy
|
Django runs cleanly on Jython version 2.5 or later, which means you can deploy
|
||||||
Django on any Java platform.
|
Django on any Java platform.
|
||||||
|
@ -22,7 +15,7 @@ This document will get you up and running with Django on top of Jython.
|
||||||
Installing Jython
|
Installing Jython
|
||||||
=================
|
=================
|
||||||
|
|
||||||
Django works with Jython versions 2.5b3 and higher. Download Jython at
|
Django works with Jython versions 2.5b3 and higher. Download Jython at
|
||||||
http://www.jython.org/.
|
http://www.jython.org/.
|
||||||
|
|
||||||
Creating a servlet container
|
Creating a servlet container
|
||||||
|
|
|
@ -255,9 +255,7 @@ working. We'll now fix this by installing our new ``django-polls`` package.
|
||||||
installs have a lot of advantages over installing the package system-wide,
|
installs have a lot of advantages over installing the package system-wide,
|
||||||
such as being usable on systems where you don't have administrator access
|
such as being usable on systems where you don't have administrator access
|
||||||
as well as preventing the package from affecting system services and other
|
as well as preventing the package from affecting system services and other
|
||||||
users of the machine. Python 2.6 added support for user libraries, so if
|
users of the machine.
|
||||||
you are using an older version this won't work, but Django 1.5 requires
|
|
||||||
Python 2.6 or newer anyway.
|
|
||||||
|
|
||||||
Note that per-user installations can still affect the behavior of system
|
Note that per-user installations can still affect the behavior of system
|
||||||
tools that run as that user, so ``virtualenv`` is a more robust solution
|
tools that run as that user, so ``virtualenv`` is a more robust solution
|
||||||
|
|
|
@ -14,6 +14,19 @@ deprecation process for some features`_.
|
||||||
.. _`backwards incompatible changes`: `Backwards incompatible changes in 1.7`_
|
.. _`backwards incompatible changes`: `Backwards incompatible changes in 1.7`_
|
||||||
.. _`begun the deprecation process for some features`: `Features deprecated in 1.7`_
|
.. _`begun the deprecation process for some features`: `Features deprecated in 1.7`_
|
||||||
|
|
||||||
|
Python compatibility
|
||||||
|
====================
|
||||||
|
|
||||||
|
Django 1.7 requires Python 2.7 or above, though we **highly recommend**
|
||||||
|
the latest minor release. Support for Python 2.6 has been dropped.
|
||||||
|
|
||||||
|
This change should affect only a small number of Django users, as most
|
||||||
|
operating-system vendors today are shipping Python 2.7 or newer as their default
|
||||||
|
version. If you're still using Python 2.6, however, you'll need to stick to
|
||||||
|
Django 1.6 until you can upgrade your Python version. Per :doc:`our support
|
||||||
|
policy </internals/release-process>`, Django 1.6 will continue to receive
|
||||||
|
security support until the release of Django 1.8.
|
||||||
|
|
||||||
What's new in Django 1.7
|
What's new in Django 1.7
|
||||||
========================
|
========================
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ from admin_scripts.tests import AdminScriptTestCase
|
||||||
|
|
||||||
from .logconfig import MyEmailBackend
|
from .logconfig import MyEmailBackend
|
||||||
|
|
||||||
PYVERS = sys.version_info[:2]
|
|
||||||
|
|
||||||
# logging config prior to using filter with mail_admins
|
# logging config prior to using filter with mail_admins
|
||||||
OLD_LOGGING = {
|
OLD_LOGGING = {
|
||||||
|
@ -87,7 +86,6 @@ class DefaultLoggingTest(TestCase):
|
||||||
self.logger.error("Hey, this is an error.")
|
self.logger.error("Hey, this is an error.")
|
||||||
self.assertEqual(output.getvalue(), 'Hey, this is an error.\n')
|
self.assertEqual(output.getvalue(), 'Hey, this is an error.\n')
|
||||||
|
|
||||||
@skipUnless(PYVERS > (2,6), "warnings captured only in Python >= 2.7")
|
|
||||||
class WarningLoggerTests(TestCase):
|
class WarningLoggerTests(TestCase):
|
||||||
"""
|
"""
|
||||||
Tests that warnings output for DeprecationWarnings is enabled
|
Tests that warnings output for DeprecationWarnings is enabled
|
||||||
|
|
|
@ -2148,13 +2148,6 @@ class ConditionalTests(BaseQuerysetTest):
|
||||||
t4 = Tag.objects.create(name='t4', parent=t3)
|
t4 = Tag.objects.create(name='t4', parent=t3)
|
||||||
t5 = Tag.objects.create(name='t5', parent=t3)
|
t5 = Tag.objects.create(name='t5', parent=t3)
|
||||||
|
|
||||||
|
|
||||||
# In Python 2.6 beta releases, exceptions raised in __len__ are swallowed
|
|
||||||
# (Python issue 1242657), so these cases return an empty list, rather than
|
|
||||||
# raising an exception. Not a lot we can do about that, unfortunately, due to
|
|
||||||
# the way Python handles list() calls internally. Thus, we skip the tests for
|
|
||||||
# Python 2.6.
|
|
||||||
@unittest.skipIf(sys.version_info[:2] == (2, 6), "Python version is 2.6")
|
|
||||||
def test_infinite_loop(self):
|
def test_infinite_loop(self):
|
||||||
# If you're not careful, it's possible to introduce infinite loops via
|
# If you're not careful, it's possible to introduce infinite loops via
|
||||||
# default ordering on foreign keys in a cycle. We detect that.
|
# default ordering on foreign keys in a cycle. We detect that.
|
||||||
|
|
|
@ -99,15 +99,8 @@ class SelectForUpdateTests(TransactionTestCase):
|
||||||
list(Person.objects.all().select_for_update(nowait=True))
|
list(Person.objects.all().select_for_update(nowait=True))
|
||||||
self.assertTrue(self.has_for_update_sql(connection, nowait=True))
|
self.assertTrue(self.has_for_update_sql(connection, nowait=True))
|
||||||
|
|
||||||
# In Python 2.6 beta and some final releases, exceptions raised in __len__
|
|
||||||
# are swallowed (Python issue 1242657), so these cases return an empty
|
|
||||||
# list, rather than raising an exception. Not a lot we can do about that,
|
|
||||||
# unfortunately, due to the way Python handles list() calls internally.
|
|
||||||
# Python 2.6.1 is the "in the wild" version affected by this, so we skip
|
|
||||||
# the test for that version.
|
|
||||||
@requires_threading
|
@requires_threading
|
||||||
@skipUnlessDBFeature('has_select_for_update_nowait')
|
@skipUnlessDBFeature('has_select_for_update_nowait')
|
||||||
@unittest.skipIf(sys.version_info[:3] == (2, 6, 1), "Python version is 2.6.1")
|
|
||||||
def test_nowait_raises_error_on_block(self):
|
def test_nowait_raises_error_on_block(self):
|
||||||
"""
|
"""
|
||||||
If nowait is specified, we expect an error to be raised rather
|
If nowait is specified, we expect an error to be raised rather
|
||||||
|
@ -128,15 +121,8 @@ class SelectForUpdateTests(TransactionTestCase):
|
||||||
self.end_blocking_transaction()
|
self.end_blocking_transaction()
|
||||||
self.assertIsInstance(status[-1], DatabaseError)
|
self.assertIsInstance(status[-1], DatabaseError)
|
||||||
|
|
||||||
# In Python 2.6 beta and some final releases, exceptions raised in __len__
|
|
||||||
# are swallowed (Python issue 1242657), so these cases return an empty
|
|
||||||
# list, rather than raising an exception. Not a lot we can do about that,
|
|
||||||
# unfortunately, due to the way Python handles list() calls internally.
|
|
||||||
# Python 2.6.1 is the "in the wild" version affected by this, so we skip
|
|
||||||
# the test for that version.
|
|
||||||
@skipIfDBFeature('has_select_for_update_nowait')
|
@skipIfDBFeature('has_select_for_update_nowait')
|
||||||
@skipUnlessDBFeature('has_select_for_update')
|
@skipUnlessDBFeature('has_select_for_update')
|
||||||
@unittest.skipIf(sys.version_info[:3] == (2, 6, 1), "Python version is 2.6.1")
|
|
||||||
def test_unsupported_nowait_raises_error(self):
|
def test_unsupported_nowait_raises_error(self):
|
||||||
"""
|
"""
|
||||||
If a SELECT...FOR UPDATE NOWAIT is run on a database backend
|
If a SELECT...FOR UPDATE NOWAIT is run on a database backend
|
||||||
|
|
|
@ -367,8 +367,6 @@ class DeprecationDisplayTest(AdminScriptTestCase):
|
||||||
self.assertIn("DeprecationWarning: warning from test", err)
|
self.assertIn("DeprecationWarning: warning from test", err)
|
||||||
self.assertIn("DeprecationWarning: module-level warning from deprecation_app", err)
|
self.assertIn("DeprecationWarning: module-level warning from deprecation_app", err)
|
||||||
|
|
||||||
@unittest.skipIf(sys.version_info[:2] == (2, 6),
|
|
||||||
"On Python 2.6, DeprecationWarnings are visible anyway")
|
|
||||||
def test_runner_deprecation_verbosity_zero(self):
|
def test_runner_deprecation_verbosity_zero(self):
|
||||||
args = ['test', '--settings=settings', '--verbosity=0']
|
args = ['test', '--settings=settings', '--verbosity=0']
|
||||||
out, err = self.run_django_admin(args)
|
out, err = self.run_django_admin(args)
|
||||||
|
|
Loading…
Reference in New Issue