3
v^j                 @   s  d Z ddlZddlZddlZddlZddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZmZ ddlmZ dd	lmZmZ dd
lmZ ddlmZ ddlmZmZ ddlmZ ddlmZ ddl m!Z! ddl"m#Z#m$Z$ ddl%m&Z& G dd dZ'd.ddZ(ej)ddd/ddZ*ej)dddd Z+G dd dZ,G dd dZ-G d d! d!e-Z.ej/d"Z0d0d$d%Z1G d&d' d'e-Z2G d(d) d)Z3G d*d+ d+Z4G d,d- d-Z5dS )1z
This module converts requested URLs to callback view functions.

URLResolver is the main class here. Its resolve() method takes a URL (as
a string) and returns a ResolverMatch object which provides access to all
attributes of the resolved URL match.
    N)import_module)quote)Local)settings)ErrorWarning)check_resolver)ImproperlyConfiguredViewDoesNotExist)MultiValueDict)cached_property)RFC3986_SUBDELIMSescape_leading_slashes)	normalize)get_language   )get_converter)NoReverseMatchResolver404)get_callablec               @   s&   e Zd ZdddZdd Zdd ZdS )	ResolverMatchNc       	      C   s   || _ || _|| _|| _|| _|r0dd |D ng | _dj| j| _|rVdd |D ng | _dj| j| _	t
|ds|jjd |jj | _n|jd |j | _|p| j}dj| j|g | _d S )Nc             S   s   g | ]}|r|qS  r   ).0xr   r   9/usr/lib/python3.6/site-packages/django/urls/resolvers.py
<listcomp>*   s    z*ResolverMatch.__init__.<locals>.<listcomp>:c             S   s   g | ]}|r|qS r   r   )r   r   r   r   r   r   ,   s    __name__.)funcargskwargsurl_nameroute	app_namesjoinapp_name
namespaces	namespacehasattr	__class__
__module__r   
_func_path	view_name)	selfr   r    r!   r"   r$   r'   r#   Z	view_pathr   r   r   __init__!   s    

