Fixed #20746 -- Removed Python 2.6 specific code/docs

This commit is contained in:
Tim Graham 2013-07-13 13:29:11 -04:00
parent 0d81fd0e5f
commit 2456ffa42c
14 changed files with 25 additions and 164 deletions

View File

@ -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()

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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"""

View File

@ -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__')

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
======================== ========================

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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)