Ticket #20757: patch_commit_8a8468f33b16.patch

File patch_commit_8a8468f33b16.patch, 7.0 KB (added by Flavio Curella, 11 years ago)

handle IndexError correctly

  • django/core/urlresolvers.py

    diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
    index b7017e47b91115db23f2406d0b4a825ca55a272a..f599cf83ddf2ec19e5ea4b8a8b19bce2adba595a 100644
    a b from threading import local  
    1313
    1414from django.http import Http404
    1515from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
    16 from django.utils.datastructures import MultiValueDict
     16from django.utils.datastructures import MultiValueDict, NameIndexedIterable
    1717from django.utils.encoding import force_str, force_text, iri_to_uri
    1818from django.utils.functional import memoize, lazy
    1919from django.utils.http import urlquote
    class RegexURLPattern(LocaleRegexProvider):  
    229229        self._callback = get_callable(self._callback_str)
    230230        return self._callback
    231231
     232
     233class URLEntry(NameIndexedIterable):
     234    state_class = tuple
     235    keys = ('urlbits', 'p_pattern', 'pattern.default')
     236
     237    def __repr__(self):
     238        return "<URLEntry: %s>" % self.state.__repr__()
     239
     240
     241class URLBit(NameIndexedIterable):
     242    state_class = tuple
     243    keys = ('format', 'argument_names')
     244
     245    def __repr__(self):
     246        return "<URLBit: %s>" % self.state.__repr__()
     247
     248
    232249class RegexURLResolver(LocaleRegexProvider):
    233250    def __init__(self, regex, urlconf_name, default_kwargs=None, app_name=None, namespace=None):
    234251        LocaleRegexProvider.__init__(self, regex)
    class RegexURLResolver(LocaleRegexProvider):  
    269286                    if pattern.app_name:
    270287                        apps.setdefault(pattern.app_name, []).append(pattern.namespace)
    271288                else:
    272                     parent = normalize(pattern.regex.pattern)
     289                    parent = [URLBit(*p) for p in normalize(pattern.regex.pattern)]
    273290                    for name in pattern.reverse_dict:
    274291                        for matches, pat, defaults in pattern.reverse_dict.getlist(name):
    275292                            new_matches = []
    276293                            for piece, p_args in parent:
    277                                 new_matches.extend([(piece + suffix, p_args + args) for (suffix, args) in matches])
    278                             lookups.appendlist(name, (new_matches, p_pattern + pat, dict(defaults, **pattern.default_kwargs)))
     294                                new_matches.extend([URLBit(piece + suffix, p_args + args) for (suffix, args) in matches])
     295                            lookups.appendlist(name, URLEntry(new_matches, p_pattern + pat, dict(defaults, **pattern.default_kwargs)))
    279296                    for namespace, (prefix, sub_pattern) in pattern.namespace_dict.items():
    280297                        namespaces[namespace] = (p_pattern + prefix, sub_pattern)
    281298                    for app_name, namespace_list in pattern.app_dict.items():
    282299                        apps.setdefault(app_name, []).extend(namespace_list)
    283300            else:
    284                 bits = normalize(p_pattern)
    285                 lookups.appendlist(pattern.callback, (bits, p_pattern, pattern.default_args))
     301                bits = [URLBit(*p) for p in normalize(p_pattern)]
     302                lookups.appendlist(pattern.callback, URLEntry(bits, p_pattern, pattern.default_args))
    286303                if pattern.name is not None:
    287                     lookups.appendlist(pattern.name, (bits, p_pattern, pattern.default_args))
     304                    lookups.appendlist(pattern.name, URLEntry(bits, p_pattern, pattern.default_args))
    288305        self._reverse_dict[language_code] = lookups
    289306        self._namespace_dict[language_code] = namespaces
    290307        self._app_dict[language_code] = apps
    def is_valid_path(path, urlconf=None):  
    574591        return True
    575592    except Resolver404:
    576593        return False
     594
     595def get_urlformat(urlname):
     596    """
     597    Given a URL name, returns the URL as a string suitable for string.format.
     598
     599    Example::
     600
     601    urlpatterns = patterns('',
     602        url(r'^extra/(?P<extra>\w+)/$', empty_view, name="named-url2"),
     603    )
     604
     605    >>> get_urlformat('named-url2')
     606    '/extra/%(extra)s/'
     607    """
     608    urlconf = get_urlconf()
     609    resolver = get_resolver(urlconf)
     610    urlbit = resolver.reverse_dict[urlname].urlbits[0]
     611    return "%s%s" % (get_script_prefix(), urlbit.format)
  • django/utils/datastructures.py

    diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py
    index 3b1638392c08bf5fed640cdea67d5559a971a584..779f90b3af1e039cd66656933a9915eb972752ee 100644
    a b class DictWrapper(dict):  
    496496        if use_func:
    497497            return self.func(value)
    498498        return value
     499
     500
     501class NameIndexedIterable(object):
     502    """
     503    An Iterable (most likely a list or tuple), whose indexes can be referred
     504    by name.
     505    """
     506    state_class = list
     507    keys = list()
     508
     509    def __init__(self, *args, **kwargs):
     510        updated_args = list(args)
     511        for i, keyword in enumerate(self.keys):
     512            if keyword in kwargs:
     513                updated_args[i] = kwargs[keyword]
     514            else:
     515                break
     516        self.state = self.state_class(updated_args)
     517        super(NameIndexedIterable, self).__init__()
     518
     519    def __getitem__(self, index):
     520        if index < len(self.state):
     521            return self.state[index]
     522        raise IndexError
     523
     524    def __setitem__(self, index, value):
     525        if index < len(self.state):
     526            self.state[index] = value
     527        raise IndexError
     528
     529    def __getattr__(self, attr):
     530        if attr in self.keys:
     531            return self.state[self.keys.index(attr)]
     532        return super(NameIndexedIterable, self).__getattr__(attr)
     533
     534    def __setattr__(self, attr, value):
     535        if attr in self.keys:
     536            self.state[self.keys.index(attr)] = value
     537        return super(NameIndexedIterable, self).__setattr__(attr, value)
     538
     539    def __repr__(self):
     540        return self.state.__repr__()
  • tests/urlpatterns_reverse/tests.py

    diff --git a/tests/urlpatterns_reverse/tests.py b/tests/urlpatterns_reverse/tests.py
    index 222ebe053b1362afca1c9962cc2b4e3fbc908b55..e265e7659e26bc305cd93a23f7491a3721a72965 100644
    a b from django.conf import settings  
    99from django.contrib.auth.models import User
    1010from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
    1111from django.core.urlresolvers import (reverse, resolve, get_callable,
    12     get_resolver, NoReverseMatch, Resolver404, ResolverMatch, RegexURLResolver,
    13     RegexURLPattern)
     12    get_resolver, get_urlformat, NoReverseMatch, Resolver404, ResolverMatch,
     13    RegexURLResolver, RegexURLPattern)
    1414from django.http import HttpRequest, HttpResponseRedirect, HttpResponsePermanentRedirect
    1515from django.shortcuts import redirect
    1616from django.test import TestCase
    class ViewLoadingTests(TestCase):  
    644644        self.assertRaises(AttributeError, get_callable,
    645645            'urlpatterns_reverse.views_broken.i_am_broken')
    646646
     647
     648class URLObjects(TestCase):
     649    urls = 'urlpatterns_reverse.named_urls'
     650
     651    def test_URL_objects(self):
     652        format = get_urlformat('named-url2')
     653        self.assertEqual(format, '/extra/%(extra)s/')
Back to Top