
    g              
          S r SSKJrJr  SSKr\R
                  " \5      rSSKrSSK	r	SSK
Jr  SrSqSSKJr  SSKJr  SSKJrJrJr  SSKJrJr  SS	KJrJrJrJrJr  SSKJ s  J!r"  S
/r#\" S5      r$\" S5      r%\" S5      r&\&\$\%4r'\(" \'5      r)Sr* SSK+r\," \S5      (       d  Sr*SrO\," \S5      (       d  Sr*Sr\," \S5      (       a(  \R\                  " 5       r/\R`                  Rb                  r2O " S S5      r3\3" 5       r/Sr2 " S S\"Rh                  \"Rj                  \"Rl                  \"Rn                  \"Rp                  \"Rr                  5      r: " S S\:5      r; " S S\:5      r< " S S\:5      r= " S S
\;\:5      r+g! \- a    Sr Nf = f)a  passlib.handlers.argon2 -- argon2 password hash wrapper

References
==========
* argon2
    - home: https://github.com/P-H-C/phc-winner-argon2
    - whitepaper: https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
* argon2 cffi wrapper
    - pypi: https://pypi.python.org/pypi/argon2_cffi
    - home: https://github.com/hynek/argon2_cffi
* argon2 pure python
    - pypi: https://pypi.python.org/pypi/argon2pure
    - home: https://github.com/bwesterb/argon2pure
    )with_statementabsolute_importN)warn)exc)
MAX_UINT32)classpropertyto_bytesrender_bytes)b64s_encodeb64s_decode)uunicodebascii_to_struascii_to_strPY2argon2ididTypezb'argon2' module points to unsupported 'argon2' pypi package; please install 'argon2-cffi' instead.	low_levelz@'argon2-cffi' is too old, please update to argon2_cffi >= 18.2.0PasswordHasherc                   ,    \ rS rSrSrSrSrSrSrSr	Sr
g)_DummyCffiHasher]   z
dummy object to use as source of defaults when argon2_cffi isn't present.
this tries to mimic the attributes of ``argon2.PasswordHasher()`` which the rest of
this module reads.

.. note:: values last synced w/ argon2 19.2 as of 2019-11-09
   i       N)__name__
__module____qualname____firstlineno____doc__	time_costmemory_costparallelismsalt_lenhash_len__static_attributes__r       P/home/matz/Project1/venv/lib/python3.13/site-packages/passlib/handlers/argon2.pyr   r   ]   s"    	 	r*   r      c                     ^  \ rS rSrSrSrSr\R                  r	\
R                  R                  S-   r\
R                  R                  S-   r\R                  rSr\r\R&                  rSr\rS	rS
r\rSrSrSrSr0 r\ S 5       r!\"r#\RH                  r$\r%\RL                  r&\'S 5       r(Sr)\*  S!U 4S jj5       r+\*S 5       r,\-R\                  " S5      r/\*S 5       r0\-R\                  " S\-Rb                  5      r2\*S 5       r3S r4S"U 4S jjr5\*S 5       r6\*S 5       r7\*S#S j5       r8\*S 5       r9U 4S jr:Sr;\*S 5       r<\*S$S j5       r=S r>U =r?$ )%_Argon2Commons   a  
Base class which implements brunt of Argon2 code.
This is then subclassed by the various backends,
to override w/ backend-specific methods.

