Permalink
Browse files

upgraded to Django 1.4.1

  • Loading branch information...
1 parent 1c48552 commit 1f8356ddd1db8cef04f453881b3012e006cdce57 @peterbe peterbe committed Jul 31, 2012
@@ -1,4 +1,4 @@
-VERSION = (1, 4, 0, 'final', 0)
+VERSION = (1, 4, 1, 'final', 0)
def get_version(version=None):
"""Derives a PEP386-compliant version number from VERSION."""
@@ -23,10 +23,7 @@
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
-# On Unix systems, a value of None will cause Django to use the same
-# timezone as the operating system.
-# If running in a Windows environment this must be set to the same as your
-# system time zone.
+# In a Windows environment this must be set to your system time zone.
TIME_ZONE = 'America/Chicago'
# Language code for this installation. All choices can be found here:
@@ -155,7 +155,10 @@ def create(cls, field, request, params, model, model_admin, field_path):
class RelatedFieldListFilter(FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path):
other_model = get_model_from_relation(field)
- rel_name = other_model._meta.pk.name
+ if hasattr(field, 'rel'):
+ rel_name = field.rel.get_related_field().name
+ else:
+ rel_name = other_model._meta.pk.name
self.lookup_kwarg = '%s__%s__exact' % (field_path, rel_name)
self.lookup_kwarg_isnull = '%s__isnull' % field_path
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
@@ -245,7 +245,7 @@ def lookup_allowed(self, lookup, value):
# if foo has been specificially included in the lookup list; so
# drop __id if it is the last part. However, first we need to find
# the pk attribute name.
- pk_attr_name = None
+ rel_name = None
for part in parts[:-1]:
try:
field, _, _, _ = model._meta.get_field_by_name(part)
@@ -255,13 +255,13 @@ def lookup_allowed(self, lookup, value):
return True
if hasattr(field, 'rel'):
model = field.rel.to
- pk_attr_name = model._meta.pk.name
+ rel_name = field.rel.get_related_field().name
elif isinstance(field, RelatedObject):
model = field.model
- pk_attr_name = model._meta.pk.name
+ rel_name = model._meta.pk.name
else:
- pk_attr_name = None
- if pk_attr_name and len(parts) > 1 and parts[-1] == pk_attr_name:
+ rel_name = None
+ if rel_name and len(parts) > 1 and parts[-1] == rel_name:
parts.pop()
if len(parts) == 1:
@@ -41,7 +41,8 @@
text-align: left;
}
-.selector .selector-filter label {
+.selector .selector-filter label,
+.inline-group .aligned .selector .selector-filter label {
width: 16px;
padding: 2px;
}
@@ -258,7 +258,7 @@ def get_ordering(self, request, queryset):
if not (set(ordering) & set(['pk', '-pk', pk_name, '-' + pk_name])):
# The two sets do not intersect, meaning the pk isn't present. So
# we add it.
- ordering.append('pk')
+ ordering.append('-pk')
return ordering
@@ -9,6 +9,7 @@
from django.test.utils import override_settings
from django.utils.encoding import force_unicode
from django.utils import translation
+from django.utils.translation import ugettext as _
class UserCreationFormTest(TestCase):
@@ -333,6 +334,6 @@ def test_unusable_password(self):
form = PasswordResetForm(data)
self.assertFalse(form.is_valid())
self.assertEqual(form["email"].errors,
- [u"The user account associated with this e-mail address cannot reset the password."])
+ [_(u"The user account associated with this e-mail address cannot reset the password.")])
PasswordResetFormTest = override_settings(USE_TZ=False)(PasswordResetFormTest)
@@ -65,8 +65,8 @@ def markdown(value, arg=''):
safe_mode = True
else:
safe_mode = False
- python_markdown_deprecation = "The use of Python-Markdown "
- "< 2.1 in Django is deprecated; please update to the current version"
+ python_markdown_deprecation = ("The use of Python-Markdown "
+ "< 2.1 in Django is deprecated; please update to the current version")
# Unicode support only in markdown v1.7 or above. Version_info
# exist only in markdown v1.6.2rc-2 or above.
markdown_vers = getattr(markdown, "version_info", None)
@@ -190,8 +190,8 @@ def post_process(self, paths, dry_run=False, **options):
if dry_run:
return
- # delete cache of all handled paths
- self.cache.delete_many([self.cache_key(path) for path in paths])
+ # where to store the new paths
+ hashed_paths = {}
# build a list of adjustable files
matches = lambda path: matches_patterns(path, self._patterns.keys())
@@ -240,9 +240,12 @@ def post_process(self, paths, dry_run=False, **options):
hashed_name = force_unicode(saved_name.replace('\\', '/'))
# and then set the cache accordingly
- self.cache.set(self.cache_key(name), hashed_name)
+ hashed_paths[self.cache_key(name)] = hashed_name
yield name, hashed_name, processed
+ # Finally set the cache
+ self.cache.set_many(hashed_paths)
+
class CachedStaticFilesStorage(CachedFilesMixin, StaticFilesStorage):
"""
@@ -47,13 +47,18 @@ def get_image_dimensions(file_or_path, close=False):
file = open(file_or_path, 'rb')
close = True
try:
+ # Most of the time PIL only needs a small chunk to parse the image and
+ # get the dimensions, but with some TIFF files PIL needs to parse the
+ # whole file.
+ chunk_size = 1024
while 1:
- data = file.read(1024)
+ data = file.read(chunk_size)
if not data:
break
p.feed(data)
if p.image:
return p.image.size
+ chunk_size = chunk_size*2
return None
finally:
if close:
@@ -35,4 +35,11 @@ def handle(self, *fixture_labels, **options):
# a strange error -- it causes this handle() method to be called
# multiple times.
shutdown_message = '\nServer stopped.\nNote that the test database, %r, has not been deleted. You can explore it on your own.' % db_name
- call_command('runserver', addrport=addrport, shutdown_message=shutdown_message, use_reloader=False, use_ipv6=options['use_ipv6'])
+ use_threading = connection.features.test_db_allows_multiple_connections
+ call_command('runserver',
+ addrport=addrport,
+ shutdown_message=shutdown_message,
+ use_reloader=False,
+ use_ipv6=options['use_ipv6'],
+ use_threading=use_threading
+ )
@@ -407,11 +407,20 @@ def _rollback(self):
def get_server_version(self):
if not self.server_version:
+ new_connection = False
if not self._valid_connection():
- self.cursor()
- m = server_version_re.match(self.connection.get_server_info())
+ # Ensure we have a connection with the DB by using a temporary
+ # cursor
+ new_connection = True
+ self.cursor().close()
+ server_info = self.connection.get_server_info()
+ if new_connection:
+ # Make sure we close the connection
+ self.connection.close()
+ self.connection = None
+ m = server_version_re.match(server_info)
if not m:
- raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info())
+ raise Exception('Unable to determine MySQL version from version string %r' % server_info)
self.server_version = tuple([int(x) for x in m.groups()])
return self.server_version
@@ -239,7 +239,7 @@ def get_query_set(self, **db_hints):
def get_prefetch_query_set(self, instances):
vals = set(instance._get_pk_val() for instance in instances)
params = {'%s__pk__in' % self.related.field.name: vals}
- return (self.get_query_set(instance=instances[0]),
+ return (self.get_query_set(instance=instances[0]).filter(**params),
attrgetter(self.related.field.attname),
lambda obj: obj._get_pk_val(),
True,
@@ -570,20 +570,10 @@ def to_python(self, data):
file = StringIO(data['content'])
try:
- # load() is the only method that can spot a truncated JPEG,
- # but it cannot be called sanely after verify()
- trial_image = Image.open(file)
- trial_image.load()
-
- # Since we're about to use the file again we have to reset the
- # file object if possible.
- if hasattr(file, 'reset'):
- file.reset()
-
- # verify() is the only method that can spot a corrupt PNG,
- # but it must be called immediately after the constructor
- trial_image = Image.open(file)
- trial_image.verify()
+ # load() could spot a truncated JPEG, but it loads the entire
+ # image in memory, which is a DoS vector. See #3848 and #18520.
+ # verify() must be called immediately after the constructor.
+ Image.open(file).verify()
except ImportError:
# Under PyPy, it is possible to import PIL. However, the underlying
# _imaging C module isn't available, so an ImportError will be
@@ -487,15 +487,18 @@ def _has_changed(self, initial, data):
pass
return super(TimeInput, self)._has_changed(self._format_value(initial), data)
+
+# Defined at module level so that CheckboxInput is picklable (#17976)
+def boolean_check(v):
+ return not (v is False or v is None or v == '')
+
+
class CheckboxInput(Widget):
def __init__(self, attrs=None, check_test=None):
super(CheckboxInput, self).__init__(attrs)
# check_test is a callable that takes a value and returns True
# if the checkbox should be checked for that value.
- if check_test is None:
- self.check_test = lambda v: not (v is False or v is None or v == '')
- else:
- self.check_test = check_test
+ self.check_test = boolean_check if check_test is None else check_test
def render(self, name, value, attrs=None):
final_attrs = self.build_attrs(attrs, type='checkbox', name=name)
@@ -9,7 +9,7 @@
from pprint import pformat
from urllib import urlencode, quote
-from urlparse import urljoin
+from urlparse import urljoin, urlparse
try:
from cStringIO import StringIO
except ImportError:
@@ -114,7 +114,7 @@ def __init__(self, *args, **kwargs):
from django.conf import settings
from django.core import signing
-from django.core.exceptions import ImproperlyConfigured
+from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
from django.core.files import uploadhandler
from django.http.multipartparser import MultiPartParser
from django.http.utils import *
@@ -731,19 +731,21 @@ def tell(self):
raise Exception("This %s instance cannot tell its position" % self.__class__)
return sum([len(str(chunk)) for chunk in self._container])
-class HttpResponseRedirect(HttpResponse):
- status_code = 302
+class HttpResponseRedirectBase(HttpResponse):
+ allowed_schemes = ['http', 'https', 'ftp']
def __init__(self, redirect_to):
- super(HttpResponseRedirect, self).__init__()
+ super(HttpResponseRedirectBase, self).__init__()
+ parsed = urlparse(redirect_to)
+ if parsed.scheme and parsed.scheme not in self.allowed_schemes:
+ raise SuspiciousOperation("Unsafe redirect to URL with scheme '%s'" % parsed.scheme)
self['Location'] = iri_to_uri(redirect_to)
-class HttpResponsePermanentRedirect(HttpResponse):
- status_code = 301
+class HttpResponseRedirect(HttpResponseRedirectBase):
+ status_code = 302
- def __init__(self, redirect_to):
- super(HttpResponsePermanentRedirect, self).__init__()
- self['Location'] = iri_to_uri(redirect_to)
+class HttpResponsePermanentRedirect(HttpResponseRedirectBase):
+ status_code = 301
class HttpResponseNotModified(HttpResponse):
status_code = 304
@@ -1143,4 +1143,11 @@ def tearDownClass(cls):
if hasattr(cls, 'server_thread'):
# Terminate the live server's thread
cls.server_thread.join()
+
+ # Restore sqlite connections' non-sharability
+ for conn in connections.all():
+ if (conn.settings_dict['ENGINE'] == 'django.db.backends.sqlite3'
+ and conn.settings_dict['NAME'] == ':memory:'):
+ conn.allow_thread_sharing = False
+
super(LiveServerTestCase, cls).tearDownClass()
@@ -155,9 +155,20 @@ def get_traceback_frame_variables(self, request, tb_frame):
Replaces the values of variables marked as sensitive with
stars (*********).
"""
- func_name = tb_frame.f_code.co_name
- func = tb_frame.f_globals.get(func_name)
- sensitive_variables = getattr(func, 'sensitive_variables', [])
+ # Loop through the frame's callers to see if the sensitive_variables
+ # decorator was used.
+ current_frame = tb_frame.f_back
+ sensitive_variables = None
+ while current_frame is not None:
+ if (current_frame.f_code.co_name == 'sensitive_variables_wrapper'
+ and 'sensitive_variables_wrapper' in current_frame.f_locals):
+ # The sensitive_variables decorator was used, so we take note
+ # of the sensitive variables' names.
+ wrapper = current_frame.f_locals['sensitive_variables_wrapper']
+ sensitive_variables = getattr(wrapper, 'sensitive_variables', None)
+ break
+ current_frame = current_frame.f_back
+
cleansed = []
if self.is_active(request) and sensitive_variables:
if sensitive_variables == '__ALL__':
@@ -26,13 +26,13 @@ def my_function()
"""
def decorator(func):
@functools.wraps(func)
- def wrapper(*args, **kwargs):
+ def sensitive_variables_wrapper(*args, **kwargs):
if variables:
- wrapper.sensitive_variables = variables
+ sensitive_variables_wrapper.sensitive_variables = variables
else:
- wrapper.sensitive_variables = '__ALL__'
+ sensitive_variables_wrapper.sensitive_variables = '__ALL__'
return func(*args, **kwargs)
- return wrapper
+ return sensitive_variables_wrapper
return decorator
@@ -61,11 +61,11 @@ def my_view(request)
"""
def decorator(view):
@functools.wraps(view)
- def wrapper(request, *args, **kwargs):
+ def sensitive_post_parameters_wrapper(request, *args, **kwargs):
if parameters:
request.sensitive_post_parameters = parameters
else:
request.sensitive_post_parameters = '__ALL__'
return view(request, *args, **kwargs)
- return wrapper
+ return sensitive_post_parameters_wrapper
return decorator

0 comments on commit 1f8356d

Please sign in to comment.