Opened 16 years ago
Closed 16 years ago
#11190 closed (invalid)
urlresolvers.reverse: possibilities = self.reverse_dict.getlist(lookup_view) is empty but everything else seems to work
| Reported by: | Owned by: | nobody | |
|---|---|---|---|
| Component: | Core (Other) | Version: | 1.0 |
| Severity: | Keywords: | urlresolvers reverse possibilities self.reverse_dict.getlist() permalink | |
| Cc: | '1.0.2 final', debian version | Triage Stage: | Unreviewed |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
I've think i've found a bug with urlresolvers.reverse() (in use with permalink).
I've tried to get this code working:
_CONTENT_VIEW = "page.views.view_by_content"
_CONTENT_VIEW_KWARG_ID_NAME = "content_id"
*snip*
# Point to content with default id
@property
@models.permalink
def link(self):
"""Return link to content with
Page calculated default content id.
"""
return (self._CONTENT_VIEW, (),
{self._CONTENT_VIEW_KWARG_ID_NAME:
self.to_object.get_default_content_id()})
And some method that is similar but in another subclass from this classes superclass.
My urls.py and page/urls.py are looking like this:
urlpatterns = patterns('',
# Example:
# (r'^evankproj/', include('evankproj.foo.urls')),
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
(r'^admin/(.*)', admin.site.root),
(r"^content/", include("evankproj.page.urls")),
*snip*
and
urlpatterns = patterns("evankproj.page.views",
(r"^$", "index"),
(r"^(?P<content_id>\d+)/$", "view_by_content"),
)
Here is a pdb session where i tried to track down the problem, I entered
from within my link method:
Quit the server with CONTROL-C.
> *snip*page/models.py(258)link()
-> return (self._CONTENT_VIEW, (),
(Pdb) up
> /usr/lib/pymodules/python2.5/django/db/models/__init__.py(29)inner()
-> bits = func(*args, **kwargs)
(Pdb) list
24 (viewname, viewargs)
25 (viewname, viewargs, viewkwargs)
26 """
27 from django.core.urlresolvers import reverse
28 def inner(*args, **kwargs):
29 -> bits = func(*args, **kwargs)
30 return reverse(bits[0], None, *bits[1:3])
31 return inner
[EOF]
(Pdb) list 20
15 ADD, CHANGE, BOTH = 1, 2, 3
16
17 def permalink(func):
18 """
19 Decorator that calls urlresolvers.reverse() to return a URL using
20 parameters returned by the decorated function "func".
21
22 "func" should be a function that returns a tuple in one of the
23 following formats:
24 (viewname, viewargs)
25 (viewname, viewargs, viewkwargs)
(Pdb) next
> /usr/lib/pymodules/python2.5/django/db/models/__init__.py(30)inner()
-> return reverse(bits[0], None, *bits[1:3])
(Pdb) p bits
('page.views.view_by_content', (), {'content_id': 1})
(Pdb) p bits[1:3]
((), {'content_id': 1})
(Pdb) next
NoReverseMatch: NoRevers...found.",)
> /usr/lib/pymodules/python2.5/django/db/models/__init__.py(30)inner()
-> return reverse(bits[0], None, *bits[1:3])
(Pdb) down
> /usr/lib/pymodules/python2.5/django/core/urlresolvers.py(254)reverse()
-> *args, **kwargs)))
(Pdb) list
249 args = args or []
250 kwargs = kwargs or {}
251 if prefix is None:
252 prefix = get_script_prefix()
253 return iri_to_uri(u'%s%s' % (prefix, get_resolver(urlconf).reverse(viewname,
254 -> *args, **kwargs)))
255
256 def clear_url_caches():
257 global _resolver_cache
258 global _callable_cache
259 _resolver_cache.clear()
(Pdb) p prefiyx
*** NameError: NameError("name 'prefiyx' is not defined",)
(Pdb) prefix
u'/'
(Pdb) down
> /usr/lib/pymodules/python2.5/django/core/urlresolvers.py(243)reverse()
-> "arguments '%s' not found." % (lookup_view, args, kwargs))
(Pdb) p lookup_view
<function view_by_content at 0x93ad6bc>
(Pdb) p lookup_view(1)
*** TypeError: TypeError('view_by_content() takes exactly 2 arguments (1 given)',)
(Pdb) p lookup_view("x", content_id=1)
<django.http.HttpResponse object at 0x947deac>
(Pdb) list
238 unicode_kwargs = dict([(k, force_unicode(v)) for (k, v) in kwargs.items()])
239 candidate = result % unicode_kwargs
240 if re.search(u'^%s' % pattern, candidate, re.UNICODE):
241 return candidate
242 raise NoReverseMatch("Reverse for '%s' with arguments '%s' and keyword "
243 -> "arguments '%s' not found." % (lookup_view, args, kwargs))
244
245 def resolve(path, urlconf=None):
246 return get_resolver(urlconf).resolve(path)
247
248 def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None):
(Pdb) p args
()
(Pdb) kwargs
{'content_id': 1}
(Pdb) p lookup_view(*(), **kwargs)
*** TypeError: TypeError('view_by_content() takes exactly 2 non-keyword arguments (0 given)',)
(Pdb) p lookup_view("x", **kwargs)
<django.http.HttpResponse object at 0x93b1f8c>
(Pdb) list
249 args = args or []
250 kwargs = kwargs or {}
251 if prefix is None:
252 prefix = get_script_prefix()
253 return iri_to_uri(u'%s%s' % (prefix, get_resolver(urlconf).reverse(viewname,
254 *args, **kwargs)))
255
256 def clear_url_caches():
257 global _resolver_cache
258 global _callable_cache
259 _resolver_cache.clear()
(Pdb) down
*** Newest frame
(Pdb) list
260 _callable_cache.clear()
261
262 def set_script_prefix(prefix):
263 """
264 Sets the script prefix for the current thread.
265 """
266 if not prefix.endswith('/'):
267 prefix += '/'
268 _prefixes[currentThread()] = prefix
269
270 def get_script_prefix():
(Pdb) list cur
*** Error in argument: 'cur'
(Pdb) list 24
19
20 try:
21 reversed
22 except NameError:
23 from django.utils.itercompat import reversed # Python 2.3 fallback
24 from sets import Set as set
25
26 _resolver_cache = {} # Maps urlconf modules to RegexURLResolver instances.
27 _callable_cache = {} # Maps view and url pattern names to their view functions.
28
29 # SCRIPT_NAME prefixes for each thread are stored here. If there's no entry for
(Pdb) list 243
238 unicode_kwargs = dict([(k, force_unicode(v)) for (k, v) in kwargs.items()])
239 candidate = result % unicode_kwargs
240 if re.search(u'^%s' % pattern, candidate, re.UNICODE):
241 return candidate
242 raise NoReverseMatch("Reverse for '%s' with arguments '%s' and keyword "
243 -> "arguments '%s' not found." % (lookup_view, args, kwargs))
244
245 def resolve(path, urlconf=None):
246 return get_resolver(urlconf).resolve(path)
247
248 def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None):
(Pdb) list 238
233 unicode_args = [force_unicode(val) for val in args]
234 candidate = result % dict(zip(params, unicode_args))
235 else:
236 if set(kwargs.keys()) != set(params):
237 continue
238 unicode_kwargs = dict([(k, force_unicode(v)) for (k, v) in kwargs.items()])
239 candidate = result % unicode_kwargs
240 if re.search(u'^%s' % pattern, candidate, re.UNICODE):
241 return candidate
242 raise NoReverseMatch("Reverse for '%s' with arguments '%s' and keyword "
243 -> "arguments '%s' not found." % (lookup_view, args, kwargs))
(Pdb) p params
*** NameError: NameError("name 'params' is not defined",)
(Pdb) p set(params)
*** NameError: NameError("name 'params' is not defined",)
(Pdb) p kwargs
{'content_id': 1}
(Pdb) dict(k, force_unicode(v)) for k, v in kwargs.items())
*** SyntaxError: invalid syntax (<stdin>, line 1)
(Pdb) dict((k, force_unicode(v)) for k, v in kwargs.items())
{'content_id': u'1'}
(Pdb) list 230
225 except (ImportError, AttributeError), e:
226 raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e))
227 possibilities = self.reverse_dict.getlist(lookup_view)
228 for possibility, pattern in possibilities:
229 for result, params in possibility:
230 if args:
231 if len(args) != len(params):
232 continue
233 unicode_args = [force_unicode(val) for val in args]
234 candidate = result % dict(zip(params, unicode_args))
235 else:
(Pdb) p possibilities
[]
(Pdb) p self
<RegexURLResolver evankproj.urls ^/>
(Pdb) p self.reverse_dict
<MultiValueDict: {None: [([(u'images/%(path)s', ['path'])], 'images/(?P<path>.*)$'), ([(u'css/%(path)s', ['path'])], 'css/(?P<path>.*)$'), ([(u'content/%(content_id)s/', ['content_id'])], 'content/(?P<content_id>\\d+)/$'), ([(u'content/', [])], 'content/$'), ([(u'admin/%(_0)s', ['_0'])], 'admin/(.*)')], <functools.partial object at 0x93a64dc>: [([(u'content/', [])], 'content/$')], <function view_by_content at 0x93a1b8c>: [([(u'content/%(content_id)s/', ['content_id'])], 'content/(?P<content_id>\\d+)/$')], <function serve at 0x93ad924>: [([(u'images/%(path)s', ['path'])], 'images/(?P<path>.*)$'), ([(u'css/%(path)s', ['path'])], 'css/(?P<path>.*)$')], <bound method AdminSite.root of <django.contrib.admin.sites.AdminSite object at 0x92ca10c>>: [([(u'admin/%(_0)s', ['_0'])], 'admin/(.*)')]}>
(Pdb) p self.reverse_dict.getlist(lookup_view)
[]
As far as i could see, property is no problem in conjunction with permalink, as an inner func gets created and returned. Also, get_absolute_url as name is no requirement for permalink (as you may think after reading the permalink documentation). So, technically this should work.
The function view_by_content gets found, so searching for it works. possibilities is empty, which is self.reverse_dict.getlist(lookup_view), so here seems to be the bug (if it is one). The for loop never gets entered and the raise statements gets executed.
The problem seems to be completly related about this, as this is a change i just made in my mercurial (revision control) repository and nothing but this changed.
Wow, that's one full-on ugly ticket description :P
I'm going to mark invalid as I can't see the problem which this ticket is attempting to address.
Firstly, perhaps _CONTENT_VIEW should really be "evankproj.page.views.view_by_content"? In any case, you should just be using a named url pattern.
I'd ask about this in IRC or the google group. If it does turn out you have discovered a Django bug, open a new ticket with only the relevant bits which show the problem (or if you're game, attach a test case which shows the bug)