
     h                        d Z ddlmZmZ ddlZ ej
                  e      ZddlZddl	Z	ddl
mZ 	 ddlmZ ej                  de       dd	lmZmZ dd
lmZ ddlmZ ddlmZmZmZmZ ddlmZ g dZdZ  G d d      Z!dddddZ"d Z#dZ$dZ%dZ& e'dg      Z(d Z) G d de*      Z+ G d d e+      Z,d!Z- G d" d#e*      Z. G d$ d%e*      Z/ e*       Z0 G d& d'e*      Z1y# e$ r ej                  d       dZY w xY w)(z?passlib.ext.django.utils - helper functions used by this plugin    )update_wrapperwrapsN)warn)VERSIONzfound django %r installationzdjango installation not found )excregistry)CryptContext)PasslibRuntimeWarning)get_method_function	iteritemsOrderedDictunicode)memoized_property)DJANGO_VERSIONMIN_DJANGO_VERSIONget_preset_configquirks)      c                   *    e Zd Zedk\  Zedk\  Zedk\  Zy)r      r   N)__name__
__module____qualname__r    none_causes_check_password_errorempty_is_usable_passwordinvalid_is_usable_passwordr       Z/var/www/html/Resume-Scraper/venv/lib/python3.12/site-packages/passlib/ext/django/utils.pyr   r   '   s)     (6'?$  .7 "06!9r    r   django10_contextdjango14_contextdjango16_contextdjango_context)z
django-1.0z
django-1.4
django-1.6zdjango-latestc                     | dk(  rt         st        d      d} | dk(  rt        S 	 t        |    }ddl}t        |j                  |      j                         S # t        $ r t        d| z        w xY w)ae  Returns configuration string for one of the preset strings
    supported by the ``PASSLIB_CONFIG`` setting.
    Currently supported presets:

    * ``"passlib-default"`` - default config used by this release of passlib.
    * ``"django-default"`` - config matching currently installed django version.
    * ``"django-latest"`` - config matching newest django version (currently same as ``"django-1.6"``).
    * ``"django-1.0"`` - config used by stock Django 1.0 - 1.3 installs
    * ``"django-1.4"`` - config used by stock Django 1.4 installs
    * ``"django-1.6"`` - config used by stock Django 1.6 installs
    zdjango-defaultz9can't resolve django-default preset, django not installedr&   passlib-defaultzunknown preset config name: %rr   N)	r   
ValueErrorPASSLIB_DEFAULT_preset_mapKeyErrorpasslib.appsgetattrapps	to_string)nameattrpasslibs      r!   r   r   ?   s      4 5 5  B4  7<<&0022  B9D@AABs   	A A.a  
[passlib]

; list of schemes supported by configuration
; currently all django 1.6, 1.4, and 1.0 hashes,
; and three common modular crypt format hashes.
schemes =
    django_pbkdf2_sha256, django_pbkdf2_sha1, django_bcrypt, django_bcrypt_sha256,
    django_salted_sha1, django_salted_md5, django_des_crypt, hex_md5,
    sha512_crypt, bcrypt, phpass

; default scheme to use for new hashes
default = django_pbkdf2_sha256

; hashes using these schemes will automatically be re-hashed
; when the user logs in (currently all django 1.0 hashes)
deprecated =
    django_pbkdf2_sha1, django_salted_sha1, django_salted_md5,
    django_des_crypt, hex_md5

; sets some common options, including minimum rounds for two primary hashes.
; if a hash has less than this number of rounds, it will be re-hashed.
sha512_crypt__min_rounds = 80000
django_pbkdf2_sha256__min_rounds = 10000

; set somewhat stronger iteration counts for ``User.is_staff``
staff__sha512_crypt__default_rounds = 100000
staff__django_pbkdf2_sha256__default_rounds = 12500