zResolverMatch.__init__c             C   s   | j | j| jf| S )N)r   r    r!   )r.   indexr   r   r   __getitem__9   s    zResolverMatch.__getitem__c             C   s$   d| j | j| j| j| j| j| jf S )Nz^ResolverMatch(func=%s, args=%s, kwargs=%s, url_name=%s, app_names=%s, namespaces=%s, route=%s))r,   r    r!   r"   r$   r'   r#   )r.   r   r   r   __repr__<   s    zResolverMatch.__repr__)NNNN)r   r+   __qualname__r/   r1   r2   r   r   r   r   r       s   
r   c             C   s   | d krt j} t| S )N)r   ROOT_URLCONF_get_cached_resolver)urlconfr   r   r   get_resolverC   s    r7   )maxsizec             C   s   t td| S )Nz^/)URLResolverRegexPattern)r6   r   r   r   r5   I   s    r5   c             C   s.   t | }t||_t||j}tt d|gS )Nz^/)r:   dict
convertersr9   url_patterns)
ns_patternresolverr<   patternZns_resolverr   r   r   get_ns_resolverN   s    
rA   c               @   s   e Zd Zdd ZdddZdS )LocaleRegexDescriptorc             C   s
   || _ d S )N)attr)r.   rC   r   r   r   r/   Z   s    zLocaleRegexDescriptor.__init__Nc             C   sj   |dkr| S t || j}t|tr<|j||jd< |jd S t }||jkr`|jt||j|< |j| S )zT
        Return a compiled regular expression based on the active language.
        Nregex)getattrrC   
isinstancestr_compile__dict__r   _regex_dict)r.   instanceclsr@   language_coder   r   r   __get__]   s    


zLocaleRegexDescriptor.__get__)N)r   r+   r3   r/   rN   r   r   r   r   rB   Y   s   rB   c               @   s   e Zd Zdd Zdd ZdS )CheckURLMixinc             C   s$   dj | }| jr |dj | j7 }|S )zI
        Format the URL pattern for display in warning messages.
        z'{}'z [name='{}'])formatname)r.   descriptionr   r   r   describeq   s    
zCheckURLMixin.describec             C   sL   | j j}tjsg S |jdrD|jd rDtdj| j dd}|gS g S dS )	zM
        Check that the pattern does not begin with a forward slash.
        /^/^\/zYour URL pattern {} has a route beginning with a '/'. Remove this slash as it is unnecessary. If this pattern is targeted in an include(), ensure the include() pattern has a trailing '/'.z	urls.W002)idN)rT   rU   rV   )	rD   r@   r   APPEND_SLASH
startswithendswithr   rP   rS   )r.   regex_patternwarningr   r   r   _check_pattern_startswith_slashz   s    z-CheckURLMixin._check_pattern_startswith_slashN)r   r+   r3   rS   r]   r   r   r   r   rO   p   s   	rO   c               @   sF   e Zd ZedZdddZdd Zdd	 Zd
d Zdd Z	dd Z
dS )r:   _regexNFc             C   s"   || _ i | _|| _|| _i | _d S )N)r^   rJ   _is_endpointrQ   r<   )r.   rD   rQ   is_endpointr   r   r   r/      s
    zRegexPattern.__init__c             C   sT   | j j|}|rP|j }|r f n|j }dd |j D }||j d  ||fS d S )Nc             S   s   i | ]\}}|d k	r||qS )Nr   )r   kvr   r   r   
<dictcomp>   s    z&RegexPattern.match.<locals>.<dictcomp>)rD   search	groupdictgroupsitemsend)r.   pathmatchr!   r    r   r   r   rj      s    zRegexPattern.matchc             C   s*   g }|j | j  | js&|j | j  |S )N)extendr]   r_   _check_include_trailing_dollar)r.   warningsr   r   r   check   s
    zRegexPattern.checkc             C   s>   | j j}|jdr6|jd r6tdj| j ddgS g S d S )N$z\$zYour URL pattern {} uses include with a route ending with a '$'. Remove the dollar from the route to avoid problems including URLs.z	urls.W001)rW   )rD   r@   rZ   r   rP   rS   )r.   r[   r   r   r   rl      s    
z+RegexPattern._check_include_trailing_dollarc             C   sD   y
t j|S  t jk
r> } ztd||f W Y dd}~X nX dS )z0Compile and return the given regular expression.z*"%s" is not a valid regular expression: %sN)recompileerrorr	   )r.   rD   er   r   r   rH      s
    
zRegexPattern._compilec             C   s
   t | jS )N)rG   r^   )r.   r   r   r   __str__   s    zRegexPattern.__str__)NF)r   r+   r3   rB   rD   r/   rj   rn   rl   rH   rt   r   r   r   r   r:      s   
	r:   z/<(?:(?P<converter>[^>:]+):)?(?P<parameter>\w+)>Fc       
      C   s6  t | jtjstd|  | }dg}i }xtj| }|sL|jtj	|  P |jtj	| d|j
   | |j d } |jd}|j std||f |jd}|dkrd}yt|}W n2 tk
r }	 ztd||	f W Y dd}	~	X nX |||< |jd	| d
 |j d  q,W |r(|jd dj||fS )a  
    Convert a path pattern into a regular expression. Return the regular
    expression and a dictionary mapping the capture names to the converters.
    For example, 'foo/<int:pk>' returns '^foo\/(?P<pk>[0-9]+)'
    and {'pk': <django.urls.converters.IntConverter>}.
    z)URL route '%s' cannot contain whitespace.^N	parameterzLURL route '%s' uses parameter name %r which isn't a valid Python identifier.	converterrG   z)URL route '%s' uses invalid converter %s.z(?P<>)ro    )set
isdisjointstring
whitespacer	   _PATH_PARAMETER_COMPONENT_RErd   appendrp   escapestartrh   groupisidentifierr   KeyErrorrD   r%   )
r#   r`   Zoriginal_routepartsr<   rj   rv   Zraw_converterrw   rs   r   r   r   _route_to_regex   s<    


  
r   c               @   s>   e Zd ZedZdddZdd Zdd	 Zd
d Zdd Z	dS )RoutePattern_routeNFc             C   s0   || _ i | _|| _|| _tt||d | _d S )Nr   )r   rJ   r_   rQ   r   rG   r<   )r.   r#   rQ   r`   r   r   r   r/      s
    zRoutePattern.__init__c             C   sz   | j j|}|rv|j }xF|j D ]:\}}| j| }y|j|||< W q" tk
