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)