tuskar-ui/horizon/utils/reverse_bugfix.py
Gabriel Hurley 052aa55d34 Unifies the project packaging into one set of modules.
There are no longer two separate projects living inside the horizon
repository. There is a single project now with a single setup.py,
single README, etc.

The openstack-dashboard/dashboard django project is now named
"openstack_dashboard" and lives as an example project in the
topmost horizon directory.

The "horizon/horizon" directory has been bumped up a level and now
is directly on the path when the root horizon directory is on
your python path.

Javascript media which the horizon module directly relies upon
now ships in the horizon/static dir rather than
openstack-dashboard/dashboard/static.

All the corresponding setup, installation, build, and env scripts
have been updated accordingly.

Implements blueprint unified-packaging.

Change-Id: Ieed8e3c777432cd046c3e0298869a9428756ab62
2012-02-29 00:20:13 -08:00

184 lines
8.3 KiB
Python

"""
Bugfix for issue #15900: https://code.djangoproject.com/ticket/15900.
This code is largely reproduced from
https://code.djangoproject.com/browser/django/trunk/django/core/urlresolvers.py
and is the work of Django's authors:
https://code.djangoproject.com/browser/django/trunk/AUTHORS
It is licensed under Django's BSD license, available here:
https://code.djangoproject.com/browser/django/trunk/LICENSE
To use, simply import this code in your project's root URLconf file before
defining any URL patterns.
"""
from django.core import urlresolvers
if not hasattr(urlresolvers.RegexURLResolver, "_reverse_with_prefix"):
import re
from django.conf import urls
from django.utils.datastructures import MultiValueDict
from django.utils.encoding import iri_to_uri, force_unicode
from django.utils.regex_helper import normalize
def _populate(self):
lookups = MultiValueDict()
namespaces = {}
apps = {}
for pattern in reversed(self.url_patterns):
p_pattern = pattern.regex.pattern
if p_pattern.startswith('^'):
p_pattern = p_pattern[1:]
if isinstance(pattern, urlresolvers.RegexURLResolver):
if pattern.namespace:
namespaces[pattern.namespace] = (p_pattern, pattern)
if pattern.app_name:
apps.setdefault(pattern.app_name, []) \
.append(pattern.namespace)
else:
parent = normalize(pattern.regex.pattern)
for name in pattern.reverse_dict:
for matches, pat, defaults in \
pattern.reverse_dict.getlist(name):
new_matches = []
for piece, p_args in parent:
vals = [(piece + suffix, p_args + args) for \
(suffix, args) in matches]
new_matches.extend(vals)
lookup_list = (new_matches, p_pattern + pat,
dict(defaults,
**pattern.default_kwargs))
lookups.appendlist(name, lookup_list)
for namespace, (prefix, sub_pattern) in \
pattern.namespace_dict.items():
namespace_vals = (p_pattern + prefix, sub_pattern)
namespaces[namespace] = namespace_vals
for app_name, namespace_list in pattern.app_dict.items():
apps.setdefault(app_name, []).extend(namespace_list)
else:
bits = normalize(p_pattern)
lookup_list = (bits, p_pattern, pattern.default_args)
lookups.appendlist(pattern.callback, lookup_list)
if pattern.name is not None:
lookup_list = (bits, p_pattern, pattern.default_args)
lookups.appendlist(pattern.name, lookup_list)
self._reverse_dict = lookups
self._namespace_dict = namespaces
self._app_dict = apps
def resolver_reverse(self, lookup_view, *args, **kwargs):
return self._reverse_with_prefix(lookup_view, '', *args, **kwargs)
def _reverse_with_prefix(self, lookup_view, _prefix, *args, **kwargs):
if args and kwargs:
raise ValueError("Don't mix *args and **kwargs in call to "
"reverse()!")
try:
lookup_view = urlresolvers.get_callable(lookup_view, True)
except (ImportError, AttributeError), e:
raise urlresolvers.NoReverseMatch("Error importing '%s': %s."
% (lookup_view, e))
possibilities = self.reverse_dict.getlist(lookup_view)
prefix_norm, prefix_args = normalize(_prefix)[0]
for possibility, pattern, defaults in possibilities:
for result, params in possibility:
if args:
if len(args) != len(params) + len(prefix_args):
continue
unicode_args = [force_unicode(val) for val in args]
candidate = (prefix_norm + result) \
% dict(zip(prefix_args + params, unicode_args))
else:
if set(kwargs.keys() + defaults.keys()) != \
set(params + defaults.keys() + prefix_args):
continue
matches = True
for k, v in defaults.items():
if kwargs.get(k, v) != v:
matches = False
break
if not matches:
continue
unicode_kwargs = dict([(k, force_unicode(v)) for \
(k, v) in kwargs.items()])
candidate = (prefix_norm + result) % unicode_kwargs
if re.search(u'^%s%s' % (_prefix, pattern),
candidate, re.UNICODE):
return candidate
# lookup_view can be URL label, or dotted path, or callable, Any of
# these can be passed in at the top, but callables are not friendly in
# error messages.
m = getattr(lookup_view, '__module__', None)
n = getattr(lookup_view, '__name__', None)
if m is not None and n is not None:
lookup_view_s = "%s.%s" % (m, n)
else:
lookup_view_s = lookup_view
raise urlresolvers.NoReverseMatch("Reverse for '%s' with "
"arguments '%s' and keyword "
"arguments '%s' not found."
% (lookup_view_s, args, kwargs))
def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None,
current_app=None):
if urlconf is None:
urlconf = urlresolvers.get_urlconf()
resolver = urlresolvers.get_resolver(urlconf)
args = args or []
kwargs = kwargs or {}
if prefix is None:
prefix = urlresolvers.get_script_prefix()
if not isinstance(viewname, basestring):
view = viewname
else:
parts = viewname.split(':')
parts.reverse()
view = parts[0]
path = parts[1:]
resolved_path = []
while path:
ns = path.pop()
# Lookup the name to see if it could be an app identifier
try:
app_list = resolver.app_dict[ns]
# Yes! Path part matches an app in the current Resolver
if current_app and current_app in app_list:
# If we are reversing for a particular app,
# use that namespace
ns = current_app
elif ns not in app_list:
# The name isn't shared by one of the instances
# (i.e., the default) so just pick the first instance
# as the default.
ns = app_list[0]
except KeyError:
pass
try:
extra, resolver = resolver.namespace_dict[ns]
resolved_path.append(ns)
prefix = prefix + extra
except KeyError, key:
if resolved_path:
raise urlresolvers.NoReverseMatch("%s is not a "
"registered namespace inside %s'"
% (key, ':'.join(resolved_path)))
else:
raise urlresolvers.NoReverseMatch("%s is not a "
"registered "
"namespace" % key)
return iri_to_uri(resolver._reverse_with_prefix(view, prefix,
*args, **kwargs))
urlresolvers.RegexURLResolver._populate = _populate
urlresolvers.RegexURLResolver.reverse = resolver_reverse
urlresolvers.RegexURLResolver._reverse_with_prefix = _reverse_with_prefix
urlresolvers.reverse = reverse