From b63ae5c60619a257ad57cf6043e71f681283e47b Mon Sep 17 00:00:00 2001 From: Preston Timmons Date: Tue, 22 Apr 2014 20:19:46 +0000 Subject: [PATCH] Fixed #22486 -- Reverse raises AttributeError on partial functions. Create the lookup_str from the original function whenever a partial is provided as an argument to a url pattern. --- django/core/urlresolvers.py | 4 ++++ tests/urlpatterns_reverse/urls.py | 6 +++++- tests/urlpatterns_reverse/views.py | 10 ++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index eebe54e..8ca602c 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -8,6 +8,7 @@ """ from __future__ import unicode_literals +import functools from importlib import import_module import re from threading import local @@ -270,6 +271,9 @@ def _populate(self): self._callback_strs.add(pattern._callback_str) elif hasattr(pattern, '_callback'): callback = pattern._callback + if isinstance(callback, functools.partial): + callback = callback.func + if not hasattr(callback, '__name__'): lookup_str = callback.__module__ + "." + callback.__class__.__name__ else: diff --git a/tests/urlpatterns_reverse/urls.py b/tests/urlpatterns_reverse/urls.py index d7dd6b6..05b925d 100644 --- a/tests/urlpatterns_reverse/urls.py +++ b/tests/urlpatterns_reverse/urls.py @@ -2,7 +2,7 @@ from django.conf.urls import patterns, url, include -from .views import empty_view, absolute_kwargs_view +from .views import empty_view, empty_view_partial, empty_view_wrapped, absolute_kwargs_view other_patterns = [ @@ -54,6 +54,10 @@ url(r'^outer-no-kwargs/([0-9]+)/', include('urlpatterns_reverse.included_no_kwargs_urls')), url('', include('urlpatterns_reverse.extra_urls')), + # Partials should be fine. + url(r'^partial/', empty_view_partial, name="partial"), + url(r'^partial_wrapped/', empty_view_wrapped, name="partial_wrapped"), + # This is non-reversible, but we shouldn't blow up when parsing it. url(r'^(?:foo|bar)(\w+)/$', empty_view, name="disjunction"), diff --git a/tests/urlpatterns_reverse/views.py b/tests/urlpatterns_reverse/views.py index 610feb8..efd5689 100644 --- a/tests/urlpatterns_reverse/views.py +++ b/tests/urlpatterns_reverse/views.py @@ -1,3 +1,5 @@ +from functools import partial, update_wrapper + from django.http import HttpResponse from django.views.generic import RedirectView from django.core.urlresolvers import reverse_lazy @@ -55,3 +57,11 @@ def login_required_view(request): def bad_view(request, *args, **kwargs): raise ValueError("I don't think I'm getting good value for this view") + + +empty_view_partial = partial(empty_view, template_name="template.html") + + +empty_view_wrapped = update_wrapper( + partial(empty_view, template_name="template.html"), empty_view, +) -- 1.9.1