diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index fb5acb52956..f0ecb384d4a 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -2,7 +2,7 @@ Form Widget classes specific to the Django admin site. """ -import copy +import django.utils.copycompat as copy from django import forms from django.forms.widgets import RadioFieldRenderer diff --git a/django/contrib/gis/geos/tests/test_geos.py b/django/contrib/gis/geos/tests/test_geos.py index 440075dd494..4f2e33f9a03 100644 --- a/django/contrib/gis/geos/tests/test_geos.py +++ b/django/contrib/gis/geos/tests/test_geos.py @@ -821,7 +821,7 @@ class GEOSTest(unittest.TestCase): def test22_copy(self): "Testing use with the Python `copy` module." - import copy + import django.utils.copycompat as copy poly = GEOSGeometry('POLYGON((0 0, 0 23, 23 23, 23 0, 0 0), (5 5, 5 10, 10 10, 10 5, 5 5))') cpy1 = copy.copy(poly) cpy2 = copy.deepcopy(poly) diff --git a/django/contrib/gis/geos/tests/test_geos_mutation.py b/django/contrib/gis/geos/tests/test_geos_mutation.py index 260a4689a63..28f484dca7d 100644 --- a/django/contrib/gis/geos/tests/test_geos_mutation.py +++ b/django/contrib/gis/geos/tests/test_geos_mutation.py @@ -2,9 +2,11 @@ # Modified from original contribution by Aryeh Leib Taurog, which was # released under the New BSD license. import unittest + +import django.utils.copycompat as copy + from django.contrib.gis.geos import * from django.contrib.gis.geos.error import GEOSIndexError -import copy def getItem(o,i): return o[i] def delItem(o,i): del o[i] diff --git a/django/contrib/gis/tests/layermap/tests.py b/django/contrib/gis/tests/layermap/tests.py index b17e7b92fce..ed5e011f9f4 100644 --- a/django/contrib/gis/tests/layermap/tests.py +++ b/django/contrib/gis/tests/layermap/tests.py @@ -1,10 +1,10 @@ import os, unittest -from copy import copy from decimal import Decimal from models import City, County, CountyFeat, Interstate, ICity1, ICity2, State, city_mapping, co_mapping, cofeat_mapping, inter_mapping from django.contrib.gis.db.backend import SpatialBackend from django.contrib.gis.utils.layermapping import LayerMapping, LayerMapError, InvalidDecimal, MissingForeignKey from django.contrib.gis.gdal import DataSource +from django.utils.copycompat import copy shp_path = os.path.dirname(__file__) city_shp = os.path.join(shp_path, '../data/cities/cities.shp') diff --git a/django/db/models/base.py b/django/db/models/base.py index 47c177295d9..5b727a059f5 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -1,4 +1,3 @@ -import copy import types import sys import os @@ -13,6 +12,7 @@ from django.db.models.options import Options from django.db import connection, transaction, DatabaseError from django.db.models import signals from django.db.models.loading import register_models, get_model +import django.utils.copycompat as copy from django.utils.functional import curry from django.utils.encoding import smart_str, force_unicode, smart_unicode from django.conf import settings diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index e54aabacb55..68abf9d22b3 100644 --- a/django/db/models/expressions.py +++ b/django/db/models/expressions.py @@ -1,7 +1,7 @@ -from copy import deepcopy from datetime import datetime from django.utils import tree +from django.utils.copycompat import deepcopy class ExpressionNode(tree.Node): """ diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index ea10b801f69..1be0bc353c6 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -1,12 +1,10 @@ -import copy import datetime +import decimal import os import re import time -try: - import decimal -except ImportError: - from django.utils import _decimal as decimal # for Python 2.3 + +import django.utils.copycompat as copy from django.db import connection from django.db.models import signals diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py index e6497f0441d..97cb4dc082e 100644 --- a/django/db/models/fields/files.py +++ b/django/db/models/fields/files.py @@ -1,7 +1,8 @@ -import copy import datetime import os +import django.utils.copycompat as copy + from django.conf import settings from django.db.models.fields import Field from django.core.files.base import File, ContentFile diff --git a/django/db/models/manager.py b/django/db/models/manager.py index 7487fa0d468..2eeb98bfbc4 100644 --- a/django/db/models/manager.py +++ b/django/db/models/manager.py @@ -1,4 +1,4 @@ -import copy +import django.utils.copycompat as copy from django.db.models.query import QuerySet, EmptyQuerySet, insert_query from django.db.models import signals from django.db.models.fields import FieldDoesNotExist diff --git a/django/db/models/query.py b/django/db/models/query.py index 6a16ce1b337..9cc7659c691 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -2,12 +2,12 @@ The main QuerySet implementation. This provides the public API for the ORM. """ -from copy import deepcopy from django.db import connection, transaction, IntegrityError from django.db.models.aggregates import Aggregate from django.db.models.fields import DateField from django.db.models.query_utils import Q, select_related_descend, CollectedObjects, CyclicDependency, deferred_class_factory from django.db.models import signals, sql +from django.utils.copycompat import deepcopy # Used to control how many objects are worked with at once in some cases (e.g. # when deleting objects). diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py index 6a6b69013f4..c5cb336f4ec 100644 --- a/django/db/models/query_utils.py +++ b/django/db/models/query_utils.py @@ -7,16 +7,11 @@ circular import difficulties. """ import weakref -from copy import deepcopy +from django.utils.copycompat import deepcopy from django.utils import tree from django.utils.datastructures import SortedDict -try: - sorted -except NameError: - from django.utils.itercompat import sorted # For Python 2.3. - class CyclicDependency(Exception): """ diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 7bc45cbce27..f3e24ed8ee4 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -7,7 +7,7 @@ databases). The abstraction barrier only works one way: this module has to know all about the internals of models in order to get the information it needs. """ -from copy import deepcopy +from django.utils.copycompat import deepcopy from django.utils.tree import Node from django.utils.datastructures import SortedDict from django.utils.encoding import force_unicode diff --git a/django/forms/fields.py b/django/forms/fields.py index 0aef355d0f1..c0ee2f09559 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -2,28 +2,19 @@ Field classes. """ -import copy import datetime import os import re import time import urlparse +from decimal import Decimal, DecimalException try: from cStringIO import StringIO except ImportError: from StringIO import StringIO -# Python 2.3 fallbacks -try: - from decimal import Decimal, DecimalException -except ImportError: - from django.utils._decimal import Decimal, DecimalException -try: - set -except NameError: - from sets import Set as set - import django.core.exceptions +import django.utils.copycompat as copy from django.utils.translation import ugettext_lazy as _ from django.utils.encoding import smart_unicode, smart_str diff --git a/django/forms/forms.py b/django/forms/forms.py index e854de8a7a0..7f6fa512870 100644 --- a/django/forms/forms.py +++ b/django/forms/forms.py @@ -2,8 +2,7 @@ Form classes """ -from copy import deepcopy - +from django.utils.copycompat import deepcopy from django.utils.datastructures import SortedDict from django.utils.html import conditional_escape from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode diff --git a/django/forms/widgets.py b/django/forms/widgets.py index b1d2cb7cdaa..d59e6343e55 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -2,12 +2,7 @@ HTML Widget classes """ -try: - set -except NameError: - from sets import Set as set # Python 2.3 fallback - -import copy +import django.utils.copycompat as copy from itertools import chain from django.conf import settings from django.utils.datastructures import MultiValueDict, MergeDict diff --git a/django/http/__init__.py b/django/http/__init__.py index 446659b5601..7b0c469c517 100644 --- a/django/http/__init__.py +++ b/django/http/__init__.py @@ -183,7 +183,7 @@ class QueryDict(MultiValueDict): return result def __deepcopy__(self, memo): - import copy + import django.utils.copycompat as copy result = self.__class__('', mutable=True) memo[id(self)] = result for key, value in dict.items(self): diff --git a/django/utils/_decimal.py b/django/utils/_decimal.py index 677d26bb323..2801046cf17 100644 --- a/django/utils/_decimal.py +++ b/django/utils/_decimal.py @@ -134,7 +134,7 @@ __all__ = [ 'setcontext', 'getcontext' ] -import copy as _copy +import django.utils.copycompat as _copy #Rounding ROUND_DOWN = 'ROUND_DOWN' diff --git a/django/utils/copycompat.py b/django/utils/copycompat.py new file mode 100644 index 00000000000..22b3cfbef7e --- /dev/null +++ b/django/utils/copycompat.py @@ -0,0 +1,14 @@ +""" +Fixes Python 2.4's failure to deepcopy unbound functions. +""" + +import copy +import types + +# Monkeypatch copy's deepcopy registry to handle functions correctly. +if (hasattr(copy, '_deepcopy_dispatch') and types.FunctionType not in copy._deepcopy_dispatch): + copy._deepcopy_dispatch[types.FunctionType] = copy._deepcopy_atomic + +# Pose as the copy module now. +del copy, types +from copy import * diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py index 2b586d7efe0..06cf6c6b75b 100644 --- a/django/utils/datastructures.py +++ b/django/utils/datastructures.py @@ -1,4 +1,4 @@ -from copy import deepcopy +from django.utils.copycompat import deepcopy class MergeDict(object): @@ -214,7 +214,7 @@ class MultiValueDict(dict): return self.__class__(super(MultiValueDict, self).items()) def __deepcopy__(self, memo=None): - import copy + import django.utils.copycompat as copy if memo is None: memo = {} result = self.__class__() diff --git a/django/utils/functional.py b/django/utils/functional.py index 823cda45873..43b7ab1437b 100644 --- a/django/utils/functional.py +++ b/django/utils/functional.py @@ -335,8 +335,10 @@ class SimpleLazyObject(LazyObject): memo[id(self)] = result return result else: - import copy - return copy.deepcopy(self._wrapped, memo) + # Changed to use deepcopy from copycompat, instead of copy + # For Python 2.4. + from django.utils.copycompat import deepcopy + return deepcopy(self._wrapped, memo) # Need to pretend to be the wrapped class, for the sake of objects that care # about this (especially in equality tests) diff --git a/django/utils/tree.py b/django/utils/tree.py index a9028b834b7..a6cfec27ad4 100644 --- a/django/utils/tree.py +++ b/django/utils/tree.py @@ -3,7 +3,7 @@ A class for storing a tree graph. Primarily used for filter constructs in the ORM. """ -from copy import deepcopy +from django.utils.copycompat import deepcopy class Node(object): """ diff --git a/tests/regressiontests/dispatch/tests/test_dispatcher.py b/tests/regressiontests/dispatch/tests/test_dispatcher.py index adf760386c2..ad3a05f2cd7 100644 --- a/tests/regressiontests/dispatch/tests/test_dispatcher.py +++ b/tests/regressiontests/dispatch/tests/test_dispatcher.py @@ -1,8 +1,8 @@ from django.dispatch import Signal import unittest -import copy import sys import gc +import django.utils.copycompat as copy if sys.platform.startswith('java'): def garbage_collect(): diff --git a/tests/regressiontests/extra_regress/models.py b/tests/regressiontests/extra_regress/models.py index 5d22d6cc07d..76eb549f81b 100644 --- a/tests/regressiontests/extra_regress/models.py +++ b/tests/regressiontests/extra_regress/models.py @@ -1,6 +1,7 @@ -import copy import datetime +import django.utils.copycompat as copy + from django.contrib.auth.models import User from django.db import models from django.db.models.query import Q diff --git a/tests/regressiontests/utils/tests.py b/tests/regressiontests/utils/tests.py index a7a6e4c3a11..6258b812003 100644 --- a/tests/regressiontests/utils/tests.py +++ b/tests/regressiontests/utils/tests.py @@ -220,7 +220,7 @@ class TestUtilsSimpleLazyObject(TestCase): self.assertEqual(_ComplexObject, SimpleLazyObject(complex_object).__class__) def test_deepcopy(self): - import copy + import django.utils.copycompat as copy # Check that we *can* do deep copy, and that it returns the right # objects.