; and even stronger ones for ``User.is_superuser``
superuser__sha512_crypt__default_rounds = 120000
superuser__django_pbkdf2_sha256__default_rounds = 15000
passlib_django_hex_md5c                 .     t                fd       }|S )z#wrap method object in bare functionc                       | i |S Nr   )argskwdsmethods     r!   wrapperz_wrap_method.<locals>.wrapper   s    t$t$$r    )r   )r<   r=   s   ` r!   _wrap_methodr>      s    
6]% %Nr    c                        e Zd ZdZdZdZdZdZd fd	Zd Z	d Z
d ZddZ ed	      Zed
kD  rej!                  d       d Zd ZddZddZ xZS )DjangoTranslatoraO  
    Object which helps translate passlib hasher objects / names
    to and from django hasher objects / names.

    These methods are wrapped in a class so that results can be cached,
    but with the ability to have independant caches, since django hasher
    names may / may not correspond to the same instance (or even class).
    Nc                     t        t        | 
  di | ||| _        t	        j
                         | _        t	        j                         | _        y )Nr   )	superr@   __init__contextweakrefWeakKeyDictionary_django_hasher_cacheWeakValueDictionary_passlib_hasher_cache)selfrD   r;   	__class__s      r!   rC   zDjangoTranslator.__init__   sE    .66"DL$+$=$=$?!%,%@%@%B"r    c                 z    | j                   j                          | j                  j                          d | _        y r9   )rG   clearrI   _django_unsalted_sha1rJ   s    r!   reset_hasherszDjangoTranslator.reset_hashers   s.    !!'')""((*%)"r    c                 j    | j                   }|t        j                  |      S |j                  |      S )zM
        resolve passlib hasher by name, using context if available.
        )rD   r	   get_crypt_handlerhandler)rJ   passlib_namerD   s      r!   _get_passlib_hasherz$DjangoTranslator._get_passlib_hasher   s2     ,,?--l;;??<00r    c                 8    | j                  |      j                  S )zF
        Convert passlib hasher / name to Django hasher name.
        )passlib_to_django	algorithm)rJ   rT   s     r!   passlib_to_django_namez'DjangoTranslator.passlib_to_django_name   s     %%l3===r    c                    t        |d      s| j                  |      }|r| j                  }	 ||   S t        |dd      }|r| j                  |      S t        |      S # t        $ r Y nw xY w| j	                  |d      x}||<   |S )z
        Convert passlib hasher / name to Django hasher.

        :param passlib_hasher:
            passlib hasher / name

        :returns:
            django hasher instance
        r1   Fcacheddjango_nameN)hasattrrU   rG   r,   rW   r.   _create_django_hasher_PasslibHasherWrapper)rJ   passlib_hasherr\   cacheresultr]   s         r!   rW   z"DjangoTranslator.passlib_to_django   s     ~v.!55nEN --E^,, nmTB--k::(88   &&~e&DEFU>*Ms   A 	A)(A)MD5PasswordHasher)md5r   BCryptPasswordHasher)bcryptc                    t         j                  j                  d      }||j                  j                  sddlm} 	  ||      S |j                  j                  j                  d      j                  } |       D ]  }|j                  |k(  s|c S  | j                  j                  |      }|rd|vrd|z   }dd	lm}   ||             S t        d
|z        # t        $ r%}t        |      j                  d      s Y d}~pd}~ww xY w)zf
        helper to create new django hasher by name.
        wraps underlying django methods.
        zpasslib.ext.django.modelsNr   )
