mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
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 os
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
from email import charset as Charset, encoders as Encoders
|
||||
from email.generator import Generator
|
||||
@ -139,9 +138,6 @@ class SafeMIMEText(MIMEText):
|
||||
"""
|
||||
fp = six.StringIO()
|
||||
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)
|
||||
return fp.getvalue()
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import collections
|
||||
import copy
|
||||
import datetime
|
||||
import decimal
|
||||
@ -17,7 +18,6 @@ from django.core import exceptions, validators
|
||||
from django.utils.datastructures import DictWrapper
|
||||
from django.utils.dateparse import parse_date, parse_datetime, parse_time
|
||||
from django.utils.functional import curry, total_ordering
|
||||
from django.utils.itercompat import is_iterator
|
||||
from django.utils.text import capfirst
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
@ -585,7 +585,7 @@ class Field(object):
|
||||
return bound_field_class(self, fieldmapping, original)
|
||||
|
||||
def _get_choices(self):
|
||||
if is_iterator(self._choices):
|
||||
if isinstance(self._choices, collections.Iterator):
|
||||
choices, self._choices = tee(self._choices)
|
||||
return choices
|
||||
else:
|
||||
|
@ -4,6 +4,7 @@ Code to manage the creation and SQL rendering of 'where' constraints.
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import collections
|
||||
import datetime
|
||||
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.sql.datastructures import EmptyResultSet, Empty
|
||||
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 import timezone
|
||||
from django.utils import tree
|
||||
@ -61,7 +61,7 @@ class WhereNode(tree.Node):
|
||||
if not isinstance(data, (list, tuple)):
|
||||
return data
|
||||
obj, lookup_type, value = data
|
||||
if is_iterator(value):
|
||||
if isinstance(value, collections.Iterator):
|
||||
# Consume any generators immediately, so that we can determine
|
||||
# emptiness and transform any non-empty values correctly.
|
||||
value = list(value)
|
||||
|
@ -8,7 +8,6 @@ import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import select
|
||||
import socket
|
||||
import threading
|
||||
import unittest
|
||||
@ -924,104 +923,6 @@ class QuietWSGIRequestHandler(WSGIRequestHandler):
|
||||
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):
|
||||
"""
|
||||
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.
|
||||
for index, port in enumerate(self.possible_ports):
|
||||
try:
|
||||
self.httpd = StoppableWSGIServer(
|
||||
self.httpd = WSGIServer(
|
||||
(self.host, port), QuietWSGIRequestHandler)
|
||||
except WSGIServerException as e:
|
||||
if (index + 1 < len(self.possible_ports) and
|
||||
|
@ -398,9 +398,8 @@ def partition(predicate, values):
|
||||
if sys.version_info >= (2, 7, 2):
|
||||
from functools import total_ordering
|
||||
else:
|
||||
# For Python < 2.7.2. Python 2.6 does not have total_ordering, and
|
||||
# total_ordering in 2.7 versions prior to 2.7.2 is buggy. See
|
||||
# http://bugs.python.org/issue10042 for details. For these versions use
|
||||
# For Python < 2.7.2. total_ordering in versions prior to 2.7.2 is buggy.
|
||||
# See http://bugs.python.org/issue10042 for details. For these versions use
|
||||
# code borrowed from Python 2.7.3.
|
||||
def total_ordering(cls):
|
||||
"""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.
|
||||
"""
|
||||
|
||||
import collections
|
||||
import sys
|
||||
|
||||
|
||||
def is_iterable(x):
|
||||
"A implementation independent way of checking for iterables"
|
||||
@ -16,14 +13,3 @@ def is_iterable(x):
|
||||
return False
|
||||
else:
|
||||
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
|
||||
==============
|
||||
|
||||
If you're using Python 2.6.8+, it's strongly recommended that you invoke the
|
||||
Python process running your Django application using the `-R`_ option or with
|
||||
the :envvar:`PYTHONHASHSEED` environment variable set to ``random``.
|
||||
It's strongly recommended that you invoke the Python process running your
|
||||
Django application using the `-R`_ option or with the
|
||||
:envvar:`PYTHONHASHSEED` environment variable set to ``random``.
|
||||
|
||||
These options help protect your site from denial-of-service (DoS)
|
||||
attacks triggered by carefully crafted inputs. Such an attack can
|
||||
|
@ -4,13 +4,6 @@ Running Django on Jython
|
||||
|
||||
.. 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).
|
||||
Django runs cleanly on Jython version 2.5 or later, which means you can deploy
|
||||
Django on any Java platform.
|
||||
|
@ -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,
|
||||
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
|
||||
users of the machine. Python 2.6 added support for user libraries, so if
|
||||
you are using an older version this won't work, but Django 1.5 requires
|
||||
Python 2.6 or newer anyway.
|
||||
users of the machine.
|
||||
|
||||
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
|
||||
|
@ -14,6 +14,19 @@ deprecation process for some features`_.
|
||||
.. _`backwards incompatible changes`: `Backwards incompatible changes 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
|
||||
========================
|
||||
|
||||
|
@ -19,7 +19,6 @@ from admin_scripts.tests import AdminScriptTestCase
|
||||
|
||||
from .logconfig import MyEmailBackend
|
||||
|
||||
PYVERS = sys.version_info[:2]
|
||||
|
||||
# logging config prior to using filter with mail_admins
|
||||
OLD_LOGGING = {
|
||||
@ -87,7 +86,6 @@ class DefaultLoggingTest(TestCase):
|
||||
self.logger.error("Hey, this is an error.")
|
||||
self.assertEqual(output.getvalue(), 'Hey, this is an error.\n')
|
||||
|
||||
@skipUnless(PYVERS > (2,6), "warnings captured only in Python >= 2.7")
|
||||
class WarningLoggerTests(TestCase):
|
||||
"""
|
||||
Tests that warnings output for DeprecationWarnings is enabled
|
||||
|
@ -2148,13 +2148,6 @@ class ConditionalTests(BaseQuerysetTest):
|
||||
t4 = Tag.objects.create(name='t4', 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):
|
||||
# If you're not careful, it's possible to introduce infinite loops via
|
||||
# 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))
|
||||
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
|
||||
@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):
|
||||
"""
|
||||
If nowait is specified, we expect an error to be raised rather
|
||||
@ -128,15 +121,8 @@ class SelectForUpdateTests(TransactionTestCase):
|
||||
self.end_blocking_transaction()
|
||||
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')
|
||||
@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):
|
||||
"""
|
||||
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: 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):
|
||||
args = ['test', '--settings=settings', '--verbosity=0']
|
||||
out, err = self.run_django_admin(args)
|
||||
|
Loading…
Reference in New Issue
Block a user