Código fuente para django.urls.resolvers

"""This module converts requested URLs to callback view functions.RegexURLResolver is the main class here. Its resolve() method takes a URL (asa string) and returns a ResolverMatch object which provides access to allattributes of the resolved URL match."""from__future__importunicode_literalsimportfunctoolsimportreimportthreadingfromimportlibimportimport_modulefromdjango.confimportsettingsfromdjango.core.exceptionsimportImproperlyConfiguredfromdjango.utilsimportlru_cache,sixfromdjango.utils.datastructuresimportMultiValueDictfromdjango.utils.encodingimportforce_str,force_textfromdjango.utils.functionalimportcached_propertyfromdjango.utils.httpimportRFC3986_SUBDELIMS,urlquotefromdjango.utils.regex_helperimportnormalizefromdjango.utils.translationimportget_languagefrom.exceptionsimportNoReverseMatch,Resolver404from.utilsimportget_callable

[documentos]classResolverMatch(object):def__init__(self,func,args,kwargs,url_name=None,app_names=None,namespaces=None):self.func=funcself.args=argsself.kwargs=kwargsself.url_name=url_name# If a URLRegexResolver doesn't have a namespace or app_name, it passes# in an empty value.self.app_names=[xforxinapp_namesifx]ifapp_nameselse[]self.app_name=':'.join(self.app_names)self.namespaces=[xforxinnamespacesifx]ifnamespaceselse[]self.namespace=':'.join(self.namespaces)ifnothasattr(func,'__name__'):# A class-based viewself._func_path='.'.join([func.__class__.__module__,func.__class__.__name__])else:# A function-based viewself._func_path='.'.join([func.__module__,func.__name__])view_path=url_nameorself._func_pathself.view_name=':'.join(self.namespaces+[view_path])def__getitem__(self,index):return(self.func,self.args,self.kwargs)[index]def__repr__(self):return"ResolverMatch(func=%s, args=%s, kwargs=%s, url_name=%s, app_names=%s, namespaces=%s)"%(self._func_path,self.args,self.kwargs,self.url_name,self.app_names,self.namespaces,)