rZ   d S X q"W ||j d  f |fS d S )N)rD   rd   re   rg   r<   	to_python
ValueErrorrh   )r.   ri   rj   r!   keyvaluerw   r   r   r   rj      s    

zRoutePattern.matchc             C   sJ   | j  }| j}d|ks*|jds*|jdrF|jtdj| j dd |S )Nz(?P<ru   ro   zYour URL pattern {} has a route that contains '(?P<', begins with a '^', or ends with a '$'. This was likely an oversight when migrating to django.urls.path().z2_0.W001)rW   )r]   r   rY   rZ   r   r   rP   rS   )r.   rm   r#   r   r   r   rn     s    
zRoutePattern.checkc             C   s   t jt|| jd S )Nr   )rp   rq   r   r_   )r.   r#   r   r   r   rH     s    zRoutePattern._compilec             C   s
   t | jS )N)rG   r   )r.   r   r   r   rt     s    zRoutePattern.__str__)NF)
r   r+   r3   rB   rD   r/   rj   rn   rH   rt   r   r   r   r   r      s   
r   c               @   sN   e Zd ZdddZedd Zedd Zdd	 Zd
d Zdd Z	dd Z
dS )LocalePrefixPatternTc             C   s   || _ i | _d S )N)prefix_default_languager<   )r.   r   r   r   r   r/   "  s    zLocalePrefixPattern.__init__c             C   s   t j| jS )N)rp   rq   language_prefix)r.   r   r   r   rD   &  s    zLocalePrefixPattern.regexc             C   s.   t  p
tj}|tjkr"| j r"dS d| S d S )Nrz   z%s/)r   r   LANGUAGE_CODEr   )r.   rM   r   r   r   r   +  s    z#LocalePrefixPattern.language_prefixc             C   s*   | j }|j|r&|t|d  f i fS d S )N)r   rY   len)r.   ri   r   r   r   r   rj   3  s    
zLocalePrefixPattern.matchc             C   s   g S )Nr   )r.   r   r   r   rn   9  s    zLocalePrefixPattern.checkc             C   s
   dj | S )Nz'{}')rP   )r.   r   r   r   rS   <  s    zLocalePrefixPattern.describec             C   s   | j S )N)r   )r.   r   r   r   rt   ?  s    zLocalePrefixPattern.__str__N)T)r   r+   r3   r/   propertyrD   r   rj   rn   rS   rt   r   r   r   r   r   !  s   
r   c               @   sB   e Zd ZdddZdd Zdd Zdd	 Zd
d Zedd Z	dS )
URLPatternNc             C   s    || _ || _|pi | _|| _d S )N)r@   callbackdefault_argsrQ   )r.   r@   r   r   rQ   r   r   r   r/   D  s    
zURLPattern.__init__c             C   s   d| j j| jj f S )Nz<%s %s>)r*   r   r@   rS   )r.   r   r   r   r2   J  s    zURLPattern.__repr__c             C   s   | j  }|j| jj  |S )N)_check_pattern_namerk   r@   rn   )r.   rm   r   r   r   rn   M  s    zURLPattern.checkc             C   s>   | j jdk	r6d| j jkr6tdj| j j dd}|gS g S dS )zG
        Check that the pattern name does not contain a colon.
        Nr   zjYour URL pattern {} has a name including a ':'. Remove the colon, to avoid ambiguous namespace references.z	urls.W003)rW   )r@   rQ   r   rP   rS   )r.   r\   r   r   r   r   R  s    
zURLPattern._check_pattern_namec             C   sH   | j j|}|rD|\}}}|j| j t| j||| j jt| j dS d S )N)r#   )r@   rj   updater   r   r   rQ   rG   )r.   ri   rj   new_pathr    r!   r   r   r   resolve`  s
    
zURLPattern.resolvec             C   sD   | j }t|tjr|j}t|ds4|jd |jj S |jd |j	 S )zw
        A string that identifies the view (e.g. 'path.to.view_function' or
        'path.to.ClassBasedView').
        r   r   )