get_hasherz"Unknown password hashing algorithmz'django.contrib.auth.hashers:get_hashers.zdjango.contrib.auth.hashers.)import_stringzunknown hasher: %r)sysmodulesgetadapterpatcheddjango.contrib.auth.hashersri   r)   str
startswith_managergetorig__wrapped__rX   _builtin_django_hashersdjango.utils.module_loadingrk   )	rJ   r]   moduleri   errget_hashershasherpathrk   s	            r!   r_   z&DjangoTranslator._create_django_hasher  s     !<=>!7!7>!+.. !..1199:cdppK%- "##{2!M" ++//<$5<A&=&((-;<<+  3x**+OP Qs   C 	D
%DD
c                 8    | j                  |      j                  S )zF
        Convert Django hasher / name to Passlib hasher name.
        )django_to_passlibr1   )rJ   r]   s     r!   django_to_passlib_namez'DjangoTranslator.django_to_passlib_name+  s     %%k2777r    c                    t        |d      r(t        |t              r|j                  S |j                  }|r| j
                  }	 ||   S |j                  t              r#|t        t              d }| j                  |      S |dk(  r)| j                  }|t        d      |j                         S |dk(  rd}| j                  }|d	 t        j                          D        }n|j#                  d
      }|D ]  }t%        |dd      |k(  s|c S  t'        d|      # t        $ r Y nw xY w| j                  |d      x}||<   |S )a  
        Convert Django hasher / name to Passlib hasher / name.
        If present, CryptContext will be checked instead of main registry.

        :param django_name:
            Django hasher class or algorithm name.
            "default" allowed if context provided.

        :raises ValueError:
            if can't resolve hasher.

        :returns:
            passlib hasher or name
        rX   Fr[   Ndefaultz)can't determine default scheme w/ contextunsalted_sha1sha1c              3      K   | ]6  }|j                  t              s|t        v rt        j                  |       8 y wr9   )rs   DJANGO_COMPAT_PREFIX_other_django_hashesr	   rR   ).0rT   s     r!   	<genexpr>z5DjangoTranslator.django_to_passlib.<locals>.<genexpr>n  s;       **+?@#77 **<8s   <>Tresolver]   z-can't translate django name to passlib name: )r^   