When a backend is loaded, the bases of the 'argon2' class proper
are modified to prepend the correct backend-specific subclass.
r   )
salt	salt_sizer'   roundsr$   r%   r&   digest_sizer(   type)r4   )r'   r$   r(   r3         lineari NFc                 L    U R                  5         [        U R                  5      $ )zJ
return tuple of types supported by this backend

.. versionadded:: 1.7.2
)get_backendtuple_backend_type_map)clss    r+   type_values_Argon2Common.type_values   s     	S**++r*   c                 (    U R                   [        :H  $ )zV
flag indicating a Type D hash

.. deprecated:: 1.7.2; will be removed in passlib 2.0
)r4   TYPE_Dselfs    r+   type_d_Argon2Common.type_d   s     yyF""r*   c	           	      6  > Ub  SU	;   a  [        S5      eXIS'   Ub  SU	;   a  [        S5      eX9S'   Ub  Ub  [        S5      eUnUb  Ub  [        S5      eUn[        [        U ]  " S0 U	D6n
Ub  U
R	                  U5      U
l        U	R                  S5      nUbK  [        U[        R                  5      (       a  [        U5      n[        R                  " XS[        S	US
9U
l        Ub>  [        U[        R                  5      (       a  [        U5      nU
R                  X+S9U
l        U
R!                  U
R                  U
R"                  5        UbK  [        U[        R                  5      (       a  [        U5      nUS:  a  US:w  a  [%        SU4-  5      eXl        U
$ )Nr2   z/'time_cost' and 'rounds' are mutually exclusiver1   z1'salt_len' and 'salt_size' are mutually exclusivez3'hash_len' and 'digest_size' are mutually exclusivez8'checksum_size' and 'digest_size' are mutually exclusiverelaxedr   r3   )minmaxparamrG   )rG   r6   r8   z7max_threads (%d) must be -1 (unlimited), or at least 1.r   )	TypeErrorsuperr.   using
_norm_typer4   get
isinstanceuhnative_string_typesintnorm_integerr   checksum_size_norm_memory_costr%   _validate_constraintsr&   
ValueErrormax_threads)r=   r4   r%   r'   r$   r3   rU   r(   rY   kwdssubclsrG   	__class__s               r+   rM   _Argon2Common.using  s     4 QRR&Nd" STT (& UVV"K$& Z[['K }c0848  ++D1FK ((9%"+r'='=>>!+.#%??6BT^9FPW$YF  "+r'='=>>!+.!'!9!9+!9!WF 	$$V%7%79K9KL "+r'='=>>!+.Q;"#4 !Z"-"0 1 1!,r*   c                 N    SU-  nX:  a  [        SU R                  UX#4-  5      eg )Nr5   zO%s: memory_cost (%d) is too low, must be at least 8 * parallelism (8 * %d = %d))rX   name)r=   r%   r&   min_memory_costs       r+   rW   #_Argon2Common._validate_constraintsB  s@     k/( =!hh)<< = = )r*   z^\$argon2[a-z]+\$c                 h    [         R                  " U5      nU R                  R                  U5      S L$ N)rQ   to_unicode_for_identify_ident_regexmatch)r=   hashs     r+   identify_Argon2Common.identifyT  s.    ))$/%%d+477r*   s  
        ^
        \$argon2(?P<type>[a-z]+)\$
        (?:
            v=(?P<version>\d+)
            \$
        )?
        m=(?P<memory_cost>\d+)
        ,
        t=(?P<time_cost>\d+)
        ,
        p=(?P<parallelism>\d+)
        (?:
            ,keyid=(?P<keyid>[^,$]+)
        )?
        (?:
            ,data=(?P<data>[^,$]+)
        )?
        (?:
            \$
            (?P<salt>[^$]+)
            (?:
                \$
                (?P<digest>.+)
            )?
        )?
        $
    c                 z   [        U[        5      (       a  UR                  S5      n[        U[        5      (       d  [        R
                  " US5      eU R                  R                  U5      nU(       d  [        R                  " U 5      eUR                  SSSSSSS	S
S5	      u	  p4pVpxpnU(       a  [        S5      eU " UR                  S5      U(       a  [        U5      OS[        U5      [        U5      [        U5      U
(       a  [        U
5      OS U	(       a  [        U	5      OS U(       a  [        U5      S9$ S S9$ )Nutf-8rg   r4   versionr%   r$   r&   keyiddatar0   digestz&argon2 'keyid' parameter not supportedasciir   )r4   rl   r%   r2   r&   r0   rn   checksum)rP   r   encodebytesr   ExpectedStringError_hash_regexrf   MalformedHashErrorgroupNotImplementedErrordecoderS   r   )r=   rg   mr4   rl   r%   r$   r&   rm   rn   r0   ro   s               r+   from_string_Argon2Common.from_string  s    dG$$;;w'D$&&))$77OO!!$'((--GGFI}k=VVX7 	V{{4v %&NOOW%$+CLK(y>K(&*T"&*T",2[(	
 		
 9=	
 		
r*   c                    U R                   nUS:X  a  SnOSU-  nU R                  nU(       a"  S[        [        U R                  5      5      -   nOSnS[	        U R
                  5      UU R                  U R                  U R                  U[        [        U R                  5      5      [        [        U R                  5      5      4-  $ )Nr    zv=%d$z,data=z"$argon2%s$%sm=%d,t=%d,p=%d%s$%s$%s)rl   rn   r   r   r   r4   r%   r2   r&   r0   rq   )rC   rl   vstrrn   kdstrs        r+   	to_string_Argon2Common.to_string  s    ,,d?DW$Dyy}[-CDDEE 4$))$KK+dii01+dmm45	7
 	
 		
r*   c                   > U(       a  [        S5        Ub   e[        nUR                  S5      nUb  [        U5      U l        [
        [        U ]  " S	0 UD6  Uc2  [        R                  " X R                  U R                  SS9(       d   eOU R                  U5      U l
        Uc2  [        R                  " X R                  U R                  SS9(       d   eOU R                  U5      U l        Uc2  [        R                  " X R                  U R                  SS9(       d   eOU R                  U5      U l        Uc  U R                   b   eg [#        U[$        5      (       d!  [        R&                  R)                  USS5      eXPl        g )
Nzoargon2 `type_d=True` keyword is deprecated, and will be removed in passlib 2.0; please use ``type="d"`` insteadrq   r4   )rJ   rl   r%   rs   rn   r   )r   rA   rO   lenrU   rL   r.   __init__rQ   validate_default_valuer4   rN   rl   _norm_versionr%   rV   rn   rP   rs   r   ExpectedTypeError)	rC   r4   rD   rl   r%   rn   rZ   rq   r\   s	           r+   r   _Argon2Common.__init__  sc     3 4<<D 88J'!$XD 	mT+3d3 <,,T99dooU[\\\-DI ?,,T<<ASAS3<> > >  --g6DL ,,T3C3CTE[E[3@B B B  $55kBD <99$$$dE**ff..tWfEEIr*   c                 @   [        U[        5      (       dS  [        (       a'  [        U[        5      (       a  UR	                  S5      nO![
        R                  R                  USS5      eU[        ;   a  U$ UR                  5       nU[        ;   a  U$ [        SU< 35      e)Nrp   strr4   zunknown argon2 hash type: )rP   r   r   rs   ry   rQ   r   r   ALL_TYPES_SETlowerrX   )r=   valuetemps      r+   rN   _Argon2Common._norm_type  s     %))sz%//W-ff..ueVDD M!L {{}= K 5BCCr*   c                 D   [        U[        R                  5      (       d!  [        R                  R	                  USS5      eUS:  a  US:w  a  [        SU4-  5      eU R                  5       nXR                  :  a%  [        SU R                  XU R                  4-  5      eU$ )Nintegerrl   r,   r   zinvalid argon2 hash version: %dzk%s: hash version 0x%X not supported by %r backend (max version is 0x%X); try updating or switching backends)	rP   rQ   	int_typesr   r   rX   r:   max_versionr_   )r=   rl   backends      r+   r   _Argon2Common._norm_version	  s    '2<<00&&**7IyII T>go>'KLL //#__$ Y!hh#//JK L L r*   c                 D    [         R                  " XU R                  SUS9$ )Nr%   )rH   rJ   rG   )rQ   rT   r`   )r=   r%   rG   s      r+   rV   _Argon2Common._norm_memory_cost  s$    sS5H5H%2GE 	Er*   c                      U R                   U   $ ! [         a     Of = fSU< SU R                  5       < S3n[        U5      e)z.
helper to resolve backend constant from type
zunsupported argon2 hash (type z not supported by z	 backend))r<   KeyErrorr:   rX   )r=   r   msgs      r+   _get_backend_type_Argon2Common._get_backend_type%  sL    
	((// 		 coo')os    
c                 Z  > [        U 5      nU R                   UR                   :w  a  gUR                  nUb  X2R                  :  a  UR                  nU R                  U:  a  gU R                  UR                  :w  a  gU R
                  UR
                  :w  a  g[        [        U ]"  " S0 UD6$ )NTr   )	r4   min_desired_versionr   rl   r%   rU   rL   r.   _calc_needs_update)rC   rZ   r=   minverr\   s       r+   r    _Argon2Common._calc_needs_update7  s    4j99 ((>Voo5__F<<& s.!2!22]D<DtDDr*   z> -- recommend you install one (e.g. 'pip install argon2_cffi')c                 \   U R                   n[        U[        5      (       a  US:  d   eUS:  a'  [        SU-  [        R
                  R                  5        [         H  nX@R                  ;   d  M  X@l	          g   [        SU-  [        R
                  R                  5        [        U l	        g)z
helper called by from backend mixin classes' _load_backend_mixin() --
invoked after backend imports have been loaded, and performs
feature detection & testing common to all backends.
r   r,   z6%r doesn't support argon2 v1.3, and should be upgradedz)%r lacks support for all known hash typesT)r   rP   rS   r   rQ   r   PasslibSecurityWarning	ALL_TYPESr<   r4   PasslibRuntimeWarningTYPE_ID)	mixin_clsr_   dryrunr   r4   s        r+   _finalize_backend_mixin%_Argon2Common._finalize_backend_mixinM  s      +++s++t0CCCIDP..0 D222!%  
 <tCRVVEaEab$INr*   c                 Z   U R                  5       nUc  Ub  U R                  U5      nUbD  UR                  UR                  UR                  5        US:X  a  UR
                  b  [        S5      e[        U5      nUS;  a  U< SU< SU< 3nO[        U5      n[        R                  " XS9e)ze
internal helper invoked when backend has hash/verification error;
used to adapt to passlib message.
argon2_cffiz8argon2_cffi backend doesn't support the 'data' parameter)zDecoding failedz reported: z: hash=)reason)r:   r{   rW   r%   r&   rn   rx   r   reprr   rv   )r=   errrg   rC   r   textr   s          r+   _adapt_backend_error"_Argon2Common._adapt_backend_errorg  s     //# <D,??4(D &&t'7'79I9IJ -'DII,A)*dee 3x   4;D$GF$ZF$$S88r*   )rU   rn   r%   r4   rl   )NNNNNNNN)NFNNN)F)NN)@r   r    r!   r"   r#   r_   setting_kwds_default_settingsr(   rU   rQ   GenericHandler_always_parse_settings_unparsed_settingsr'   default_salt_sizemin_salt_sizer   max_salt_sizer$   default_rounds
min_rounds
max_roundsrounds_costmax_parallelism_default_versionr   r   r`   rY   pure_use_threadsr<   r   r>   r   r4   r&   rl   r%   propertyrD   rn   classmethodrM   rW   recompilere   rh   Xru   r{   r   r   rN   r   rV   r   r   _no_backend_suggestionr   r   r)   __classcell__r\   s   @r+   r.   r.   s   s/     D
L0 &..M  ..EE&' **==MN *22MM '00NJJK
 $O #K  O K 
 , , D $//K G $//K# # D [_=A9 9v = = ::23L8 82 ** 6 
7K: 
 
4
8,d D D(    E E  "E( ^ 2 9 9r*   r.   c                      ^  \ rS rSrSr\S 5       r\S 5       r\R                  " SSS9\S 5       5       r
U 4S	 jrS
rU =r$ )
_NoBackendi  zt
mixin used before any backend has been loaded.
contains stubs that force loading of one of the available backends.
c                 D    U R                  5         U R                  U5      $ rc   )_stub_requires_backendrg   )r=   secrets     r+   rg   _NoBackend.hash  s    ""$xxr*   c                 D    U R                  5         U R                  X5      $ rc   )r   verify)r=   r   rg   s      r+   r   _NoBackend.verify  s    ""$zz&''r*   z1.7z2.0)
deprecatedremovedc                 D    U R                  5         U R                  X5      $ rc   )r   genhash)r=   r   configs      r+   r   _NoBackend.genhash  s     	""${{6**r*   c                 J   > U R                  5         [        [        U ]  U5      $ rc   )r   rL   r   _calc_checksum)rC   r   r\   s     r+   r   _NoBackend._calc_checksum  s%     	##% VT1&99r*   r   )r   r    r!   r"   r#   r   rg   r   rQ   deprecated_methodr   r   r)   r   r   s   @r+   r   r     sc         ( ( UE:+  ;+: :r*   r   c                   |    \ rS rSrSr\S 5       r\S 5       r\" S \	 5       5      r
\S 5       r\S 5       rS rS	rg
)_CffiBackendi  z
argon2_cffi backend
c                    U [         L d   e[        c&  [        (       a  [        R                  " [        5      eg[        R
                  R                  n[        R                  S[        R                  U5        [        R                  n0 n[         H  n [        XFR                  5       5      XV'   M!     XPl        U=U l        U l        U R)                  X5      $ ! [         a    U[        [         4;  d
   SU-  5       e Mo  f = f)NFzOdetected 'argon2_cffi' backend, version %r, with support for 0x%x argon2 hashesunexpected missing type: %r)r   _argon2_cffi_argon2_cffi_errorr   PasslibSecurityErrorr   ARGON2_VERSIONlogdebug__version__r   r   getattrupperAttributeErrorTYPE_IrA   r<   rl   r   r   )r   r_   r   r   TypeEnumtype_mapr4   s          r+   _load_backend_mixin _CffiBackend._load_backend_mixin  s     L((( !!../ABB",,;;		c**K	9  $$DZ!(::<!@  '/# 5@?	I100>> " ZFF#33Y5RUY5YY3Zs   C$D ?D c                    [         R                  " U5        [        US5      n [        [        R
                  R                  U R                  U R                  5      U R                  U R                  U R                  [        U R                  5       5      U R                  US95      $ ! [        R                  R                   a  nU R!                  U5      eS nAff = f)Nrk   )r4   r%   r$   r&   r0   r(   r   )rQ   validate_secretr	   r   r   r   hash_secretr   r4   r%   r   r&   _generate_saltrU   
exceptionsHashingErrorr   )r=   r   r   s      r+   rg   _CffiBackend.hash  s     	6"&'*	0 !7!7!C!C**3884OO,,OOc0023** "D "   &&33 	0**3//	0s   BB( (CCCc              #   \   #    U  H"  n[        S UR                  S5      5      U4v   M$     g7f)s
   $argon2%s$rp   N)r
   rr   ).0r4   s     r+   	<genexpr>_CffiBackend.<genexpr>  s,      2'0t )G8LMtT'0s   *,c           	         [         R                  " U5        [        US5      n[        US5      nU R                  R	                  US SUR                  SS5      -    [        5      nU R                  U5      n [        R                  R                  X!U5      nUSL d   eg! [        R                  R                   a     g[        R                  R                   a  nU R                  XbS9eS nAff = f)Nrk   rp   r6      $TFrg   )rQ   r   r	   _byte_ident_maprO   findr   r   r   r   verify_secretr   VerifyMismatchErrorVerificationErrorr   )r=   r   rg   r4   	type_coderesultr   s          r+   r   _CffiBackend.verify  s     	6"&'*g& ""&&t,AQtyyq/A-A'BFK))$/		;!++99$	RFT>!>&&:: 	&&88 	;**3*::	;s   7'B C0?C0C++C0c                 2   [         R                  " U5        [        US5      nU R                  U5      n [	        [
        R                  R                  U R                  UR                  5      UR                  UR                  UR                  [        UR                  5      UR                  UUR                  S95      nUR                  S:X  a  UR'                  SS5      nU$ ! [
        R                   R"                   a  nU R%                  XRS9eS nAff = f)Nrk   )r4   r%   r$   r&   r0   r(   r   rl   r   r   z$v=16$$)rQ   r   r	   r{   r   r   r   r   r   r4   r%   r2   r&   r0   rU   rl   r   r   r   replace)r=   r   r   rC   r  r   s         r+   r   _CffiBackend.genhash  s     	6"&'*v&	="<#9#9#E#E**4995 ,,++ ,,dii(++ $F 	$ 	F <<4^^Hc2F &&33 	=**3*<<	=s   BC$ $DDDc                     [        S5      e)Nz-shouldn't be called under argon2_cffi backend)AssertionError)rC   r   s     r+   r   _CffiBackend._calc_checksum*  s    LMMr*   r   N)r   r    r!   r"   r#   r   r   rg   dictr   r   r   r   r   r)   r   r*   r+   r   r     sv     ? ?> 0 0&  2'02 2O ; ;,  6Nr*   r   c                   .    \ rS rSrSr\S 5       rS rSrg)_PureBackendi4  z
argon2pure backend
c                    U [         L d   e SS Kq SSKJn  [
        R                  SU5        U(       d  [        S[        R                  5        0 n[         H'  n [        [        SUR                  5       -   5      XE'   M)     X@l        U=U l        U l        U R)                  X5      $ ! [         a     gf = f! [         a    [
        R                  S5         gf = f! [         a    U[        [         4;  d
   SU-  5       e M  f = f)	Nr   F)ARGON2_DEFAULT_VERSIONz\detected 'argon2pure' backend, but package is too old (passlib requires argon2pure >= 1.2.3)zBdetected 'argon2pure' backend, with support for 0x%x argon2 hasheszUsing argon2pure backend, which is 100x+ slower than is required for adequate security. Installing argon2_cffi (via 'pip install argon2_cffi') is strongly recommendedARGON2r   )r  
argon2pure_argon2pureImportErrorr  r   warningr   r   r   r   r   r   r   r   r   rA   r<   rl   r   r   )r   r_   r   r   r   r4   s         r+   r    _PureBackend._load_backend_mixin<  s    L(((	,
	H 			V	  +,/,F,FH
 DZ!(h6M!N  '/#4??	I100>>=  		  	KK A B	$ " ZFF#33Y5RUY5YY3Zs4   B' B7 #C'
B43B47CC$DDc                 >   [         R                  " U5        [        US5      n[        UU R                  U R
                  U R                  U R                  U R                  U R                  U R                  5      U R                  S9nU R                  S:  a  U R                  US'   U R                  (       a  SUS'   U R                  (       a  U R                  US'    [        R                   " S	0 UD6$ ! [        R"                   a  nU R%                  X0S9eS nAff = f)
Nrk   )passwordr0   r$   r%   r&   
tag_lengthr  rl   r   threadsTuse_threadsassociated_datarB   r   )rQ   r   r	   r  r0   r2   r%   r&   rU   r   r4   rl   rY   r   rn   r  r   Argon2Errorr   )rC   r   rZ   r   s       r+   r   _PureBackend._calc_checksumn  s    
6"&'*kk(((()),,TYY7LL	
 a"..DO  "&D99&*iiD"#	<%%---&& 	<++C+;;	<s   C4 4DDDr   N)	r   r    r!   r"   r#   r   r   r   r)   r   r*   r+   r  r  4  s!     &? &?b<r*   r  c                   ,    \ rS rSrSrSrSr\\\	S.r
Srg)r   i  a  
This class implements the Argon2 password hash [#argon2-home]_, and follows the :ref:`password-hash-api`.

Argon2 supports a variable-length salt, and variable time & memory cost,
and a number of other configurable parameters.

The :meth:`~passlib.ifc.PasswordHash.replace` method accepts the following optional keywords:

:type type: str
:param type:
    Specify the type of argon2 hash to generate.
    Can be one of "ID", "I", "D".

    This defaults to "ID" if supported by the backend, otherwise "I".

:type salt: str
:param salt:
    Optional salt string.
    If specified, the length must be between 0-1024 bytes.
    If not specified, one will be auto-generated (this is recommended).

:type salt_size: int
:param salt_size:
    Optional number of bytes to use when autogenerating new salts.

:type rounds: int
:param rounds:
    Optional number of rounds to use.
    This corresponds linearly to the amount of time hashing will take.

:type time_cost: int
:param time_cost:
    An alias for **rounds**, for compatibility with underlying argon2 library.

:param int memory_cost:
    Defines the memory usage in kibibytes.
    This corresponds linearly to the amount of memory hashing will take.

:param int parallelism:
    Defines the parallelization factor.
    *NOTE: this will affect the resulting hash value.*

:param int digest_size:
    Length of the digest in bytes.

:param int max_threads:
    Maximum number of threads that will be used.
    -1 means unlimited; otherwise hashing will use ``min(parallelism, max_threads)`` threads.

    .. note::

        This option is currently only honored by the argon2pure backend.

:type relaxed: bool
:param relaxed:
    By default, providing an invalid value for one of the other
    keywords will result in a :exc:`ValueError`. If ``relaxed=True``,
    and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning`
    will be issued instead. Correctable errors include ``rounds``
    that are too small or too large, and ``salt`` strings that are too long.

.. versionchanged:: 1.7.2

    Added the "type" keyword, and support for type "D" and "ID" hashes.
    (Prior versions could verify type "D" hashes, but not generate them).

.. todo::

    * Support configurable threading limits.
)r   r  T)Nr   r  r   N)r   r    r!   r"   r#   backends_backend_mixin_targetr   r   r  _backend_mixin_mapr)   r   r*   r+   r   r     s+    E` -H ! #"r*   )>r#   
__future__r   r   logging	getLoggerr   r   r   typeswarningsr   r   r  passlibr   passlib.crypto.digestr   passlib.utilsr   r	   r
   passlib.utils.binaryr   r   passlib.utils.compatr   r   r   r   r   passlib.utils.handlersutilshandlersrQ   __all__r   rA   r   r   setr   r   r   hasattrr  r   r   r   r   r   r   SubclassBackendMixinParallelismMixin	HasRounds
HasRawSaltHasRawChecksumr   r.   r   r   r  r   r*   r+   <module>r:     s  " 7 ! 	    , ? ? 9 N N # #   
3	
3
D' ff%	I  ! <((4 	 \;//_ <)**$335#--<<   )*
R9B++R-@-@LL"--1B1B%%R9v!: !:TsN= sNxT<= T<t[Z [Q  Ls   E? ?F
	F