r   rF   	functoolspartialr   r)   r+   r*   r   r3   )r.   r   r   r   r   
lookup_strh  s    
zURLPattern.lookup_str)NN)
r   r+   r3   r/   r2   rn   r   r   r   r   r   r   r   r   r   C  s   
r   c               @   s   e Zd Zd"ddZdd Zdd Zdd	 Zd
d Zedd Z	edd Z
edd Zedd Zdd Zdd Zedd Zedd Zdd Zdd Zd d! ZdS )#r9   Nc             C   sT   || _ || _d | _|pi | _|| _|| _i | _i | _i | _t	 | _
d| _t | _d S )NF)r@   urlconf_namer   default_kwargsr(   r&   _reverse_dict_namespace_dict	_app_dictr{   _callback_strs
_populatedr   _local)r.   r@   r   r   r&   r(   r   r   r   r/   w  s    
zURLResolver.__init__c             C   sP   t | jtr&| jr&d| jd jj }n
t| j}d| jj|| j| j| jj	 f S )Nz	<%s list>r   z<%s %s (%s:%s) %s>)
rF   r   listr*   r   reprr&   r(   r@   rS   )r.   Zurlconf_reprr   r   r   r2     s    
zURLResolver.__repr__c             C   s>   g }x| j D ]}|jt| qW |j| j  |p<| jj S )N)r=   rk   r   _check_custom_error_handlersr@   rn   )r.   messagesr@   r   r   r   rn     s
    zURLResolver.checkc             C   s  g } xdD ]\}}y| j |\}}W n^ ttfk
r } z>t| jd| }dj||d	}|jt|t|d
d wW Y d d }~X nX t	j
|}	d g| }
y|	j|
  W q tk
 r   dj||jd |j |dkrdndd}|jt|dd Y qX qW |S )N           r   z	handler%szDThe custom handler{status_code} view '{path}' could not be imported.)status_coderi   z	urls.E008)hintrW   zeThe custom handler{status_code} view '{path}' does not take the correct number of arguments ({args}).r   zrequest, exceptionrequest)r   ri   r    z	urls.E007)rW   r   r   r   r   r   r   r   r   )r   r   r   r   )resolve_error_handlerImportErrorr
   rE   urlconf_modulerP   r   r   rG   inspect	signaturebind	TypeErrorr+   r3   )r.   r   r   Znum_parametershandlerZ
param_dictrs   ri   msgr   r    r   r   r   r     s*    


z(URLResolver._check_custom_error_handlersc             C   s(  t | jddrd S zd| j_t }i }i }t }xt| jD ]}|jjj}|j	drf|dd  }t
|tr| jj|j t|jjj}|j|j|||j|jjf |jd k	r|j|j|||j|jjf q@|j  |jr|j|jg j|j ||f||j< nxh|jD ]^}xV|jj|D ]F\}	}
}}t||
 }|j||||
 ||j| jj|jj|f q W qW xB|jj D ]4\}\}}|jj}|jjj| || |f||< q|W x*|j j D ]\}}|j|g j!| qW | jj|j q@W || j"|< || j#|< || j$|< d| _%W d d| j_X d S )N
populatingFTru   r   )&rE   r   r   r   r   reversedr=   r@   rD   rY   rF   r   r   addr   r   
appendlistr   r   r<   rQ   	_populater&   
setdefaultr   r(   reverse_dictgetlistr   namespace_dictrg   r   app_dictrk   r   r   r   r   )r.   lookupsr'   appsrM   Zurl_patternZ	p_patternbitsrQ   matchespatdefaultsr<   Znew_matchesr(   prefixZsub_patternZcurrent_convertersr&   Znamespace_listr   r   r   r     s^    



"



zURLResolver._populatec             C   s"   t  }|| jkr| j  | j| S )N)r   r   r   )r.   rM   r   r   r   r     s    
zURLResolver.reverse_dictc             C   s"   t  }|| jkr| j  | j| S )N)r   r   r   )r.   rM   r   r   r   r     s    
zURLResolver.namespace_dictc             C   s"   t  }|| jkr| j  | j| S )N)r   r   r   )r.   rM   r   r   r   r     s    
zURLResolver.app_dictc             C   s&   | s|S |j dr|dd }| | S )z<Join two routes, without the starting ^ in the second route.ru   r   N)rY   )Zroute1Zroute2r   r   r   _join_route  s
    
