diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 43c5503f990..fbda8b7a35b 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -1,3 +1,4 @@ +from functools import update_wrapper, partial from django import forms, template from django.forms.formsets import all_valid from django.forms.models import (modelform_factory, modelformset_factory, @@ -17,10 +18,8 @@ from django.http import Http404, HttpResponse, HttpResponseRedirect from django.shortcuts import get_object_or_404, render_to_response from django.utils.decorators import method_decorator from django.utils.datastructures import SortedDict -from django.utils.functional import update_wrapper from django.utils.html import escape, escapejs from django.utils.safestring import mark_safe -from django.utils.functional import curry from django.utils.text import capfirst, get_text_list from django.utils.translation import ugettext as _ from django.utils.translation import ungettext @@ -426,7 +425,7 @@ class ModelAdmin(BaseModelAdmin): "form": self.form, "fields": fields, "exclude": exclude, - "formfield_callback": curry(self.formfield_for_dbfield, request=request), + "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelform_factory(self.model, **defaults) @@ -457,7 +456,7 @@ class ModelAdmin(BaseModelAdmin): Returns a Form class for use in the Formset on the changelist page. """ defaults = { - "formfield_callback": curry(self.formfield_for_dbfield, request=request), + "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelform_factory(self.model, **defaults) @@ -468,7 +467,7 @@ class ModelAdmin(BaseModelAdmin): is used. """ defaults = { - "formfield_callback": curry(self.formfield_for_dbfield, request=request), + "formfield_callback": partial(self.formfield_for_dbfield, request=request), } defaults.update(kwargs) return modelformset_factory(self.model, @@ -1327,7 +1326,7 @@ class InlineModelAdmin(BaseModelAdmin): "fk_name": self.fk_name, "fields": fields, "exclude": exclude, - "formfield_callback": curry(self.formfield_for_dbfield, request=request), + "formfield_callback": partial(self.formfield_for_dbfield, request=request), "extra": self.extra, "max_num": self.max_num, "can_delete": self.can_delete, diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index b03bce455ed..1f98db8abc0 100644 --- a/django/contrib/admin/sites.py +++ b/django/contrib/admin/sites.py @@ -1,4 +1,5 @@ import re +from functools import update_wrapper from django import http, template from django.contrib.admin import ModelAdmin, actions from django.contrib.admin.forms import AdminAuthenticationForm @@ -9,7 +10,6 @@ from django.db.models.base import ModelBase from django.core.exceptions import ImproperlyConfigured from django.core.urlresolvers import reverse from django.shortcuts import render_to_response -from django.utils.functional import update_wrapper from django.utils.safestring import mark_safe from django.utils.text import capfirst from django.utils.translation import ugettext as _ diff --git a/django/contrib/admin/views/decorators.py b/django/contrib/admin/views/decorators.py index 9088eb04946..9fabe64a6a2 100644 --- a/django/contrib/admin/views/decorators.py +++ b/django/contrib/admin/views/decorators.py @@ -1,8 +1,4 @@ -try: - from functools import wraps -except ImportError: - from django.utils.functional import wraps # Python 2.4 fallback. - +from functools import wraps from django.utils.translation import ugettext as _ from django.contrib.admin.forms import AdminAuthenticationForm from django.contrib.auth.views import login diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 1978b3e800a..f210d4ec797 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -2,8 +2,7 @@ Form Widget classes specific to the Django admin site. """ -import django.utils.copycompat as copy - +import copy from django import forms from django.forms.widgets import RadioFieldRenderer from django.forms.util import flatatt diff --git a/django/contrib/auth/decorators.py b/django/contrib/auth/decorators.py index 64b77a5f964..00a6bce17d6 100644 --- a/django/contrib/auth/decorators.py +++ b/django/contrib/auth/decorators.py @@ -1,9 +1,5 @@ import urlparse -try: - from functools import wraps -except ImportError: - from django.utils.functional import wraps # Python 2.4 fallback. - +from functools import wraps from django.conf import settings from django.contrib.auth import REDIRECT_FIELD_NAME from django.utils.decorators import available_attrs diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index 8fcbdef6e8e..4fceca840a1 100644 --- a/django/contrib/auth/models.py +++ b/django/contrib/auth/models.py @@ -1,4 +1,5 @@ import datetime +import hashlib import urllib from django.contrib import auth @@ -8,7 +9,6 @@ from django.db import models from django.db.models.manager import EmptyManager from django.contrib.contenttypes.models import ContentType from django.utils.encoding import smart_str -from django.utils.hashcompat import md5_constructor, sha_constructor from django.utils.translation import ugettext_lazy as _ from django.utils.crypto import constant_time_compare @@ -29,9 +29,9 @@ def get_hexdigest(algorithm, salt, raw_password): return crypt.crypt(raw_password, salt) if algorithm == 'md5': - return md5_constructor(salt + raw_password).hexdigest() + return hashlib.md5(salt + raw_password).hexdigest() elif algorithm == 'sha1': - return sha_constructor(salt + raw_password).hexdigest() + return hashlib.sha1(salt + raw_password).hexdigest() raise ValueError("Got unknown password algorithm type in password.") def check_password(raw_password, enc_password): diff --git a/django/contrib/auth/tests/tokens.py b/django/contrib/auth/tests/tokens.py index 20b2ecbbc71..c9baff2261a 100644 --- a/django/contrib/auth/tests/tokens.py +++ b/django/contrib/auth/tests/tokens.py @@ -58,14 +58,14 @@ class TokenGeneratorTest(TestCase): # Hard code in the Django 1.2 algorithm (not the result, as it is time # dependent) def _make_token(user): - from django.utils.hashcompat import sha_constructor + import hashlib from django.utils.http import int_to_base36 timestamp = (date.today() - date(2001,1,1)).days ts_b36 = int_to_base36(timestamp) - hash = sha_constructor(settings.SECRET_KEY + unicode(user.id) + - user.password + user.last_login.strftime('%Y-%m-%d %H:%M:%S') + - unicode(timestamp)).hexdigest()[::2] + hash = hashlib.sha1(settings.SECRET_KEY + unicode(user.id) + + user.password + user.last_login.strftime('%Y-%m-%d %H:%M:%S') + + unicode(timestamp)).hexdigest()[::2] return "%s-%s" % (ts_b36, hash) user = User.objects.create_user('tokentestuser', 'test2@example.com', 'testpw') diff --git a/django/contrib/auth/tokens.py b/django/contrib/auth/tokens.py index f03ed0c93f4..483c4838a74 100644 --- a/django/contrib/auth/tokens.py +++ b/django/contrib/auth/tokens.py @@ -1,7 +1,6 @@ from datetime import date - +import hashlib from django.conf import settings -from django.utils.hashcompat import sha_constructor from django.utils.http import int_to_base36, base36_to_int from django.utils.crypto import constant_time_compare, salted_hmac @@ -67,9 +66,9 @@ class PasswordResetTokenGenerator(object): def _make_token_with_timestamp_old(self, user, timestamp): # The Django 1.2 method ts_b36 = int_to_base36(timestamp) - hash = sha_constructor(settings.SECRET_KEY + unicode(user.id) + - user.password + user.last_login.strftime('%Y-%m-%d %H:%M:%S') + - unicode(timestamp)).hexdigest()[::2] + hash = hashlib.sha1(settings.SECRET_KEY + unicode(user.id) + + user.password + user.last_login.strftime('%Y-%m-%d %H:%M:%S') + + unicode(timestamp)).hexdigest()[::2] return "%s-%s" % (ts_b36, hash) def _num_days(self, dt): diff --git a/django/contrib/comments/forms.py b/django/contrib/comments/forms.py index 4ecc4c4c06c..a0cfc2452c0 100644 --- a/django/contrib/comments/forms.py +++ b/django/contrib/comments/forms.py @@ -1,6 +1,6 @@ -import time import datetime - +import hashlib +import time from django import forms from django.forms.util import ErrorDict from django.conf import settings @@ -8,7 +8,6 @@ from django.contrib.contenttypes.models import ContentType from models import Comment from django.utils.crypto import salted_hmac, constant_time_compare from django.utils.encoding import force_unicode -from django.utils.hashcompat import sha_constructor from django.utils.text import get_text_list from django.utils.translation import ungettext, ugettext_lazy as _ @@ -100,7 +99,7 @@ class CommentSecurityForm(forms.Form): """Generate a (SHA1) security hash from the provided info.""" # Django 1.2 compatibility info = (content_type, object_pk, timestamp, settings.SECRET_KEY) - return sha_constructor("".join(info)).hexdigest() + return hashlib.sha1("".join(info)).hexdigest() class CommentDetailsForm(CommentSecurityForm): """ diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py index 76f8eaf973e..64c1f8b4200 100644 --- a/django/contrib/contenttypes/generic.py +++ b/django/contrib/contenttypes/generic.py @@ -2,6 +2,7 @@ Classes allowing "generic" relations through ContentType and object-id fields. """ +from functools import partial from django.core.exceptions import ObjectDoesNotExist from django.db import connection from django.db.models import signals @@ -11,11 +12,8 @@ from django.db.models.loading import get_model from django.forms import ModelForm from django.forms.models import BaseModelFormSet, modelformset_factory, save_instance from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets -from django.utils.encoding import smart_unicode -from django.utils.functional import curry - from django.contrib.contenttypes.models import ContentType - +from django.utils.encoding import smart_unicode class GenericForeignKey(object): """ @@ -414,7 +412,7 @@ class GenericInlineModelAdmin(InlineModelAdmin): "ct_field": self.ct_field, "fk_field": self.ct_fk_field, "form": self.form, - "formfield_callback": curry(self.formfield_for_dbfield, request=request), + "formfield_callback": partial(self.formfield_for_dbfield, request=request), "formset": self.formset, "extra": self.extra, "can_delete": self.can_delete, diff --git a/django/contrib/formtools/preview.py b/django/contrib/formtools/preview.py index 3fa61ba6bfe..7d6398c9a65 100644 --- a/django/contrib/formtools/preview.py +++ b/django/contrib/formtools/preview.py @@ -2,13 +2,15 @@ Formtools Preview application. """ -import cPickle as pickle +try: + import cPickle as pickle +except ImportError: + import pickle from django.conf import settings from django.http import Http404 from django.shortcuts import render_to_response from django.template.context import RequestContext -from django.utils.hashcompat import md5_constructor from django.utils.crypto import constant_time_compare from django.contrib.formtools.utils import security_hash diff --git a/django/contrib/formtools/utils.py b/django/contrib/formtools/utils.py index 894178a6168..974850dc6e2 100644 --- a/django/contrib/formtools/utils.py +++ b/django/contrib/formtools/utils.py @@ -3,10 +3,10 @@ try: except ImportError: import pickle +import hashlib from django.conf import settings from django.forms import BooleanField from django.utils.crypto import salted_hmac -from django.utils.hashcompat import md5_constructor def security_hash(request, form, *args): @@ -39,7 +39,7 @@ def security_hash(request, form, *args): # Python 2.3, but Django requires 2.4 anyway, so that's OK. pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL) - return md5_constructor(pickled).hexdigest() + return hashlib.md5(pickled).hexdigest() def form_hmac(form): diff --git a/django/contrib/formtools/wizard.py b/django/contrib/formtools/wizard.py index 6f3660dd996..d581f0df83a 100644 --- a/django/contrib/formtools/wizard.py +++ b/django/contrib/formtools/wizard.py @@ -4,7 +4,10 @@ step and storing the form's state as HTML hidden fields so that no state is stored on the server side. """ -import cPickle as pickle +try: + import cPickle as pickle +except ImportError: + import pickle from django import forms from django.conf import settings @@ -13,7 +16,6 @@ from django.http import Http404 from django.shortcuts import render_to_response from django.template.context import RequestContext from django.utils.crypto import constant_time_compare -from django.utils.hashcompat import md5_constructor from django.utils.translation import ugettext_lazy as _ from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_protect diff --git a/django/contrib/gis/geos/tests/test_geos.py b/django/contrib/gis/geos/tests/test_geos.py index 8342b580edb..4620a9fb528 100644 --- a/django/contrib/gis/geos/tests/test_geos.py +++ b/django/contrib/gis/geos/tests/test_geos.py @@ -820,7 +820,7 @@ class GEOSTest(unittest.TestCase, TestDataMixin): def test22_copy(self): "Testing use with the Python `copy` module." - import django.utils.copycompat as copy + import 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 266a12d3b3d..c8f7e658adf 100644 --- a/django/contrib/gis/geos/tests/test_geos_mutation.py +++ b/django/contrib/gis/geos/tests/test_geos_mutation.py @@ -2,8 +2,7 @@ # Modified from original contribution by Aryeh Leib Taurog, which was # released under the New BSD license. -import django.utils.copycompat as copy - +import copy from django.contrib.gis.geos import * from django.contrib.gis.geos.error import GEOSIndexError from django.utils import unittest diff --git a/django/contrib/gis/tests/layermap/tests.py b/django/contrib/gis/tests/layermap/tests.py index ad7a50462c2..3caa22d09bd 100644 --- a/django/contrib/gis/tests/layermap/tests.py +++ b/django/contrib/gis/tests/layermap/tests.py @@ -1,7 +1,7 @@ +import copy import os from decimal import Decimal -from django.utils.copycompat import copy from django.utils.unittest import TestCase from django.contrib.gis.gdal import DataSource, OGRException diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py index bb09cb657a7..7dfc39e6cb3 100644 --- a/django/contrib/sessions/backends/base.py +++ b/django/contrib/sessions/backends/base.py @@ -1,4 +1,5 @@ import base64 +import hashlib import os import random import sys @@ -11,7 +12,6 @@ except ImportError: from django.conf import settings from django.core.exceptions import SuspiciousOperation -from django.utils.hashcompat import md5_constructor from django.utils.crypto import constant_time_compare, salted_hmac # Use the system (hardware-based) random number generator if it exists. @@ -119,7 +119,7 @@ class SessionBase(object): def _decode_old(self, session_data): encoded_data = base64.decodestring(session_data) pickled, tamper_check = encoded_data[:-32], encoded_data[-32:] - if not constant_time_compare(md5_constructor(pickled + settings.SECRET_KEY).hexdigest(), + if not constant_time_compare(hashlib.md5(pickled + settings.SECRET_KEY).hexdigest(), tamper_check): raise SuspiciousOperation("User tampered with session cookie.") return pickle.loads(pickled) @@ -161,7 +161,7 @@ class SessionBase(object): # No getpid() in Jython, for example pid = 1 while 1: - session_key = md5_constructor("%s%s%s%s" + session_key = hashlib.md5("%s%s%s%s" % (randrange(0, MAX_SESSION_KEY), pid, time.time(), settings.SECRET_KEY)).hexdigest() if not self.exists(session_key): diff --git a/django/contrib/sessions/tests.py b/django/contrib/sessions/tests.py index afdb7618168..9cce3549acc 100644 --- a/django/contrib/sessions/tests.py +++ b/django/contrib/sessions/tests.py @@ -1,5 +1,6 @@ import base64 from datetime import datetime, timedelta +import hashlib import pickle import shutil import tempfile @@ -15,7 +16,6 @@ from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation from django.http import HttpResponse from django.test import TestCase, RequestFactory from django.utils import unittest -from django.utils.hashcompat import md5_constructor class SessionTestsMixin(object): @@ -257,7 +257,7 @@ class SessionTestsMixin(object): # Hard code the Django 1.2 method here: def encode(session_dict): pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL) - pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest() + pickled_md5 = hashlib.md5(pickled + settings.SECRET_KEY).hexdigest() return base64.encodestring(pickled + pickled_md5) data = {'a test key': 'a test value'} diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py index b75d636a7ab..57bb63eedcb 100644 --- a/django/core/cache/backends/filebased.py +++ b/django/core/cache/backends/filebased.py @@ -1,15 +1,15 @@ "File-based cache backend" +import hashlib import os -import time import shutil +import time try: import cPickle as pickle except ImportError: import pickle from django.core.cache.backends.base import BaseCache -from django.utils.hashcompat import md5_constructor class FileBasedCache(BaseCache): def __init__(self, dir, params): @@ -145,7 +145,7 @@ class FileBasedCache(BaseCache): Thus, a cache key of "foo" gets turnned into a file named ``{cache-dir}ac/bd/18db4cc2f85cedef654fccc4a4d8``. """ - path = md5_constructor(key).hexdigest() + path = hashlib.md5(key).hexdigest() path = os.path.join(path[:2], path[2:4], path[4:]) return os.path.join(self._dir, path) diff --git a/django/core/cache/backends/locmem.py b/django/core/cache/backends/locmem.py index ecec8750bad..fa3b4b7f180 100644 --- a/django/core/cache/backends/locmem.py +++ b/django/core/cache/backends/locmem.py @@ -77,12 +77,10 @@ class LocMemCache(BaseCache): key = self.make_key(key, version=version) self.validate_key(key) self._lock.writer_enters() - # Python 2.4 doesn't allow combined try-except-finally blocks. try: - try: - self._set(key, pickle.dumps(value), timeout) - except pickle.PickleError: - pass + self._set(key, pickle.dumps(value), timeout) + except pickle.PickleError: + pass finally: self._lock.writer_leaves()