isinstancer`   passlib_handlerrX   rI   r,   r   rs   PASSLIB_WRAPPER_PREFIXlenrU   rD   	TypeErrorrS   r	   list_crypt_handlersschemesr.   r)   )	rJ   r]   r\   rb   rc   rT   rD   
candidatesrS   s	            r!   r   z"DjangoTranslator.django_to_passlib1  s}     ;, +'<="222 &//K ..E[)) !!"89&s+A'B'CDL++L99 )#llG KLL??$$
 /) K
 ,,?$,$@$@$BJ !6J! 	Gwt4C	 %( ) 	)a   &&{5&ABFU;'Ms   D 	D'&D'c                    t        |d      r|S | j                  ||      }|dk(  rJ|j                  dk(  r;|s| j                  |      S | j                  }|| j                  |      x}| _        |S | j                  ||      S )zH
        Take in a django algorithm name, return django hasher.
        rX   r[   r   django_salted_sha1)r^   r   r1   r_   rN   rW   )rJ   r]   r\   ra   rc   s        r!   resolve_django_hasherz&DjangoTranslator.resolve_django_hasher  s    
 ;, //F/K /)n.A.AEY.Y11+>>//F~6:6P6PQ\6]]3M %%nV%DDr    r9   T)r   r   r   __doc__rD   rG   rN   rI   rC   rP   rU   rY   rW   dictrw   r   updater_   r   r   r   __classcell__rK   s   @r!   r@   r@      s     G   ! !C*
1>9@ #  	 &&) 	' 	
 =L8O)jEr    r@   c                   R    e Zd ZdZdZdZdZdZdZdZ	d" fd	Z
 fdZd Zd#dZd	 Zd$d
Zd$dZd Zd Zd ZdZdZedz   ZdZedz   d ed      fedz   d ed      fedz   dfedz   dfedz   dfedz   dfedz   dfedz   dfedz   dfedz   dfedz   dfgZd Zd Zd  Zd! Z xZS )%DjangoContextAdapteraC  
    Object which tries to adapt a Passlib CryptContext object,
    using a Django-hasher compatible API.

    When installed in django, :mod:`!passlib.ext.django` will create
    an instance of this class, and then monkeypatch the appropriate
    methods into :mod:`!django.contrib.auth` and other appropriate places.
    NTFc                    t        j                  t        dz         | _        |
t	               }t        t        |   d
d|i| |rt        |      sJ || _	        	 ddl
m}   |       | j                        | _        ddlm} |j"                  j%                  d      rt&        j)                  |      }|| _        ddlm} || _        t        j                  t        dz         }t'        |	      | _        y # t        $ r	 ddlm} Y w xY w)Nz.DjangoContextAdapterrD   r   )	lru_cache)make_passwordzpasslib.)is_password_usablez.DjangoContextAdapter._manager)logr   )logging	getLoggerr   r   r
   rB   r   rC   callableget_user_category	functoolsr   ImportErrordjango.utils.lru_cacher{   rq   r   r   rs   _PatchManagerpeek_unpatched_func_orig_make_passwordr   rt   )	rJ   rD   r   r;   r   r   r   mlogrK   s	           r!   rC   zDjangoContextAdapter.__init__  s     $$X0G%GH ?"nG"D2K7KdK -..%6D"	9+ '9;t'7'78 	>##..z:)==mLM#0  	C"4   ,L!LM%$/!  	98	9s   C5 5DDc                 H    ddl m}  |d       t        t        |           y)zH
        Wrapper to manually reset django's hasher lookup cache
        r   )rP   PASSWORD_HASHERS)settingN)rq   rP   rB   r   )rJ   rP   rK   s     r!   rP   z"DjangoContextAdapter.reset_hashers  s!    
 	>01 	"D79r    c                     | j                   }| j                  j                  d      D cg c]
  } ||       c}S c c}w )zq
        Passlib replacement for get_hashers() --
        Return list of available django hasher classes
        Tr   )rW   rD   r   )rJ   rW   r|   s      r!   r{   z DjangoContextAdapter.get_hashers  sK    
 !22"ll2242@B "&) B 	B Bs   =c                 $    | j                  |      S )z^
        Passlib replacement for get_hasher() --
        Return django hasher by name
        )r   )rJ   rX   s     r!   ri   zDjangoContextAdapter.get_hasher  s    
 )))44r    c                     | j                   j                  |dd      }|j                  dk(  r"|j                  d      r| j	                  d      S | j                  |      S )zl
        Passlib replacement for identify_hasher() --
        Identify django hasher based on hash.
        T)r   requiredr   zsha1$$r   )rD   identifyr1   rs   ri   rW   )rJ   encodedrS   s      r!   identify_hasherz$DjangoContextAdapter.identify_hasher  s[    
 ,,'''M<<//G4F4Fx4P ???33%%g..r    c                     || j                  d      S | j                  |      }d|j                  vrn8|j                  d      r|j	                  d      }n|r|j	                  |      }|j                  |      S )z9
        Passlib replacement for make_password()
        Nsalt	unsalted_ )r   )r   r   setting_kwdsrs   usinghash)rJ   passwordr   r|   ra   s        r!   r   z"DjangoContextAdapter.make_password#  s     ++D11 //7444{+ ,11r1:N ,11t1<N""8,,r    c                 \   || j                  |      sy| j                  }	 |j                  ||      }|r|s|S |dk(  r|j                  ||      s9|S | j                  |      }|j                  |      r|j                  ||      s|S  ||       |S # t        j                  $ r Y yw xY w)z:
        Passlib replacement for check_password()
        Fr   )secret)r   rD   verifyr   UnknownHashErrorneeds_updater   r   )rJ   r   r   setter	preferredrD   correctr|   s           r!   check_passwordz#DjangoContextAdapter.check_password:  s     4#:#:7#C ,,	nnXw7G FN 	!'''A ++I6F(++GH+E  	x; ## 	 	s   B B+*B+c                    |y|j                   }| j                  |      sy| j                  |      }	 | j                  j	                  |||      \  }}|r|||_         |j                          |S # t
        j                  $ r Y yw xY w)z?
        Passlib replacement for User.check_password()
        Fcategory)r   r   r   rD   verify_and_updater   r   save)rJ   userr   r   catoknew_hashs          r!   user_check_passwordz(DjangoContextAdapter.user_check_passwordl  s     }}&&t,$$T*	<<99(DSV9WLB
 (&$DMIIK	 ## 	 	s   !A2 2BBc                     ||j                          y| j                  |      }| j                  j                  ||      |_        y)z=
        Passlib replacement for User.set_password()
        Nr   )set_unusable_passwordr   rD   r   r   )rJ   r   r   r   s       r!   user_set_passwordz&DjangoContextAdapter.user_set_password  sA     &&(((.C LL--h-EDMr    c                 8    |j                   ry|j                  ryy)z
        Helper for hashing passwords per-user --
        figure out the CryptContext category for specified Django user object.
        .. note::
            This may be overridden via PASSLIB_GET_CATEGORY django setting
        	superuserstaffN)is_superuseris_staff)rJ   r   s     r!   r   z&DjangoContextAdapter.get_user_category  s     ]]r    zdjango.contrib.auth.hasherszdjango.contrib.auth.modelsz:Userzdjango.contrib.auth.formsz.check_passwordr   )r<   z.set_passwordr   :r   r   r{   ri   r   c                    | j                   }| j                  r|j                  d       yt        t        k  rt        dt              |j                  d       | j                  }| j                  D ]l  }t        |      dk(  r|i fz  }|\  }}}|j                  d      r||z  }t        | |      }|j                  d      rt        |      }|j                  ||       n | j                          d| _        |j                  d	       y)
zI
        Install monkeypatch to replace django hasher framework.
        z3monkeypatching already applied, refusing to reapplyFz&passlib.ext.django requires django >= z#preparing to monkeypatch django ...r   )r   ,r<   Tz"... finished monkeypatching django)r   rp   warningr   r   RuntimeErrordebugrt   patch_locationsr   endswithr.   rn   r>   patchrP   )rJ   r   managerrecordtargetsourceoptsvalues           r!   install_patchz"DjangoContextAdapter.install_patch  s   
 hh<<KKMN .. 2 5 6 6 			78 --** 	)F6{a2%#) FFDz*& D&)Exx! %U+MM&%(	) 	 		67r    c                    | j                   }| j                  }| j                  rg|j                  d       |j	                  d       | j
                  j                  i        d| _        | j                          |j                  d       y|j                         r^|j                  d       |j	                          | j
                  j                  i        | j                          |j                  d       y|j                  d       y)a  
        Remove monkeypatch from django hasher framework.
        As precaution in case there are lingering refs to context,
        context object will be wiped.

        .. warning::
            This may cause problems if any other Django modules have imported
            their own copies of the patched functions, though the patched
            code has been designed to throw an error as soon as possible in
            this case.
        z!removing django monkeypatching...T)unpatch_conflictsFz*...finished removing django monkeypatchingz-reverting partial monkeypatching of django...zdjango not monkeypatched)
r   rt   rp   r   unpatch_allrD   loadrP   isactiver   )rJ   r   r   s      r!   remove_patchz!DjangoContextAdapter.remove_patch  s     hh--<<II9:$7LLb! DL IIBCKKGH!LLb! IIBC		,-r    c                    | j                          | j                  r	 | j                          n1| j                  rt
        j                  d       | j                          t
        j                  d       y#  | j                           xY w)zD
        Load configuration from django, and install patch.
        z.didn't expect monkeypatching would be applied!zpasslib.ext.django loadedN)_load_settingsenabledr   r   rp   r   errorr   rO   s    r!   
load_modelzDjangoContextAdapter.load_model  sm     	<<""$ ||		JK		-.!!#s   A6 6B	c                    ddl m} t               }t        |d|      }||u rt        |d|      }||u rd}|t	        dt
               d}n2t        |t        t        t        f      st        j                  |d	d      t        |d
d      }|r"t        |      st        j                  |dd
      |dk(  rd| _        y| j                  j                  dd       t        |t               rd|vrt#        |      }|r|| _        n| j                  j                  dd       | j&                  j)                  |       | j+                          y)z-
        Update settings from django
        r   )settingsPASSLIB_CONFIGPASSLIB_CONTEXTr(   Nz}setting PASSLIB_CONFIG=None is deprecated, and support will be removed in Passlib 1.8, use PASSLIB_CONFIG='disabled' instead.disabledzstr or dictPASSLIB_GET_CATEGORYr   Fr   
get_category)django.confr   objectr.   r   DeprecationWarningr   r   bytesr   r   ExpectedTypeErrorr   r   __dict__poprr   r   r   rD   r   rP   )rJ   r   _UNSETconfigr   s        r!   r   z#DjangoContextAdapter._load_settings#  s?    	) #3V<VX'8&AFV&F> : $%  FFWeT$:;''?OPP x)?F 6''jBXYY Z DLMMi. fc"t6'9&v.F %1D"MMnd3 	&!r    )NN)r   )Nr   )r   r   r   r   rD   r   r   rt   r   rp   rC   rP   r{   ri   r   r   r   r   r   r   HASHERS_PATHMODELS_PATHUSER_CLASS_PATH
FORMS_PATHr   r   r   r   r   r   r   r   s   @r!   r   r     sM    G   H G G
"0H	: B5/"-.,d,F$ 1L.K!G+O,J 
,	,.CTQUEVW	?	*,?TARS
 
	-.		_-		]+		\*		./
 
s	,-	s	O,	c	<(	c	,-1O8(T!N/$6r    r   z--!!!generate-new-salt!!!--c                   (    e Zd ZdZd Zd Zd Zd Zy)ProxyPropertyz%helper that proxies another attributec                     || _         y r9   )r2   )rJ   r2   s     r!   rC   zProxyProperty.__init__g  s	    	r    c                 6    ||}t        || j                        S r9   )r.   r2   )rJ   objclss      r!   __get__zProxyProperty.__get__j  s    ;CsDII&&r    c                 2    t        || j                  |       y r9   )setattrr2   )rJ   r  r   s      r!   __set__zProxyProperty.__set__o  s    TYY&r    c                 0    t        || j                         y r9   )delattrr2   )rJ   r  s     r!   
__delete__zProxyProperty.__delete__r  s    TYYr    N)r   r   r   r   rC   r  r  r  r   r    r!   r  r  d  s    /'
' r    r  c                       e Zd ZdZdZd Zd Zed        Z ed        Zed        Z	ed        Z
d	 Zd
 ZddZd Zd Zy)r`   z
    adapter which which wraps a :cls:`passlib.ifc.PasswordHash` class,
    and provides an interface compatible with the Django hasher API.

    :param passlib_handler:
        passlib hash handler (e.g. :cls:`passlib.hash.sha256_crypt`.
    Nc                     t        |dd       rt        d|j                        |j                  rt        d|j                  z        || _        | j
                  r"|j                  | _        t        d      | _	        y y )Nr]   zFhandlers that reflect an official django hasher shouldn't be wrapped: z%can't wrap disabled-hash handlers: %rrounds)
r.   r)   r1   is_disabledr   _has_roundsdefault_roundsr  r  
iterations)rJ   r   s     r!   rC   z_PasslibHasherWrapper.__init__  s    ?M48-225 6 6 &&D-224 5 5. )88DK+H5DO r    c                      d| j                   z  S )Nz!<PasslibHasherWrapper handler=%r>)r   rO   s    r!   __repr__z_PasslibHasherWrapper.__repr__  s    2T5I5IIIr    c                 P    d| j                   j                  j                         z  S )NzPasslib_%s_PasswordHasher)r   r1   titlerO   s    r!   r   z_PasslibHasherWrapper.__name__  s"    *T-A-A-F-F-L-L-NNNr    c                 2    d| j                   j                  v S )Nr  )r   r   rO   s    r!   r  z!_PasslibHasherWrapper._has_rounds  s    4//<<<<r    c                 p    t        d      }| j                  rd| j                  j                  v rd|d<   |S )zy
        internal helper for safe_summary() --
        used to translate passlib hash options -> django keywords
        r   )checksumpbkdf2r  r  )r   r  r   r1   )rJ   outs     r!   _translate_kwdsz%_PasslibHasherWrapper._translate_kwds  s8     F#D,@,@,E,E E(CM