zURLResolver._join_routec             C   s   | j s| j  || jkS )N)r   r   r   )r.   rQ   r   r   r   _is_callback  s    zURLResolver._is_callbackc                sT  t |}g }| jj|}|rD|\}}}x
| jD  ] y j|}W n` tk
r } zD|jd jd}	|	d k	r|j fdd|	D  n|j	 g W Y d d }~X q2X |r&|| j
}
|
j|j |j}|
s||j }t trdnt  j}t|j||
|j| jg|j | jg|j | j||jS |j	 g q2W t||dtd|id S )Nr   triedc             3   s   | ]} g| V  qd S )Nr   )r   t)r@   r   r   	<genexpr>&  s    z&URLResolver.resolve.<locals>.<genexpr>rz   )r   ri   ri   )rG   r@   rj   r=   r   r   r    getrk   r   r   r   r!   rF   r   r   r   r"   r&   r$   r(   r'   r   r#   )r.   ri   r   rj   r   r    r!   Z	sub_matchrs   Z	sub_triedZsub_match_dictZsub_match_argsZcurrent_router   )r@   r   r     s>    


zURLResolver.resolvec             C   s    t | jtrt| jS | jS d S )N)rF   r   rG   r   )r.   r   r   r   r   B  s    
zURLResolver.urlconf_modulec             C   sL   t | jd| j}yt| W n* tk
rF   d}t|j| jdY nX |S )NZurlpatternszThe 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.)rQ   )rE   r   iterr   r	   rP   r   )r.   patternsr   r   r   r   r=   I  s    zURLResolver.url_patternsc             C   s<   t | jd| d }|s0ddlm} t |d| }t|i fS )Nz	handler%sr   )urls)rE   r   django.confr   r   )r.   Z	view_typer   r   r   r   r   r   X  s
    z!URLResolver.resolve_error_handlerc             O   s   | j |df||S )Nrz   )_reverse_with_prefix)r.   lookup_viewr    r!   r   r   r   reversea  s    zURLResolver.reversec                s  |r rt d| js| j  | jj|}x|D ]\}}}}	x|D ]\}
}|rtt|t|krdqFtt||}n6t j	|j
|rqFt fdd|j D rqF }i }x<|j D ]0\}}||	kr|	| j|||< qt|||< qW |jdd|
 }tjdtj||f || rFt|| td d}t|S qFW q2W t|d	d }t|d
d }|d k	rx|d k	rxd||f }n|}dd |D }|r|rd|f }n rd f }nd}d||t||f }ndd|i }t|d S )Nz2Don't mix *args and **kwargs in call to reverse()!c             3   s"   | ]\}} j |||kV  qd S )N)r   )r   ra   rb   )r!   r   r   r   v  s    z3URLResolver._reverse_with_prefix.<locals>.<genexpr>%z%%z^%s%sz/~:@)safer+   r   z%s.%sc             S   s   g | ]\}}}}|qS r   r   )r   _r@   r   r   r   r     s    z4URLResolver._reverse_with_prefix.<locals>.<listcomp>zarguments '%s'zkeyword arguments '%s'zno argumentsz;Reverse for '%s' with %s not found. %d pattern(s) tried: %szZReverse for '%(view)s' not found. '%(view)s' is not a valid view function or pattern name.view)r   r   r   r   r   r   r;   zipr{   symmetric_difference
differenceanyrg   Zto_urlrG   replacerp   rd   r   r   r   r   rE   r   )r.   r   _prefixr    r!   possibilitiesZpossibilityr@   r   r<   resultparamsZcandidate_subsZtext_candidate_subsra   rb   Zcandidate_paturlmnZlookup_view_sr   Zarg_msgr   r   )r!   r   r   d  sT    
z URLResolver._reverse_with_prefix)NNN)r   r+   r3   r/   r2   rn   r   r   r   r   r   r   staticmethodr   r   r   r   r   r=   r   r   r   r   r   r   r   r9   v  s    
=	(	r9   )N)N)F)6__doc__r   r   rp   r}   	importlibr   urllib.parser   asgiref.localr   r   r   Zdjango.core.checksr   r   django.core.checks.urlsr   django.core.exceptionsr	   r
   django.utils.datastructuresr   django.utils.functionalr   django.utils.httpr   r   Zdjango.utils.regex_helperr   django.utils.translationr   r<   r   
exceptionsr   r   utilsr   r   r7   	lru_cacher5   rA   rB   rO   r:   rq   r   r   r   r   r   r9   r   r   r   r   <module>   sD   #

!6
*+"3