@lru_cache.lru_cache(maxsize=None)defget_resolver(urlconf=None):ifurlconfisNone:fromdjango.confimportsettingsurlconf=settings.ROOT_URLCONFreturnRegexURLResolver(r'^/',urlconf)@lru_cache.lru_cache(maxsize=None)defget_ns_resolver(ns_pattern,resolver):# Build a namespaced resolver for the given parent URLconf pattern.# This makes it possible to have captured parameters in the parent# URLconf pattern.ns_resolver=RegexURLResolver(ns_pattern,resolver.url_patterns)returnRegexURLResolver(r'^/',[ns_resolver])classLocaleRegexProvider(object):""" A mixin to provide a default regex property which can vary by active language. """def__init__(self,regex):# regex is either a string representing a regular expression, or a# translatable string (using ugettext_lazy) representing a regular# expression.self._regex=regexself._regex_dict={}@propertydefregex(self):""" Return a compiled regular expression based on the activate language. """language_code=get_language()iflanguage_codenotinself._regex_dict:regex=self._regexifisinstance(self._regex,six.string_types)elseforce_text(self._regex)try:compiled_regex=re.compile(regex,re.UNICODE)exceptre.errorase:raiseImproperlyConfigured('"%s" is not a valid regular expression: %s'%(regex,six.text_type(e)))self._regex_dict[language_code]=compiled_regexreturnself._regex_dict[language_code]classRegexURLPattern(LocaleRegexProvider):def__init__(self,regex,callback,default_args=None,name=None):LocaleRegexProvider.__init__(self,regex)self.callback=callback# the viewself.default_args=default_argsor{}self.name=namedef__repr__(self):returnforce_str('<%s%s%s>'%(self.__class__.__name__,self.name,self.regex.pattern))defresolve(self,path):match=self.regex.search(path)ifmatch:# If there are any named groups, use those as kwargs, ignoring# non-named groups. Otherwise, pass all non-named arguments as# positional arguments.kwargs=match.groupdict()args=()ifkwargselsematch.groups()# In both cases, pass any extra_kwargs as **kwargs.kwargs.update(self.default_args)returnResolverMatch(self.callback,args,kwargs,self.name)@cached_propertydeflookup_str(self):""" A string that identifies the view (e.g. 'path.to.view_function' or 'path.to.ClassBasedView'). """callback=self.callback# Python 3.5 collapses nested partials, so can change "while" to "if"# when it's the minimum supported version.whileisinstance(callback,functools.partial):callback=callback.funcifnothasattr(callback,'__name__'):returncallback.__module__+"."+callback.__class__.__name__elifsix.PY3:returncallback.__module__+"."+callback.__qualname__else:# PY2 does not support __qualname__returncallback.__module__+"."+callback.__name__classRegexURLResolver(LocaleRegexProvider):def__init__(self,regex,urlconf_name,default_kwargs=None,app_name=None,namespace=None):LocaleRegexProvider.__init__(self,regex)# urlconf_name is the dotted Python path to the module defining# urlpatterns. It may also be an object with an urlpatterns attribute# or urlpatterns itself.self.urlconf_name=urlconf_nameself.callback=Noneself.default_kwargs=default_kwargsor{}self.namespace=namespaceself.app_name=app_nameself._reverse_dict={}self._namespace_dict={}self._app_dict={}# set of dotted paths to all functions and classes that are used in# urlpatternsself._callback_strs=set()self._populated=Falseself._local=threading.local()def__repr__(self):ifisinstance(self.urlconf_name,list)andlen(self.urlconf_name):# Don't bother to output the whole list, it can be hugeurlconf_repr='<%s list>'%self.urlconf_name[0].__class__.__name__else:urlconf_repr=repr(self.urlconf_name)returnstr('<%s%s (%s:%s) %s>')%(self.__class__.__name__,urlconf_repr,self.app_name,self.namespace,self.regex.pattern,)def_populate(self):# Short-circuit if called recursively in this thread to prevent# infinite recursion. Concurrent threads may call this at the same# time and will need to continue, so set 'populating' on a# thread-local variable.ifgetattr(self._local,'populating',False):returnself._local.populating=Truelookups=MultiValueDict()namespaces={}apps={}language_code=get_language()forpatterninreversed(self.url_patterns):ifisinstance(pattern,RegexURLPattern):self._callback_strs.add(pattern.lookup_str)p_pattern=pattern.regex.patternifp_pattern.startswith('^'):p_pattern=p_pattern[1:]ifisinstance(pattern,RegexURLResolver):ifpattern.namespace:namespaces[pattern.namespace]=(p_pattern,pattern)ifpattern.app_name:apps.setdefault(pattern.app_name,[]).append(pattern.namespace)else:parent_pat=pattern.regex.patternfornameinpattern.reverse_dict:formatches,pat,defaultsinpattern.reverse_dict.getlist(name):new_matches=normalize(parent_pat+pat)lookups.appendlist(name,(new_matches,p_pattern+pat,dict(defaults,**pattern.default_kwargs),))fornamespace,(prefix,sub_pattern)inpattern.namespace_dict.items():namespaces[namespace]=(p_pattern+prefix,sub_pattern)forapp_name,namespace_listinpattern.app_dict.items():apps.setdefault(app_name,[]).extend(namespace_list)ifnotgetattr(pattern._local,'populating',False):pattern._populate()self._callback_strs.update(pattern._callback_strs)else:bits=normalize(p_pattern)lookups.appendlist(pattern.callback,(bits,p_pattern,pattern.default_args))ifpattern.nameisnotNone:lookups.appendlist(pattern.name,(bits,p_pattern,pattern.default_args))self._reverse_dict[language_code]=lookupsself._namespace_dict[language_code]=namespacesself._app_dict[language_code]=appsself._populated=Trueself._local.populating=False@propertydefreverse_dict(self):language_code=get_language()iflanguage_codenotinself._reverse_dict:self._populate()returnself._reverse_dict[language_code]@propertydefnamespace_dict(self):language_code=get_language()iflanguage_codenotinself._namespace_dict:self._populate()returnself._namespace_dict[language_code]@propertydefapp_dict(self):language_code=get_language()iflanguage_codenotinself._app_dict:self._populate()returnself._app_dict[language_code]def_is_callback(self,name):ifnotself._populated:self._populate()returnnameinself._callback_strsdefresolve(self,path):path=force_text(path)# path may be a reverse_lazy objecttried=[]match=self.regex.search(path)ifmatch:new_path=path[match.end():]forpatterninself.url_patterns:try:sub_match=pattern.resolve(new_path)exceptResolver404ase:sub_tried=e.args[0].get('tried')ifsub_triedisnotNone:tried.extend([pattern]+tfortinsub_tried)else:tried.append([pattern])else:ifsub_match:# Merge captured arguments in match with submatchsub_match_dict=dict(match.groupdict(),**self.default_kwargs)sub_match_dict.update(sub_match.kwargs)# If there are *any* named groups, ignore all non-named groups.# Otherwise, pass all non-named arguments as positional arguments.sub_match_args=sub_match.argsifnotsub_match_dict:sub_match_args=match.groups()+sub_match.argsreturnResolverMatch(sub_match.func,sub_match_args,sub_match_dict,sub_match.url_name,[self.app_name]+sub_match.app_names,[self.namespace]+sub_match.namespaces,)tried.append([pattern])raiseResolver404({'tried':tried,'path':new_path})raiseResolver404({'path':path})@cached_propertydefurlconf_module(self):ifisinstance(self.urlconf_name,six.string_types):returnimport_module(self.urlconf_name)else:returnself.urlconf_name@cached_propertydefurl_patterns(self):# urlconf_module might be a valid set of patterns, so we default to itpatterns=getattr(self.urlconf_module,"urlpatterns",self.urlconf_module)try:iter(patterns)exceptTypeError:msg=("The included URLconf '{name}' does not appear to have any ""patterns in it. If you see valid patterns in the file then ""the issue is probably caused by a circular import.")raiseImproperlyConfigured(msg.format(name=self.urlconf_name))returnpatternsdefresolve_error_handler(self,view_type):callback=getattr(self.urlconf_module,'handler%s'%view_type,None)ifnotcallback:# No handler specified in file; use lazy import, since# django.conf.urls imports this file.fromdjango.confimporturlscallback=getattr(urls,'handler%s'%view_type)returnget_callable(callback),{}defreverse(self,lookup_view,*args,**kwargs):returnself._reverse_with_prefix(lookup_view,'',*args,**kwargs)def_reverse_with_prefix(self,lookup_view,_prefix,*args,**kwargs):ifargsandkwargs:raiseValueError("Don't mix *args and **kwargs in call to reverse()!")text_args=[force_text(v)forvinargs]text_kwargs={k:force_text(v)for(k,v)inkwargs.items()}ifnotself._populated:self._populate()possibilities=self.reverse_dict.getlist(lookup_view)forpossibility,pattern,defaultsinpossibilities:forresult,paramsinpossibility:ifargs:iflen(args)!=len(params):continuecandidate_subs=dict(zip(params,text_args))else:if(set(kwargs.keys())|set(defaults.keys())!=set(params)|set(defaults.keys())):continuematches=Truefork,vindefaults.items():ifkwargs.get(k,v)!=v:matches=Falsebreakifnotmatches:continuecandidate_subs=text_kwargs# WSGI provides decoded URLs, without %xx escapes, and the URL# resolver operates on such URLs. First substitute arguments# without quoting to build a decoded URL and look for a match.# Then, if we have a match, redo the substitution with quoted# arguments in order to return a properly encoded URL.candidate_pat=_prefix.replace('%','%%')+resultifre.search('^%s%s'%(re.escape(_prefix),pattern),candidate_pat%candidate_subs,re.UNICODE):# safe characters from `pchar` definition of RFC 3986url=urlquote(candidate_pat%candidate_subs,safe=RFC3986_SUBDELIMS+str('/~:@'))# Don't allow construction of scheme relative urls.ifurl.startswith('//'):url='/%%2F%s'%url[2:]returnurl# lookup_view can be URL name or callable, but callables are not# friendly in error messages.m=getattr(lookup_view,'__module__',None)n=getattr(lookup_view,'__name__',None)ifmisnotNoneandnisnotNone:lookup_view_s="%s.%s"%(m,n)else:lookup_view_s=lookup_viewpatterns=[patternfor(possibility,pattern,defaults)inpossibilities]raiseNoReverseMatch("Reverse for '%s' with arguments '%s' and keyword ""arguments '%s' not found. %d pattern(s) tried: %s"%(lookup_view_s,args,kwargs,len(patterns),patterns))classLocaleRegexURLResolver(RegexURLResolver):""" A URL resolver that always matches the active language code as URL prefix. Rather than taking a regex argument, we just override the ``regex`` function to always return the active language-code as regex. """def__init__(self,urlconf_name,default_kwargs=None,app_name=None,namespace=None,prefix_default_language=True,):super(LocaleRegexURLResolver,self).__init__(None,urlconf_name,default_kwargs,app_name,namespace,)self.prefix_default_language=prefix_default_language@propertydefregex(self):language_code=get_language()orsettings.LANGUAGE_CODEiflanguage_codenotinself._regex_dict:iflanguage_code==settings.LANGUAGE_CODEandnotself.prefix_default_language:regex_string=''else:regex_string='^%s/'%language_codeself._regex_dict[language_code]=re.compile(regex_string,re.UNICODE)returnself._regex_dict[language_code]