summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Wilson Jr <gary.wilson@gmail.com>2008-08-02 05:56:57 +0000
committerGary Wilson Jr <gary.wilson@gmail.com>2008-08-02 05:56:57 +0000
commitc85c8f88914cdba05813cc5768377841340bd09d (patch)
tree58f61ee33072b70256a448f7df7333109adf1936
parent8a58f2216cb2897db53ad166d71393fef1181c1a (diff)
downloaddjango-c85c8f88914cdba05813cc5768377841340bd09d.tar.gz
Fixed #7919 -- md5 and sha modules are deprecated since Python 2.5, use hashlib module when available. Patch from Karen Tracey.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8193 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/contrib/admin/sites.py35
-rw-r--r--django/contrib/admin/views/decorators.py8
-rw-r--r--django/contrib/auth/tokens.py12
-rw-r--r--django/contrib/comments/models.py4
-rw-r--r--django/contrib/csrf/middleware.py53
-rw-r--r--django/contrib/formtools/preview.py7
-rw-r--r--django/contrib/formtools/wizard.py7
-rw-r--r--django/contrib/sessions/backends/base.py10
-rw-r--r--django/contrib/sessions/models.py6
-rw-r--r--django/core/cache/backends/filebased.py29
-rw-r--r--django/db/backends/util.py5
-rw-r--r--django/middleware/common.py6
-rw-r--r--django/utils/cache.py6
-rw-r--r--django/utils/hashcompat.py16
-rw-r--r--tests/regressiontests/cache/tests.py33
-rw-r--r--tests/regressiontests/file_uploads/tests.py6
-rw-r--r--tests/regressiontests/test_client_regress/models.py10
17 files changed, 137 insertions, 116 deletions
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
index 6cb0c21795..5bb53886c6 100644
--- a/django/contrib/admin/sites.py
+++ b/django/contrib/admin/sites.py
@@ -1,3 +1,8 @@
+import base64
+import cPickle as pickle
+import datetime
+import re
+
from django import http, template
from django.contrib.admin import ModelAdmin
from django.contrib.auth import authenticate, login
@@ -9,11 +14,7 @@ from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy, ugettext as _
from django.views.decorators.cache import never_cache
from django.conf import settings
-import base64
-import cPickle as pickle
-import datetime
-import md5
-import re
+from django.utils.hashcompat import md5_constructor
ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
LOGIN_FORM_KEY = 'this_is_the_login_form'
@@ -29,14 +30,14 @@ class NotRegistered(Exception):
def _encode_post_data(post_data):
from django.conf import settings
pickled = pickle.dumps(post_data)
- pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
+ pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
return base64.encodestring(pickled + pickled_md5)
def _decode_post_data(encoded_data):
from django.conf import settings
encoded_data = base64.decodestring(encoded_data)
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
- if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
+ if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
from django.core.exceptions import SuspiciousOperation
raise SuspiciousOperation, "User may have tampered with session cookie."
return pickle.loads(pickled)
@@ -48,10 +49,10 @@ class AdminSite(object):
register() method, and the root() method can then be used as a Django view function
that presents a full admin interface for the collection of registered models.
"""
-
+
index_template = None
login_template = None
-
+
def __init__(self):
self._registry = {} # model_class class -> admin_class instance
@@ -117,23 +118,23 @@ class AdminSite(object):
return request.user.is_authenticated() and request.user.is_staff
def root(self, request, url):
- """
+ """
Handles main URL routing for the admin app.
`url` is the remainder of the URL -- e.g. 'comments/comment/'.
"""
if request.method == 'GET' and not request.path.endswith('/'):
return http.HttpResponseRedirect(request.path + '/')
-
+
# Figure out the admin base URL path and stash it for later use
self.root_path = re.sub(re.escape(url) + '$', '', request.path)
-
+
url = url.rstrip('/') # Trim trailing slash, if it exists.
# The 'logout' view doesn't require that the person is logged in.
if url == 'logout':
return self.logout(request)
-
+
# Check permission to continue or display login form.
if not self.has_permission(request):
return self.login(request)
@@ -154,7 +155,7 @@ class AdminSite(object):
match = USER_CHANGE_PASSWORD_URL_RE.match(url)
if match:
return self.user_change_password(request, match.group(1))
-
+
if '/' in url:
return self.model_page(request, *url.split('/', 2))
@@ -320,14 +321,14 @@ class AdminSite(object):
# Sort the models alphabetically within each app.
for app in app_list:
app['models'].sort(lambda x, y: cmp(x['name'], y['name']))
-
+
context = {
'title': _('Site administration'),
'app_list': app_list,
'root_path': self.root_path,
}
context.update(extra_context or {})
- return render_to_response(self.index_template or 'admin/index.html', context,
+ return render_to_response(self.index_template or 'admin/index.html', context,
context_instance=template.RequestContext(request)
)
index = never_cache(index)
@@ -342,7 +343,7 @@ class AdminSite(object):
post_data = _encode_post_data(request.POST)
else:
post_data = _encode_post_data({})
-
+
context = {
'title': _('Log in'),
'app_path': request.path,
diff --git a/django/contrib/admin/views/decorators.py b/django/contrib/admin/views/decorators.py
index 57517cc821..cf0cd704c2 100644
--- a/django/contrib/admin/views/decorators.py
+++ b/django/contrib/admin/views/decorators.py
@@ -1,5 +1,4 @@
import base64
-import md5
import cPickle as pickle
try:
from functools import wraps
@@ -12,6 +11,7 @@ from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login
from django.shortcuts import render_to_response
from django.utils.translation import ugettext_lazy, ugettext as _
+from django.utils.hashcompat import md5_constructor
ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.")
LOGIN_FORM_KEY = 'this_is_the_login_form'
@@ -35,13 +35,13 @@ def _display_login_form(request, error_message=''):
def _encode_post_data(post_data):
pickled = pickle.dumps(post_data)
- pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
+ pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
return base64.encodestring(pickled + pickled_md5)
def _decode_post_data(encoded_data):
encoded_data = base64.decodestring(encoded_data)
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
- if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
+ if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
from django.core.exceptions import SuspiciousOperation
raise SuspiciousOperation, "User may have tampered with session cookie."
return pickle.loads(pickled)
@@ -87,7 +87,7 @@ def staff_member_required(view_func):
if len(users) == 1:
message = _("Your e-mail address is not your username. Try '%s' instead.") % users[0].username
else:
- # Either we cannot find the user, or if more than 1
+ # Either we cannot find the user, or if more than 1
# we cannot guess which user is the correct one.
message = _("Usernames cannot contain the '@' character.")
return _display_login_form(request, message)
diff --git a/django/contrib/auth/tokens.py b/django/contrib/auth/tokens.py
index acfbc3bb9c..c9b353583c 100644
--- a/django/contrib/auth/tokens.py
+++ b/django/contrib/auth/tokens.py
@@ -50,17 +50,17 @@ class PasswordResetTokenGenerator(object):
# last_login will also change), we produce a hash that will be
# invalid as soon as it is used.
# We limit the hash to 20 chars to keep URL short
- import sha
- hash = sha.new(settings.SECRET_KEY + unicode(user.id) +
- user.password + unicode(user.last_login) +
- unicode(timestamp)).hexdigest()[::2]
+ from django.utils.hashcompat import sha_constructor
+ hash = sha_constructor(settings.SECRET_KEY + unicode(user.id) +
+ user.password + unicode(user.last_login) +
+ unicode(timestamp)).hexdigest()[::2]
return "%s-%s" % (ts_b36, hash)
def _num_days(self, dt):
- return (dt - date(2001,1,1)).days
+ return (dt - date(2001,1,1)).days
def _today(self):
# Used for mocking in tests
- return date.today()
+ return date.today()
default_token_generator = PasswordResetTokenGenerator()
diff --git a/django/contrib/comments/models.py b/django/contrib/comments/models.py
index a13fec9e6e..fdf34c8997 100644
--- a/django/contrib/comments/models.py
+++ b/django/contrib/comments/models.py
@@ -29,8 +29,8 @@ class CommentManager(models.Manager):
'pa,ra') and target (something like 'lcom.eventtimes:5157'). Used to
validate that submitted form options have not been tampered-with.
"""
- import md5
- return md5.new(options + photo_options + rating_options + target + settings.SECRET_KEY).hexdigest()
+ from django.utils.hashcompat import md5_constructor
+ return md5_constructor(options + photo_options + rating_options + target + settings.SECRET_KEY).hexdigest()
def get_rating_options(self, rating_string):
"""
diff --git a/django/contrib/csrf/middleware.py b/django/contrib/csrf/middleware.py
index 1a75a5d6ab..24c1511c91 100644
--- a/django/contrib/csrf/middleware.py
+++ b/django/contrib/csrf/middleware.py
@@ -2,44 +2,45 @@
Cross Site Request Forgery Middleware.
This module provides a middleware that implements protection
-against request forgeries from other sites.
-
+against request forgeries from other sites.
"""
+
+import re
+import itertools
+
from django.conf import settings
from django.http import HttpResponseForbidden
+from django.utils.hashcompat import md5_constructor
from django.utils.safestring import mark_safe
-import md5
-import re
-import itertools
_ERROR_MSG = mark_safe('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p></body></html>')
_POST_FORM_RE = \
re.compile(r'(<form\W[^>]*\bmethod=(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE)
-
-_HTML_TYPES = ('text/html', 'application/xhtml+xml')
+
+_HTML_TYPES = ('text/html', 'application/xhtml+xml')
def _make_token(session_id):
- return md5.new(settings.SECRET_KEY + session_id).hexdigest()
+ return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
class CsrfMiddleware(object):
"""Django middleware that adds protection against Cross Site
- Request Forgeries by adding hidden form fields to POST forms and
- checking requests for the correct value.
-
- In the list of middlewares, SessionMiddleware is required, and must come
- after this middleware. CsrfMiddleWare must come after compression
+ Request Forgeries by adding hidden form fields to POST forms and
+ checking requests for the correct value.
+
+ In the list of middlewares, SessionMiddleware is required, and must come
+ after this middleware. CsrfMiddleWare must come after compression
middleware.
-
- If a session ID cookie is present, it is hashed with the SECRET_KEY
- setting to create an authentication token. This token is added to all
- outgoing POST forms and is expected on all incoming POST requests that
+
+ If a session ID cookie is present, it is hashed with the SECRET_KEY
+ setting to create an authentication token. This token is added to all
+ outgoing POST forms and is expected on all incoming POST requests that
have a session ID cookie.
-
- If you are setting cookies directly, instead of using Django's session
+
+ If you are setting cookies directly, instead of using Django's session
framework, this middleware will not work.
"""
-
+
def process_request(self, request):
if request.method == 'POST':
try:
@@ -54,10 +55,10 @@ class CsrfMiddleware(object):
request_csrf_token = request.POST['csrfmiddlewaretoken']
except KeyError:
return HttpResponseForbidden(_ERROR_MSG)
-
+
if request_csrf_token != csrf_token:
return HttpResponseForbidden(_ERROR_MSG)
-
+
return None
def process_response(self, request, response):
@@ -66,7 +67,7 @@ class CsrfMiddleware(object):
cookie = response.cookies[settings.SESSION_COOKIE_NAME]
csrf_token = _make_token(cookie.value)
except KeyError:
- # No outgoing cookie to set session, but
+ # No outgoing cookie to set session, but
# a session might already exist.
try:
session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
@@ -74,12 +75,12 @@ class CsrfMiddleware(object):
except KeyError:
# no incoming or outgoing cookie
pass
-
+
if csrf_token is not None and \
response['Content-Type'].split(';')[0] in _HTML_TYPES:
-
+
# ensure we don't add the 'id' attribute twice (HTML validity)
- idattributes = itertools.chain(("id='csrfmiddlewaretoken'",),
+ idattributes = itertools.chain(("id='csrfmiddlewaretoken'",),
itertools.repeat(''))
def add_csrf_field(match):
"""Returns the matched <form> tag plus the added <input> element"""
diff --git a/django/contrib/formtools/preview.py b/django/contrib/formtools/preview.py
index db5d58e971..c56fdff628 100644
--- a/django/contrib/formtools/preview.py
+++ b/django/contrib/formtools/preview.py
@@ -2,12 +2,13 @@
Formtools Preview application.
"""
+import cPickle as pickle
+
from django.conf import settings
from django.http import Http404
from django.shortcuts import render_to_response
from django.template.context import RequestContext
-import cPickle as pickle
-import md5
+from django.utils.hashcompat import md5_constructor
AUTO_ID = 'formtools_%s' # Each form here uses this as its auto_id parameter.
@@ -109,7 +110,7 @@ class FormPreview(object):
# Use HIGHEST_PROTOCOL because it's the most efficient. It requires
# Python 2.3, but Django requires 2.3 anyway, so that's OK.
pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
- return md5.new(pickled).hexdigest()
+ return md5_constructor(pickled).hexdigest()
def failed_hash(self, request):
"Returns an HttpResponse in the case of an invalid security hash."
diff --git a/django/contrib/formtools/wizard.py b/django/contrib/formtools/wizard.py
index 7b96d91187..984b6e487e 100644
--- a/django/contrib/formtools/wizard.py
+++ b/django/contrib/formtools/wizard.py
@@ -4,13 +4,14 @@ 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
+
from django import forms
from django.conf import settings
from django.http import Http404
from django.shortcuts import render_to_response
from django.template.context import RequestContext
-import cPickle as pickle
-import md5
+from django.utils.hashcompat import md5_constructor
class FormWizard(object):
# Dictionary of extra template context variables.
@@ -150,7 +151,7 @@ class FormWizard(object):
# Use HIGHEST_PROTOCOL because it's the most efficient. It requires
# Python 2.3, but Django requires 2.3 anyway, so that's OK.
pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
- return md5.new(pickled).hexdigest()
+ return md5_constructor(pickled).hexdigest()
def determine_step(self, request, *args, **kwargs):
"""
diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py
index b40fba6e6e..7153b8a267 100644
--- a/django/contrib/sessions/backends/base.py
+++ b/django/contrib/sessions/backends/base.py
@@ -1,5 +1,4 @@
import base64
-import md5
import os
import random
import sys
@@ -12,6 +11,7 @@ except ImportError:
from django.conf import settings
from django.core.exceptions import SuspiciousOperation
+from django.utils.hashcompat import md5_constructor
class SessionBase(object):
@@ -73,13 +73,13 @@ class SessionBase(object):
def encode(self, session_dict):
"Returns the given session dictionary pickled and encoded as a string."
pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
- pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
+ pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
return base64.encodestring(pickled + pickled_md5)
def decode(self, session_data):
encoded_data = base64.decodestring(session_data)
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
- if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
+ if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
raise SuspiciousOperation("User tampered with session cookie.")
try:
return pickle.loads(pickled)
@@ -117,8 +117,8 @@ class SessionBase(object):
# No getpid() in Jython, for example
pid = 1
while 1:
- session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1),
- pid, time.time(), settings.SECRET_KEY)).hexdigest()
+ session_key = md5_constructor("%s%s%s%s" % (random.randint(0, sys.maxint - 1),
+ pid, time.time(), settings.SECRET_KEY)).hexdigest()
if not self.exists(session_key):
break
return session_key
diff --git a/django/contrib/sessions/models.py b/django/contrib/sessions/models.py
index 70fce3b226..cf2865fcc8 100644
--- a/django/contrib/sessions/models.py
+++ b/django/contrib/sessions/models.py
@@ -1,10 +1,10 @@
import base64
-import md5
import cPickle as pickle
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
+from django.utils.hashcompat import md5_constructor
class SessionManager(models.Manager):
@@ -13,7 +13,7 @@ class SessionManager(models.Manager):
Returns the given session dictionary pickled and encoded as a string.
"""
pickled = pickle.dumps(session_dict)
- pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
+ pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
return base64.encodestring(pickled + pickled_md5)
def save(self, session_key, session_dict, expire_date):
@@ -56,7 +56,7 @@ class Session(models.Model):
def get_decoded(self):
encoded_data = base64.decodestring(self.session_data)
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
- if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
+ if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
from django.core.exceptions import SuspiciousOperation
raise SuspiciousOperation, "User tampered with session cookie."
try:
diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py
index c1277bf20c..0ad586d477 100644
--- a/django/core/cache/backends/filebased.py
+++ b/django/core/cache/backends/filebased.py
@@ -1,29 +1,31 @@
"File-based cache backend"
-import md5
-import os, time
+import os
+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 CacheClass(BaseCache):
def __init__(self, dir, params):
BaseCache.__init__(self, params)
-
+
max_entries = params.get('max_entries', 300)
try:
self._max_entries = int(max_entries)
except (ValueError, TypeError):
self._max_entries = 300
-
+
cull_frequency = params.get('cull_frequency', 3)
try:
self._cull_frequency = int(cull_frequency)
except (ValueError, TypeError):
self._cull_frequency = 3
-
+
self._dir = dir
if not os.path.exists(self._dir):
self._createdir()
@@ -31,7 +33,7 @@ class CacheClass(BaseCache):
def add(self, key, value, timeout=None):
if self.has_key(key):
return None
-
+
self.set(key, value, timeout)
def get(self, key, default=None):
@@ -52,12 +54,12 @@ class CacheClass(BaseCache):
def set(self, key, value, timeout=None):
fname = self._key_to_file(key)
dirname = os.path.dirname(fname)
-
+
if timeout is None:
timeout = self.default_timeout
-
+
self._cull()
-
+
try:
if not os.path.exists(dirname):
os.makedirs(dirname)
@@ -103,12 +105,12 @@ class CacheClass(BaseCache):
def _cull(self):
if int(self._num_entries) < self._max_entries:
return
-
+
try:
filelist = os.listdir(self._dir)
except (IOError, OSError):
return
-
+
if self._cull_frequency == 0:
doomed = filelist
else:
@@ -133,11 +135,11 @@ class CacheClass(BaseCache):
Convert the filename into an md5 string. We'll turn the first couple
bits of the path into directory prefixes to be nice to filesystems
that have problems with large numbers of files in a directory.
-
+
Thus, a cache key of "foo" gets turnned into a file named
``{cache-dir}ac/bd/18db4cc2f85cedef654fccc4a4d8``.
"""
- path = md5.new(key.encode('utf-8')).hexdigest()
+ path = md5_constructor(key.encode('utf-8')).hexdigest()
path = os.path.join(path[:2], path[2:4], path[4:])
return os.path.join(self._dir, path)
@@ -147,4 +149,3 @@ class CacheClass(BaseCache):
count += len(files)
return count
_num_entries = property(_get_num_entries)
-
diff --git a/django/db/backends/util.py b/django/db/backends/util.py
index 25b41e3fb6..7228b4046b 100644
--- a/django/db/backends/util.py
+++ b/django/db/backends/util.py
@@ -1,7 +1,8 @@
import datetime
-import md5
from time import time
+from django.utils.hashcompat import md5_constructor
+
try:
import decimal
except ImportError:
@@ -114,7 +115,7 @@ def truncate_name(name, length=None):
if length is None or len(name) <= length:
return name
- hash = md5.md5(name).hexdigest()[:4]
+ hash = md5_constructor(name).hexdigest()[:4]
return '%s%s' % (name[:length-4], hash)
diff --git a/django/middleware/common.py b/django/middleware/common.py
index 5cb7ca1bd3..a564017ed6 100644
--- a/django/middleware/common.py
+++ b/django/middleware/common.py
@@ -1,4 +1,3 @@
-import md5
import re
from django.conf import settings
@@ -6,6 +5,7 @@ from django import http
from django.core.mail import mail_managers
from django.utils.http import urlquote
from django.core import urlresolvers
+from django.utils.hashcompat import md5_constructor
class CommonMiddleware(object):
"""
@@ -21,7 +21,7 @@ class CommonMiddleware(object):
slash, and it is not found in urlpatterns, a new URL is formed by
appending a slash at the end. If this new URL is found in
urlpatterns, then an HTTP-redirect is returned to this new URL;
- otherwise the initial URL is processed as usual.
+ otherwise the initial URL is processed as usual.
- ETags: If the USE_ETAGS setting is set, ETags will be calculated from
the entire page content and Not Modified responses will be returned
@@ -108,7 +108,7 @@ class CommonMiddleware(object):
if response.has_header('ETag'):
etag = response['ETag']
else:
- etag = '"%s"' % md5.new(response.content).hexdigest()
+ etag = '"%s"' % md5_constructor(response.content).hexdigest()
if response.status_code >= 200 and response.status_code < 300 and request.META.get('HTTP_IF_NONE_MATCH') == etag:
cookies = response.cookies
response = http.HttpResponseNotModified()
diff --git a/django/utils/cache.py b/django/utils/cache.py
index 603199cc7e..78063c6b11 100644
--- a/django/utils/cache.py
+++ b/django/utils/cache.py
@@ -17,7 +17,6 @@ An example: i18n middleware would need to distinguish caches by the
"Accept-language" header.
"""
-import md5
import re
import time
try:
@@ -29,6 +28,7 @@ from django.conf import settings
from django.core.cache import cache
from django.utils.encoding import smart_str, iri_to_uri
from django.utils.http import http_date
+from django.utils.hashcompat import md5_constructor
cc_delim_re = re.compile(r'\s*,\s*')
@@ -104,7 +104,7 @@ def patch_response_headers(response, cache_timeout=None):
if cache_timeout < 0:
cache_timeout = 0 # Can't have max-age negative
if not response.has_header('ETag'):
- response['ETag'] = '"%s"' % md5.new(response.content).hexdigest()
+ response['ETag'] = '"%s"' % md5_constructor(response.content).hexdigest()
if not response.has_header('Last-Modified'):
response['Last-Modified'] = http_date()
if not response.has_header('Expires'):
@@ -138,7 +138,7 @@ def patch_vary_headers(response, newheaders):
def _generate_cache_key(request, headerlist, key_prefix):
"""Returns a cache key from the headers given in the header list."""
- ctx = md5.new()
+ ctx = md5_constructor()
for header in headerlist:
value = request.META.get(header, None)
if value is not None:
diff --git a/django/utils/hashcompat.py b/django/utils/hashcompat.py
new file mode 100644
index 0000000000..8880d92646
--- /dev/null
+++ b/django/utils/hashcompat.py
@@ -0,0 +1,16 @@
+"""
+The md5 and sha modules are deprecated since Python 2.5, replaced by the
+hashlib module containing both hash algorithms. Here, we provide a common
+interface to the md5 and sha constructors, preferring the hashlib module when
+available.
+"""
+
+try:
+ import hashlib
+ md5_constructor = hashlib.md5
+ sha_constructor = hashlib.sha1
+except ImportError:
+ import md5
+ md5_constructor = md5.new
+ import sha
+ sha_constructor = sha.new
diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
index f050348c77..78c32288b6 100644
--- a/tests/regressiontests/cache/tests.py
+++ b/tests/regressiontests/cache/tests.py
@@ -3,11 +3,17 @@
# Unit tests for cache framework
# Uses whatever cache backend is set in the test settings file.
+import os
+import shutil
+import tempfile
import time
import unittest
+
from django.core.cache import cache
-from django.utils.cache import patch_vary_headers
+from django.core.cache.backends.filebased import CacheClass as FileCache
from django.http import HttpResponse
+from django.utils.cache import patch_vary_headers
+from django.utils.hashcompat import md5_constructor
# functions/classes for complex data type tests
def f():
@@ -27,7 +33,7 @@ class Cache(unittest.TestCase):
cache.add("addkey1", "value")
cache.add("addkey1", "newvalue")
self.assertEqual(cache.get("addkey1"), "value")
-
+
def test_non_existent(self):
# get with non-existent keys
self.assertEqual(cache.get("does_not_exist"), None)
@@ -80,9 +86,9 @@ class Cache(unittest.TestCase):
cache.set('expire2', 'very quickly', 1)
cache.set('expire3', 'very quickly', 1)
- time.sleep(2)
+ time.sleep(2)
self.assertEqual(cache.get("expire1"), None)
-
+
cache.add("expire2", "newvalue")
self.assertEqual(cache.get("expire2"), "newvalue")
self.assertEqual(cache.has_key("expire3"), False)
@@ -98,11 +104,6 @@ class Cache(unittest.TestCase):
cache.set(key, value)
self.assertEqual(cache.get(key), value)
-import os
-import md5
-import shutil
-import tempfile
-from django.core.cache.backends.filebased import CacheClass as FileCache
class FileBasedCacheTests(unittest.TestCase):
"""
@@ -112,23 +113,23 @@ class FileBasedCacheTests(unittest.TestCase):
self.dirname = tempfile.mktemp()
os.mkdir(self.dirname)
self.cache = FileCache(self.dirname, {})
-
+
def tearDown(self):
shutil.rmtree(self.dirname)
-
+
def test_hashing(self):
"""Test that keys are hashed into subdirectories correctly"""
self.cache.set("foo", "bar")
- keyhash = md5.new("foo").hexdigest()
+ keyhash = md5_constructor("foo").hexdigest()
keypath = os.path.join(self.dirname, keyhash[:2], keyhash[2:4], keyhash[4:])
self.assert_(os.path.exists(keypath))
-
+
def test_subdirectory_removal(self):
"""
Make sure that the created subdirectories are correctly removed when empty.
"""
self.cache.set("foo", "bar")
- keyhash = md5.new("foo").hexdigest()
+ keyhash = md5_constructor("foo").hexdigest()
keypath = os.path.join(self.dirname, keyhash[:2], keyhash[2:4], keyhash[4:])
self.assert_(os.path.exists(keypath))
@@ -139,9 +140,9 @@ class FileBasedCacheTests(unittest.TestCase):
class CacheUtils(unittest.TestCase):
"""TestCase for django.utils.cache functions."""
-
+
def test_patch_vary_headers(self):
- headers = (
+ headers = (
# Initial vary, new headers, resulting vary.
(None, ('Accept-Encoding',), 'Accept-Encoding'),
('Accept-Encoding', ('accept-encoding',), 'Accept-Encoding'),
diff --git a/tests/regressiontests/file_uploads/tests.py b/tests/regressiontests/file_uploads/tests.py
index aada1e1ff2..dd6b7c4181 100644
--- a/tests/regressiontests/file_uploads/tests.py
+++ b/tests/regressiontests/file_uploads/tests.py
@@ -1,6 +1,5 @@
import os
import errno
-import sha
import shutil
import unittest
@@ -8,6 +7,7 @@ from django.core.files import temp as tempfile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase, client
from django.utils import simplejson
+from django.utils.hashcompat import sha_constructor
from models import FileModel, UPLOAD_ROOT, UPLOAD_TO
@@ -45,10 +45,10 @@ class FileUploadTests(TestCase):
for key in post_data.keys():
try:
- post_data[key + '_hash'] = sha.new(post_data[key].read()).hexdigest()
+ post_data[key + '_hash'] = sha_constructor(post_data[key].read()).hexdigest()
post_data[key].seek(0)
except AttributeError:
- post_data[key + '_hash'] = sha.new(post_data[key]).hexdigest()
+ post_data[key + '_hash'] = sha_constructor(post_data[key]).hexdigest()
response = self.client.post('/file_uploads/verify/', post_data)
diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py
index 47e34641fb..3518df3b9f 100644
--- a/tests/regressiontests/test_client_regress/models.py
+++ b/tests/regressiontests/test_client_regress/models.py
@@ -1,12 +1,10 @@
"""
Regression tests for the Test Client, especially the customized assertions.
-
"""
+
from django.test import Client, TestCase
from django.core.urlresolvers import reverse
from django.core.exceptions import SuspiciousOperation
-import os
-import sha
class AssertContainsTests(TestCase):
def test_contains(self):
@@ -24,7 +22,7 @@ class AssertContainsTests(TestCase):
self.assertNotContains(response, 'once')
except AssertionError, e:
self.assertEquals(str(e), "Response should not contain 'once'")
-
+
try:
self.assertContains(response, 'never', 1)
except AssertionError, e:
@@ -287,7 +285,7 @@ class URLEscapingTests(TestCase):
class ExceptionTests(TestCase):
fixtures = ['testdata.json']
-
+
def test_exception_cleared(self):
"#5836 - A stale user exception isn't re-raised by the test client."
@@ -300,7 +298,7 @@ class ExceptionTests(TestCase):
pass
# At this point, an exception has been raised, and should be cleared.
-
+
# This next operation should be successful; if it isn't we have a problem.
login = self.client.login(username='staff', password='password')
self.failUnless(login, 'Could not log in')