r    c                 <    t         | j                  j                  z   S r9   )r   r   r1   rO   s    r!   rX   z_PasslibHasherWrapper.algorithm  s    %(<(<(A(AAAr    c                     t         S r9   )_GEN_SALT_SIGNALrO   s    r!   r   z_PasslibHasherWrapper.salt  s
      r    c                 :    | j                   j                  ||      S r9   )r   r   )rJ   r   r   s      r!   r   z_PasslibHasherWrapper.verify  s    ##**8W==r    c                    i }||t         k7  r||d<   | j                  r |||d<   n4|||d<   n,| j                  |d<   n||t        d| j                  z         | j
                  }|r |j                  di |}|j                  |      S )Nr   r  z0%s.hash(): 'rounds' and 'iterations' are ignoredr   )r,  r  r  r   r   r   r   r   )rJ   r   r   r  r  r;   rS   s          r!   encodez_PasslibHasherWrapper.encode  s    (8 8DL!!'X'!+X!%X:#9CdmmST&&#gmm+d+G||H%%r    c                 @   ddl m} ddlm} | j                  } |d      |j
                  fg}t        |d      r[|j                  ||      }t        |      D ]:  \  }}| j                  j                  ||      }|j                   ||      |f       < t        |      S )Nr   )	mask_hash)ugettext_nooprX   	parsehash)sanitize)rq   r1  django.utils.translationr2  r   r1   r^   r3  r   r)  rn   appendr   )	rJ   r   r1  _rS   itemsr;   keyr   s	            r!   safe_summaryz"_PasslibHasherWrapper.safe_summary  s    9?&& {^W\\*

 7K($$Wy$AD'o .
U**..sC8afe_-. 5!!r    c                     | j                   rC| j                  j                  | j                  | j                        }|j	                  |      ryy)N)
min_rounds
max_roundsTF)r  r   r   r  r   )rJ   r   subclss      r!   must_updatez!_PasslibHasherWrapper.must_update  sI      ))//4;;SWS^S^/_F""7+r    )NNN)r   r   r   r   r   rC   r!  r   r  r)  rX   r   r   r/  r:  r?  r   r    r!   r`   r`   v  s     O6(J O O = =   B B >&$" 
r    r`   c                       e Zd ZdZddZd ZexZZd Ze	d        Z
efdZddZdd	Zdd
Zd ZddZed        ZddZddZd Zy)r   z4helper to manage monkeypatches and run sanity checksNc                 \    |xs t        j                  t        dz         | _        i | _        y )Nz._PatchManager)r   r   r   r   _state)rJ   r   s     r!   rC   z_PatchManager.__init__b  s(     H'++H7G,GHr    c                 ,    t        | j                        S r9   )boolrB  rO   s    r!   r   z_PatchManager.isactiveh  s    DKK  r    c                     |j                  d      \  }}t        ||gd      }d|v r&|j                  dd      \  }}t        ||      }d|v r&||fS )z8retrieve obj and final attribute name from resource pathr   r   )fromlistlevelrj   r   )split
__import__r.   )rJ   r}   r1   r2   r  heads         r!   _import_pathz_PatchManager._import_patho  s_    ZZ_
da8Tk

3*:4d#3 Tk Dyr    c                 0    t        |       t        |      k(  S )zAcheck if two values are the same (stripping method wrappers, etc))r   )leftrights     r!   _is_same_valuez_PatchManager._is_same_valuex  s     #4(,?,FFFr    c                 D    | j                  |      \  }}t        |||      S r9   )rK  r.   )rJ   r9  r   r  r2   s        r!   	_get_pathz_PatchManager._get_path  s%    %%c*	TsD'**r    c                 &    | j                  ||      S )zreturn current value for path)rQ  )rJ   r}   r   s      r!   rn   z_PatchManager.get  s    ~~dG,,r    c                     	 | j                   |   \  }}|t        u r|S |S # t        $ r | j                  |      }Y (w xY w)z*return original (unpatched) value for path)rB  r,   rQ  r  )rJ   r}   r   r   r7  s        r!   ru   z_PatchManager.getorig  sK    	)kk$'HE1  6/w4u4  	)NN4(E	)s     ==c                     | j                   }t        | j                        D ]C  \  }\  }} || j                  |      |      r"d|z  }|rt	        |      t        |t               E y)z:run sanity check on all keys, issue warning if out of syncz(another library has patched resource: %rN)rO  r   rB  rQ  r   r   r   )rJ   strictsamer}   origexpectedmsgs          r!   	check_allz_PatchManager.check_all  sh    ""&/&< 	1"D"4DNN4((3<tCC"3''S/0	1r    c                     | j                  |      \  }}|t        u rt        ||      rt        ||       y y t	        |||       y r9   )rK  r  r^   r  r  )rJ   r}   r   r  r2   s        r!   	_set_pathz_PatchManager._set_path  sD    %%d+	TF?sD!T" " Cu%r    c                   	 |t         k7  sJ | j                  |      }	 | j                  |   \  }}| j                  j	                  d|       | j                  ||      st        d|z  t               	 |r%t        |      sJ ||		fd}t        ||       |}t        |      r|t        |      _        | j                  ||       ||f| j                  |<   y# t        $ r! | j                  j	                  d|       |}Y w xY w)zBmonkeypatch object+attr at <path> to have <value>, stores originalzmodifying resource: %rz4overridding resource another library has patched: %rzpatching resource: %rc                       g| i |S r9   r   )r:   r;   wrapped
wrapped_bys     r!   r=   z$_PatchManager.patch.<locals>.wrapper  s    !'9D9D99r    N)r  rQ  rB  r   r   rO  r   r   r,   r   r   r   _patched_original_valuer\  )
rJ   r}   r   wrapcurrentrW  rX  r=   r_  r`  s
           @@r!   r   z_PatchManager.patch  s    ..&		4![[.ND(
 HHNN3T:&&w9K24E?"GJ:7E*EE?AE&>tU#!5MD)  	HHNN2D9D	s   C 'DDc                     |j                   S r9   )ra  )r  r   s     r!   r   z!_PatchManager.peek_unpatched_func  s    ,,,r    c                 R      fd}t              r}d ||       y|S )zBfunction decorator which patches function of same name in <parent>c                 p    r2dv rdnd}|z   xs | j                   z   }j                  ||        | S )Nr   rj   )rb  )r   r   )funcsepr}   enabler1   parentrJ   rb  s      r!   builderz*_PatchManager.monkeypatch.<locals>.builder  sA     F]c|t'<t}}=

4D
1Kr    N)r   )rJ   rj  r1   ri  rb  rk  rg  s   `````  r!   monkeypatchz_PatchManager.monkeypatch  s/    	 	 D>DDDMr    c                 r   	 | j                   |   \  }}| j                  |      }| j                  j	                  d|       | j                  ||      s7|rt        d|z  t               n!t        d|z  t               | j                   |= y | j                  ||       | j                   |= y # t        $ r Y y w xY w)Nzunpatching resource: %rz2reverting resource another library has patched: %rz6not reverting resource another library has patched: %r)	rB  r,   rQ  r   r   rO  r   r   r\  )rJ   r}   r   rW  rX  rc  s         r!   unpatchz_PatchManager.unpatch  s    	![[.ND( ..&0$7""7H5 I24 M24KK%tT"KK  		s   B* *	B65B6c                 ^    t        | j                        D ]  } | j                  |fi |  y r9   )listrB  rn  )rJ   r;   r9  s      r!   r   z_PatchManager.unpatch_all  s-    $ 	&CDLL%%	&r    r9   )F)NTFr   )r   r   r   r   rC   r   __bool____nonzero__rK  staticmethodrO  r  rQ  rn   ru   rZ  r\  r   classmethodr   rl  rn  r   r   r    r!   r   r   X  s|    >!
 &%H{ G G &, +-5
1&*8 - -&&&r    r   )2r   r   r   r   r   r   r   r   rl   rE   warningsr   djangor   r   r   r   r3   r   r	   passlib.contextr
   passlib.excr   passlib.utils.compatr   r   r   r   passlib.utils.decorr   __all__r   r   r+   r   r*   r   r   setr   r>   r   r@   r   r,  r  r`   r  r   r   r    r!   <module>r}     s4   E
 , 'g''1 
  0II,n=
 " ( - U U 1  
: 
:$ %$$%	3: N $  !  I;' LEv LEjn+ nn 1  F  $EF E@ 
\&F \&S"  II-.Ns   C C65C6