+
    2jp                       R t ^ RIHt ^ RIt^ RIHt ^ RIHtHt ^ RIH	t	 ^ RI
HtHtHt ^ RIHtHtHt ^ RIt^ RIHtHt ^R	IHt ^R
IHt ^RIHtHt ^RIHt ^RIH t  ^RI!H"t" ^RI#H$t$ ^RI%H&t& ]'       d=   ^ RI'H(t(H)t)H*t* ^ RI+H,t, ^RI-H.t. ^RI/H0t0H1t1H2t2H3t3H4t4H5t5H6t6H7t7 ^RI8H9t9H:t:H;t;H<t< ^RI=H>t> ]P~                  ! ]@4      tA. RIOtB ! R R]4      tC ! R R]4      tD ! R R]4      tE ! R  R]F4      tG ! R! R]F4      tH ! R" R]F4      tIR# R$ ltJR% R& ltKR' R( ltLR)RJR*RJR+RR,R/R- R. lltMR/ R0 ltNR1 R2 ltOR3 R4 ltPR5 R6 ltQ]R7 R8 l4       tR]R9 R: l4       tRR; R< ltRR= R> ltSR? R@ ltTRA RB ltURC RD ltVRE RF ltWRG RH ltXR# )Kaj  Build a :class:`LockInput` from a finished resolve.

The provider's caches still hold the listings the resolver consumed
when this runs, so artefact hashes and per-file Requires-Python can
be read directly without a second fetch.  This module also owns the
``read_lockfile_anchor`` helper used by ``nab lock`` to keep
``P<n>D`` durations stable across re-locks.
)annotationsN)defaultdict)datetimetimezone)Path)TYPE_CHECKINGProtocoloverload)quoteurlsplit
urlunsplit)	SdistFile	WheelFile)parse_iso_datetime)tool_nab_section)PylockPylockValidationError)SpecifierSetcanonicalize_name)validate_specifier_versions)
path_state)BASE_MEMBER)IterableMappingSequence)IndexConfig)Version)
ArchivePinIndexPin	LockInputPinShapeSdistArtifact
TargetLockVcsPinWheelArtifact)ArchiveSource
DistPolicyLocalSource	VcsSource)ResolveTargetMissingHashErrorMissingSdistErrorMissingVcsCommitErrorc                  &    ] tR t^BtRtR R ltRtR# )_LockInputIndexz7Protocol for the InMemoryIndex slice the builder reads.c                    V ^8  d   QhRRRR/# )   packagestrreturn
str | None )formats   "g/home/user/billing-ledger-validation/.venv/lib/python3.14/site-packages/nab_python/_lockfile/builder.py__annotate___LockInputIndex.__annotate__E   s            c                    R# )z9Return the configured index name that served ``package``.Nr6   )selfr2   s   &&r8   get_listing_index!_LockInputIndex.get_listing_indexE       r;   r6   N)__name__
__module____qualname____firstlineno____doc__r>   __static_attributes__r6   r;   r8   r/   r/   B   s    A r;   r/   c                  0    ] tR t^JtRt]R R l4       tRtR# )_LockInputCoordinatorz:Protocol for the FetchCoordinator slice the builder reads.c                   V ^8  d   QhRR/# )r1   r4   r/   r6   )r7   s   "r8   r9   "_LockInputCoordinator.__annotate__N   s       r;   c                    R# )z:The underlying index used to look up serving-index labels.Nr6   r=   s   &r8   index_LockInputCoordinator.indexM        	r;   r6   N)rA   rB   rC   rD   rE   propertyrM   rF   r6   r;   r8   rH   rH   J   s    D r;   rH   c                      ] tR t^St$ RtR]R&    R]R&    ]R R l4       tR R	 ltR
 R lt	R R lt
R R ltR R ltRR R lltR R ltR R ltRtR# )LockInputProviderzStructural protocol for the provider slice the builder reads.

Mirrors the public surface :class:`~nab_python.provider.Provider`
exposes that :func:`build_target_lock` consumes; tests
may supply a stub without inheriting the full Provider class.
z2Mapping[tuple[str, Version], Mapping[str, object]]
deps_cachez@Mapping[tuple[str, Version], Mapping[str, Mapping[str, object]]]extra_deps_mapc                   V ^8  d   QhRR/# )r1   r4   rH   r6   )r7   s   "r8   r9   LockInputProvider.__annotate__b   s      2 r;   c                    R# )z<Coordinator used to look up the index that served a listing.Nr6   rL   s   &r8   coordinatorLockInputProvider.coordinatora   rO   r;   c                    V ^8  d   QhRRRR/# )r1   canonical_namer3   r4   zLocalSource | Noner6   )r7   s   "r8   r9   rV   f   s      s :L r;   c                   R# )zAReturn the configured LocalSource for ``canonical_name`` or None.Nr6   r=   r[   s   ""r8   local_source_for"LockInputProvider.local_source_forf   r@   r;   c                    V ^8  d   QhRRRR/# )r1   r[   r3   r4   zVcsSource | Noner6   )r7   s   "r8   r9   rV   j   s      S 8H r;   c                   R# )z?Return the configured VcsSource for ``canonical_name`` or None.Nr6   r]   s   ""r8   vcs_source_for LockInputProvider.vcs_source_forj   r@   r;   c                    V ^8  d   QhRRRR/# )r1   r[   r3   r4   zArchiveSource | Noner6   )r7   s   "r8   r9   rV   n   s       <P r;   c                   R# )zCReturn the configured ArchiveSource for ``canonical_name`` or None.Nr6   r]   s   ""r8   archive_source_for$LockInputProvider.archive_source_forn   r@   r;   c                    V ^8  d   QhRRRR/# )r1   r[   r3   r4   r5   r6   )r7   s   "r8   r9   rV   r   s      # Z r;   c                   R# )z@Return the resolved 40-char SHA captured during materialisation.Nr6   r]   s   ""r8   vcs_pin_forLockInputProvider.vcs_pin_forr   r@   r;   c               $    V ^8  d   QhRRRRRR/# )r1   r[   r3   versionr   r4   zlist[WheelFile | SdistFile]r6   )r7   s   "r8   r9   rV   v   s$      !,3	$r;   c                   R# )zDReturn the listing slice that matches ``(canonical_name, version)``.Nr6   r=   r[   rm   s   """r8   dist_files_for LockInputProvider.dist_files_forv        	r;   Nc               (    V ^8  d   QhRRRRRRRR/# )	r1   r[   r3   rm   r   
index_namer5   r4   r'   r6   )r7   s   "r8   r9   rV   |   s,      !,3AK	r;   c                   R# )zIReturn the effective :class:`DistPolicy` for ``canonical_name==version``.Nr6   )r=   r[   rm   rt   s   """"r8   effective_dist_policy'LockInputProvider.effective_dist_policy|   rr   r;   c               $    V ^8  d   QhRRRRRR/# )r1   r[   r3   rm   r   r4   r5   r6   )r7   s   "r8   r9   rV      s$      !,3	r;   c                   R# )zHReturn the ``requires-python`` override for ``canonical_name==version``.Nr6   ro   s   """r8   effective_requires_python+LockInputProvider.effective_requires_python   rr   r;   c               $    V ^8  d   QhRRRRRR/# )r1   r[   r3   rm   r   r4   intr6   )r7   s   "r8   r9   rV      s"      s W TW r;   c                   R# )z=Return how many wheels the tag filter dropped at ``version``.Nr6   ro   s   """r8   tag_excluded_wheel_count*LockInputProvider.tag_excluded_wheel_count   r@   r;   r6   N)rA   rB   rC   rD   rE   __annotations__rP   rX   r^   rb   rf   rj   rp   rv   rz   r   rF   r6   r;   r8   rR   rR   S   s[     CB@TTC  r;   rR   c                      ] tR t^tRtRtR# )r+   a  A distribution chosen by the resolver has no usable hash.

PEP 751 requires at least one hash per artefact.  When an index
serves a wheel or sdist without a ``hashes`` map (rare on PyPI,
common on file:// indexes), the lock writer cannot emit a
spec-compliant entry.  Surface the failure with the offending
package and filename so the user can either add a hash to their
local index or exclude the package.
r6   NrA   rB   rC   rD   rE   rF   r6   r;   r8   r+   r+          r;   c                      ] tR t^tRtRtR# )r,   a  A ``sdist-install`` package's pinned version has no sdist.

Under :attr:`~nab_python.provider.DistPolicy.SDIST_INSTALL` the
resolver may read a wheel's metadata but the lock must pin only the
sdist.  When the pinned version publishes wheels but no sdist, the
wheels are dropped and nothing is left to pin.  Surface the package
and version so the user can pick a version with an sdist or relax
the policy, rather than emitting an empty package the spec rejects.
r6   Nr   r6   r;   r8   r,   r,      r   r;   c                      ] tR t^tRtRtR# )r-   a  A VCS source reached the lock writer without a resolved commit SHA.

PEP 751 requires ``packages.vcs.commit-id`` to be an immutable
identifier.  nab records the post-clone SHA on the provider during
materialisation, before any version can be pinned, so a missing SHA
here means a VCS source was pinned without being cloned.  Surface it
loudly rather than emit a branch name or empty string as the commit
id, which would silently produce a non-reproducible lock.
r6   Nr   r6   r;   r8   r-   r-      r   r;   c                    V ^8  d   QhRRRR/# )r1   pathr   r4   datetime | Noner6   )r7   s   "r8   r9   r9      s      t  r;   c                   \        V 4      P                  '       g   R#  V P                  R4      ;_uu_ 4       p\        P                  ! V4      pRRR4       \        X4      p\        T\        4      '       d   TP                  R4      MRp\        T\        4      '       d5   TP                  '       d   T# TP                  \        P                   R7      # \        T\"        4      '       dA    \%        T4      pTP                  '       d   T# TP                  \        P                   R7      # R#   + '       g   i     L; i  \
        \        \        P                  3 d     R# i ; i  \&         d     R# i ; i)a8  Return the ``[tool.nab].created-at`` timestamp from ``path`` if any.

Used by ``nab lock`` to keep ``P<n>D`` durations stable across
re-locks: the anchor used for the previous resolve is read back
and reused unless the user passes ``--upgrade``.

Returns ``None`` when ``path`` does not exist, cannot be read, is
not valid TOML, is not a PEP 751-shaped pylock, or is missing the
``[tool.nab]`` block.  Naive timestamps (no offset) are coerced to UTC
for symmetry with the writer; this is informational provenance, so
a missing offset is recoverable rather than fatal.
Nrbz
created-at)tzinfo)r   should_readopentomliloadOSErrorUnicodeDecodeErrorTOMLDecodeErrorr   
isinstancedictgetr   r   replacer   utcr3   r   
ValueError)r   fdatanabrawdts   &     r8   read_lockfile_anchorr      s    d'''YYt__::a=D  4
 C#-c4#8#8#'',
dC#x  jjjsFckkk&FF#s	#C(B YYYrCBJJhllJ$CC _')>)>?   		s@   E  D-E  ,E' -D=	8E  =E    E$#E$'E65E6c                    V ^8  d   QhRRRR/# )r1   r   r   r4   zdict[str, Version] | Noner6   )r7   s   "r8   r9   r9      s       *C r;   c                   \        V 4      P                  '       g   R#  V P                  R4      ;_uu_ 4       p\        P                  ! V4      pRRR4       \
        P                  ! X4      pTP                   Uu/ uF2  qDP                  f   K  \        TP                  4      TP                  bK4  	  up#   + '       g   i     Lo; i  \        \        \        P                  \        3 d     R# i ; iu upi )a  Return the ``name -> version`` map from a prior pylock at ``path``.

Used by ``nab lock`` to diff a re-lock against the previous result.
Packages without a recorded version (direct-reference entries that
omit it) are skipped.

Returns ``None`` when ``path`` does not exist, cannot be read, is
not valid TOML, or is not a spec-compliant PEP 751 lockfile; the
caller falls back to a no-diff summary line.
Nr   )r   r   r   r   r   r   	from_dictr   r   r   r   packagesrm   r3   name)r   r   r   pylockpkgs   &    r8   read_lockfile_packagesr      s     d'''YYt__::a=D !!$' /5oo.=s"CHHs{{"o  _ ')>)>@UV s4   C	 B6C	 ;C5$C56C	C	 	%C21C2c                    V ^8  d   QhRRRR/# )r1   urlr3   r4   r6   )r7   s   "r8   r9   r9      s     3 3 3 3r;   c                    \        V 4      pVP                  P                  R4      w  r#pV'       g   V # VP                  P	                  R4      '       d!   VP                  R^4      ^ ,          pV RV 2p\        VP                  VR7      4      # )a  Return ``url`` with credential userinfo removed.

Lockfiles are committed to version control, so an index or VCS URL
carrying an embedded ``user:password`` must not be written verbatim.
An SSH login such as ``git@`` is the protocol login, not a secret,
and is required to clone, so it is kept (only an embedded password is
dropped); host case and port are preserved.  A no-op for URLs without
userinfo.
@ssh:)netloc)r   r   
rpartitionschemeendswithsplitr   _replace)r   partsuserinfosephostlogins   &     r8   _strip_userinfor      s~     SME,,11#6H4
||U##sA&q)$ ennDn122r;   indexesresolved_keys
base_rootsselector_rootsc               8    V ^8  d   QhRRRRRRRRR	R
RRRRRR/# )r1   providerrR   targetr*   pinsMapping[str, Version]r   Sequence[IndexConfig]r   Iterable[str]r   zIterable[str] | Noner   z.Mapping[tuple[str, str], Iterable[str]] | Noner4   r#   r6   )r7   s   "r8   r9   r9      sc     c ccc  c
 #c !c %c Cc cr;   c                  ^RI HpHp Vf   V'       d   Rp	\        V	4      hRp/ p
VP	                  4        EF  w  r\        V4      pV P                  W4      pV'       d   \        P                  RVVV4       V P                  V4      pVeY   V! V\        V4      \        \        VP                  4      P                  4       4      VP                  VP                  R7      W&   K  V P!                  V4      pVe#   \#        VVVV P%                  V4      R7      W&   K  V P'                  V4      pVe   \)        WV4      W&   EK  \+        WW4      W&   EK  	  \-        WV4      w  ppT! TT
TT\/        T TTT;'       g    / R7      R7      # )	a:  Build one target's :class:`~nab_python.lockfile.TargetLock`.

``provider`` is the :class:`Provider` that drove the resolve for
``target``; its caches still hold the listings the resolver
consumed.  ``pins`` is the canonical-name -> :class:`Version`
mapping returned by the resolver after extras keys have been
stripped.

``resolved_keys`` is the full set of resolver result keys, including
``name[extra]`` proxies; it is read to find which extras activated
so their edges join the forward dependency graph.

``base_roots`` and ``selector_roots`` are the resolver keys each
install context requires directly: the project's own dependencies,
and those of each selected extra and each selected group, keyed by
its ``(kind, name)`` member.  :func:`_membership_gates` walks the
resolve from each to find which contexts reach each package.  An
empty ``base_roots`` is a project with no dependencies of its own, so
it does not stand in for ``None``: omitting it while passing selector
roots raises.

Every wheel the target can install, plus the sdist, is recorded for
each pinned version.
)LocalPinr#   zNselector_roots need base_roots: without them every package looks selector-onlyz4%s==%s: %d wheel(s) omitted from lock by target tags)r   rm   r   editablesubdirectory)resolved_sha)r   r   )r   r   dependenciesbase_dependenciespackage_gatesr6   )lockfiler   r#   r   itemsr   r   loggerdebugr^   r3   r   r   resolver   r   rb   _vcs_pin_from_sourcerj   rf   _archive_pin_from_source_index_pin_from_listing_forward_dependency_graph_membership_gates)r   r   r   r   r   r   r   r   r#   msg	lock_pinsraw_namerm   	canonicalprunedlocal_source
vcs_sourcearchive_sourcer   r   s   &&&$$$$             r8   build_target_lockr      s   D 0B  S/!
%'I!ZZ\%h/	229FLLF	  00;##+Gl//088:;%..)66$I  ,,Y7
!#7%11)<	$I  !44Y?%#;N$I  6 
	G *N '@'#L# !+'!)//R	
 r;   c          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )r1   r   rR   r   r   r   r   r   z'Mapping[tuple[str, str], Iterable[str]]r4   z&dict[str, tuple[tuple[str, str], ...]]r6   )r7   s   "r8   r9   r9   d  sA     "M "M"M
"M 	"M
 <"M ,"Mr;   c          
        VP                  4        UUu/ uF  w  rE\        V4      VbK  	  ppp\        \        4      p\	        WV4       F  pWt,          P                  \        4       K   	  VP                  4        F/  w  r\	        WV	4       F  pWt,          P                  V4       K  	  K1  	  VP                  4        UU
u/ uF  w  rJV\        \        V
4      4      bK  	  up
p# u uppi u up
pi )a  Name every install context that reaches each package.

A selected extra or group is folded into the resolve that produces
the lock, so its requirements pin packages a default install must not
receive.  PEP 751 decides per package from ``packages.marker``, so a
package has to name every context that reaches it; the writer turns
each ``(kind, name)`` member into ``'name' in extras`` /
``'name' in dependency_groups``.  The project's own dependencies are
one such context, recorded as
:data:`~nab_python.lockfile.BASE_MEMBER` until the writer knows what to
call it, so a package both they and a group reach installs for either.

Reachability is over this target's resolved graph, so an extras proxy
(an extra requiring ``pkg[fancy]`` while the project requires plain
``pkg``) gates what ``fancy`` adds without gating ``pkg``.

Empty roots on both sides gate nothing, which is a lock with no
selection and no name for the project's own dependencies.
)	r   r   r   set_reachable_namesaddr   tuplesorted)r   r   r   r   r   rm   pinnedreachmemberrootsmemberss   &&$$       r8   r   r   d  s    4 EIJJLQL=4%w.LFQ4?4DE :>$ ?'--/$Xu=DKOOF# > 0 ?DkkmLm]TD%w((mLL R Ms   C% C+c               (    V ^8  d   QhRRRRRRRR/# )	r1   r   rR   r   r   r   r   r4   zset[str]r6   )r7   s   "r8   r9   r9     s0     " ""!" " 	"r;   c                   ^RI Hp \        4       p\        4       p\        V4      pV'       d   VP	                  4       pWu9   d   K   VP                  V4       V! V4      w  r\        V4      p
VP                  V
4      pVf   K]  VP                  V
4       W3pVP                  V P                  P                  V/ 4      4       V	f   K  VP                  V P                  P                  V/ 4      P                  V	/ 4      4       K  V# )zReturn the pinned names reachable from ``roots`` at their pinned versions.

The walk is over resolver keys, so a ``name[extra]`` root pulls in
that extra's dependencies on top of the package's own.
split_extra)r   r   r   listpopr   r   r   extendrS   rT   )r   r   r   r   reachedseenstackkeyr   extrar   rm   	cache_keys   &&&          r8   r   r     s     'GUDKE
iik;%c*%h/	**Y'?I(	X((,,Y;<LL0044YCGGrRSNr;   c               (    V ^8  d   QhRRRRRRRR/# )	r1   r   rR   r   r   r   r   r4   z=tuple[dict[str, tuple[str, ...]], dict[str, tuple[str, ...]]]r6   )r7   s   "r8   r9   r9     s1     4 44
4 !4 C	4r;   c           	       a ^RI Ho \        \        4      pV F4  pS! V4      w  rVVf   K  V\	        V4      ,          P                  V4       K6  	  V Uu0 uF  p\	        V4      kK  	  pp/ p	/ p
VP                  4        EF3  w  r\	        V4      pW3pV P                  P                  V/ 4       Uu0 uF  p\	        S! V4      ^ ,          4      kK  	  pp\        V4      pV P                  P                  V/ 4      pVP                  VR4       F.  pVP                  V3R lVP                  V/ 4       4       4       K0  	  VV,          pVV,          pVP                  V4       VP                  V4       V'       d   \        \        V4      4      W&   V'       g   EK  \        \        V4      4      W&   EK6  	  W3# u upi u upi )aJ  Build the forward dependency graph among the locked packages.

Returns ``(full, base)``.  ``full`` maps each pinned package to the
canonical names of its direct dependencies that are themselves
pinned; an activated extra (a ``name[extra]`` key in
``resolved_keys``) folds that extra's dependencies in.  ``base`` is
the subset from each package's own metadata (``deps_cache``), before
any extra is folded in, so it holds only the edges that fire
regardless of which extra was activated.  Names not in ``pins`` are
dropped from both so every edge points at a real ``[[packages]]``
entry.
r   c              3  T   <"   T F  p\        S! V4      ^ ,          4      x  K  	  R# 5i)    Nr   ).0depr   s   & r8   	<genexpr>,_forward_dependency_graph.<locals>.<genexpr>  s*      3C "+c"21"5663s   %(r6   )r   r   r   r   r   r   r   rS   r   rT   updatediscardr   r   )r   r   r   activated_extrasr   baser   r   r   graph
base_graphr   rm   r   r   r   	base_depsall_deps	extra_mapr   s   &&&                @r8   r   r     s   " '3>s3C!#&.t4599%@ 
 377$$%$F7(*E-/J!ZZ\%h/	(	  **..y"=
= k#.q12= 	 
 y>++//	2>	%)))R8EOO $==3  9
 	V	F 	)$#$VH%56E9$)&*;$<J!/ *0 7 8
s   F:1!F?c          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )r1   r   rR   r   r3   rm   r   r   r   r4   r   r6   )r7   s   "r8   r9   r9     sA     O OOO O #	O
 Or;   c           	     *  a ^RI Hp ^RIHpHpHo ^RIHp \        V P                  W4      4      pV P                  P                  P                  V4      p	V P                  WV	4      VP                  J dy   V U
u. uF  p
\        V
\         4      '       d   K  V
NK  	  pp
\"        ;QJ d    R V 4       F  '       g   K   RM	  RM! R V 4       4      '       g   V RV RV 2p\%        V4      h\&        ;QJ d    . V3R	 lV 4       F  NK  	  5M! V3R	 lV 4       4      p\)        R
 V 4       R4      pVe   \+        W4      MRpV P-                  W4      pVe   TM
\/        V4      pV P                  P                  P                  V4      pV Uu/ uF  pVP0                  VP2                  bK  	  ppVe   VP5                  V4      MRpVf   V'       d   V RV: R2p\7        V4      hTpV! V\9        V4      \;        V4      VVVR7      # u up
i u upi )a  Construct an :class:`IndexPin` for an index-served package.

The recorded ``index`` is the URL of the configured index that
served the package's listing during the resolve, looked up from
the coordinator's :class:`InMemoryIndex` (which records the
serving index by name) and resolved against ``indexes`` for the
URL.  A pinned package's serving index is always recorded and is
one of ``indexes``, so the URL is always known.

Under :attr:`~nab_python.provider.DistPolicy.SDIST_INSTALL` the
package's wheels stayed in ``versions_cache`` as a possible
metadata source for the resolver; only the sdist is emitted
into the lock so installers download and build that archive.

A ``requires-python`` metadata override takes precedence over the
Simple-API value so the pin records the specifier the resolver
actually admitted against; a conforming :pep:`751` installer would
otherwise reject a widened pin whose lock still carried the narrow
artefact value.
)DEFAULT_INDEX_URL)r   r"   r%   )r'   c              3  B   "   T F  p\        V\        4      x  K  	  R # 5ir   r   r   r   r   s   & r8   r   *_index_pin_from_listing.<locals>.<genexpr>
  s     ;U:a++Us   TFz==zx has no sdist, but its dist-policy is 'sdist-install'; pick a version that publishes an sdist or change dist-policy for c              3  l   <"   T F)  p\        V\        4      '       g   K  \        VS4      x  K+  	  R # 5ir   )r   r   _build_artifact)r   r   r%   s   & r8   r   r    s*      38aJq)<T)=))5s   44c              3  V   "   T F  p\        V\        4      '       g   K  Vx  K!  	  R # 5ir   r  r  s   & r8   r   r    s     D%Q:a+Cqq%s   )
)Nz: recorded serving index z% is not one of the configured indexes)r   rm   rM   sdistwheelsrequires_python)fetchr  r   r   r"   r%   r   r'   r   rp   rX   rM   r>   rv   SDIST_INSTALLr   r   anyr,   r   nextr  rz   _common_requires_pythonr   r   r   AssertionErrorr3   r   )r   r   rm   r   r  r   r"   r'   filesservingr   r   r  
sdist_filer  override_rpr  serving_nameixby_name	index_urlr%   s   &&&&                 @r8   r   r     s	   4 *AA%((<=E""((::9EG&&y7C##	$ "BEqAy)AEBs;U;sss;U;;;+Ry )**36 
 $C((U 38UU 38 F D%DdKJ6@6L
2RV 
 44YHK".4KE4R  ''--??	JL)012rwwG1-9-EL)4I +6|6F G4 4  !%%%	Gi(' I C. 2s   ;HH Hc               $    V ^8  d   QhRRRRRR/# )r1   sourceWheelFile | SdistFileclsztype[WheelArtifact]r4   r%   r6   )r7   s   "r8   r9   r9   8  &      !	 r;   c                    R # r   r6   r'  r)  s   &&r8   r  r  7       r;   c               $    V ^8  d   QhRRRRRR/# )r1   r'  r(  r)  ztype[SdistArtifact]r4   r"   r6   )r7   s   "r8   r9   r9   =  r*  r;   c                    R # r   r6   r,  s   &&r8   r  r  <  r-  r;   c               $    V ^8  d   QhRRRRRR/# )r1   r'  r(  r)  z#type[WheelArtifact | SdistArtifact]r4   zWheelArtifact | SdistArtifactr6   )r7   s   "r8   r9   r9   A  s&      !	, #r;   c           	         \        V P                  4      pV! V P                  \        V P                  4      VV P
                  \        V P                  4      V P                  R 7      # ))filenamer   hashessizeupload_time
local_path)	_filter_acceptable_hashesr3  r2  r   r   r4  _parse_upload_timer5  r6  )r'  r)  r3  s   && r8   r  r  A  sS     'v}}5FFJJ'[[&v'9'9:$$ r;   c                    V ^8  d   QhRRRR/# )r1   r   r5   r4   r   r6   )r7   s   "r8   r9   r9   P  s     + +J +? +r;   c                    V f   R#  \        V 4      pTP                  f   R# TP                  \        P
                  4      #   \         d     R# i ; i)aq  Parse an index ``upload-time`` string to a UTC ``datetime``.

Accepts the RFC 3339 form the Simple/JSON API serves (``Z`` or an
explicit offset) and normalizes it to UTC (PEP 751 requires UTC for
the emitted field). Returns ``None`` when the field is absent,
unparseable, or has no timezone; the timestamp is informational, so
a bad value is dropped rather than fatal.
N)r   r   r   
astimezoner   r   )r   parseds   & r8   r8  r8  P  sS     {#C( }}X\\**	  s   A AAc                    V ^8  d   QhRRRR/# )r1   r3  ztuple[tuple[str, str], ...]r4   r6   )r7   s   "r8   r9   r9   d  s      ' r;   c                   a ^RI Ho \        ;QJ d     . V3R l\        V 4       4       F  NK  	  5# ! V3R l\        V 4       4       4      # )a  Return the subset of ``hashes`` whose algorithm is consumable.

Pip's hash-checking mode and PEP 751 both accept any of sha256,
sha384, or sha512; nab forwards every recorded entry so consumers
can pick.  Unacceptable algorithms (e.g. md5) are dropped, so the
result may be empty.
)ACCEPTED_HASH_ALGORITHMSc              3  @   <"   T F  w  rVS9   g   K  W3x  K  	  R # 5ir   r6   )r   algodigestr?  s   &  r8   r   ,_filter_acceptable_hashes.<locals>.<genexpr>p  s'      *LD++ 	*s   )r   r?  r   r   )r3  r?  s   &@r8   r7  r7  d  sB     45 "6N5 5 "6N  r;   c                    V ^8  d   QhRRRR/# )r1   
lock_inputr    r4   Noner6   )r7   s   "r8   r9   r9   w  s     0 0	 0d 0r;   c           
        ^RI HpHp V P                  P	                  4        F  pVP
                  P	                  4        F  p\        WB4      '       g   K  . VP                  OVP                  e   VP                  3MRO5pV FJ  pVP                  '       d   K  VP                   RVP                  : R\        V4      : R2p\        V4      h	  K  	  K  	  R# )zRaise :class:`MissingHashError` if a pinned artefact has no hash.

PEP 751 and pip's hash-checking mode each need at least one of
sha256/sha384/sha512 per artefact.  The plain ``name==version``
writer records no hash and does not call this.
)r?  r   Nz: artefact z% has no acceptable hash (need one of )r6   )r   r?  r   targetsvaluesr   r   r  r  r3  r   r2  r   r+   )rE  r?  r   lockpin	artefactsartefactr   s   &       r8   require_artifact_hashesrO  w  s     >""))+99##%Cc,,W#**W		8MSUWI%88*K0A0A/D E8 89<A? 
 +3// &	 & ,r;   c                    V ^8  d   QhRRRR/# )r1   r  zIterable[WheelFile | SdistFile]r4   r5   r6   )r7   s   "r8   r9   r9     s      #B z r;   c                0   \        4       pV  FN  pVP                  f    R#  \        \        VP                  4      4       TP                  TP                  4       KP  	  \        V4      ^8X  d   \        \        V4      4      # R#   \         d      R# i ; i)aG  Return the package-level Requires-Python value, or ``None``.

An artefact with no Requires-Python is unconstrained, so a single
such artefact leaves the whole package unconstrained. Otherwise the
value survives only when every artefact agrees.

A value nab cannot use counts as unconstrained too, matching
``excluded_by_python``, which admits a dist on any Python when the
specifier will not parse or its versions will not convert. So the
lock writer always records a usable specifier or ``None``, and the
pin is never over-constrained by an artefact whose floor nab could
not read.
N)	r   r  r   r   r   r   lenr  iter)r  r   r   s   &  r8   r  r    s     UD$	'Q5F5F(GH 	""#  4yA~DJ  		s   BBBc          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )r1   r   r3   rm   r   r'  r)   r   r5   r4   r$   r6   )r7   s   "r8   r9   r9     s:     ? ??? ?
 ? ?r;   c                   ^ RI Hp ^RIHp Vf   V  R2p\	        V4      hVP                  VP                  4      pVP                  '       d   VP                  V8w  d   VP                  MRp\        VP                  4      p	VP                   RV	 RV 2p
VP                  '       d"   V
R\        VP                  RR	7       2,          p
T! T \        V4      T
T	TVP                  ;'       g    RVVP                  R
7      # )a  Build a :class:`VcsPin` from a :class:`VcsSource`.

``resolved_sha`` is the post-clone SHA recorded on the provider by
:func:`~nab_python._provider.sources.materialize_vcs_source`.  A VCS
source cannot be pinned without first being materialised, so a
``None`` here is an internal invariant violation: raise
:class:`MissingVcsCommitError` rather than emit a branch name or
empty string as ``commit_id``.

``requested_revision`` is the URL's ``@<ref>``, kept only when it
is a named ref that differs from ``commit_id`` (i.e. the user did
not pin the bare SHA).  ``subdirectory`` carries the
``#subdirectory=`` fragment so an installer can locate the project
inside the repo.

``bare_repo_url`` comes from ``parsed.repo_url``, which
:meth:`VcsRequest.parse` has already separated from the ref and the
fragment.  ``repo_url`` re-pins that bare URL to ``commit_id`` (the
``git+`` prefix, ``@<sha>``, and any ``#subdirectory=`` fragment) so
the requirements.txt line installs the locked commit, not the ref
the user supplied.
)
VcsRequest)r$   Nz: VCS source pinned without a resolved commit SHA; materialize_vcs_source records the post-clone SHA before any version can be pinned, so this is an internal invariant violation+r   z#subdirectory=/)safe)r   rm   repo_urlbare_repo_url	commit_idr   requested_revisionvcs_type)nab_index.vcsrV  r   r$   r-   parser   refr   rZ  r   r   r
   r3   )r   rm   r'  r   rV  r$   r   r<  r]  r[  rZ  s   &&&$       r8   r   r     s    : )!k   	 $C((fjj)F jjjVZZ<%?

T  $FOO4M---,@HnU6+>+>S%I$JKKG#((00D-	 	r;   c               (    V ^8  d   QhRRRRRRRR/# )	r1   r   r3   rm   r   r'  r&   r4   r   r6   )r7   s   "r8   r9   r9     s0        	r;   c                    ^ RI Hp ^RIHp VP	                  VP
                  4      pT! T \        V4      \        VP
                  4      VP                  VP                  ;'       g    RR7      # )ab  Build an :class:`ArchivePin` from an :class:`ArchiveSource`.

The URL, hashes, and subdirectory come from the source declaration,
which config parse validated (a hash is required), so the pin records
the exact archive the resolve used.  The URL is stripped of any
credential userinfo, like every other pin, so a committed lockfile
never carries a token.
)ArchiveRequest)r   N)r   rm   r   r3  r   )
nab_index.archiverd  r   r   r`  r   r3   r   r3  r   )r   rm   r'  rd  r   requests   &&&   r8   r   r     sY     1%""6::.GGGKK(~~))11T r;   )r+   r,   r-   r   r   r   rO  r6   )YrE   
__future__r   loggingcollectionsr   r   r   pathlibr   typingr   r   r	   urllib.parser
   r   r   r   nab_index.clientr   r   _iso8601r   _tomlr   _vendor.packaging.pylockr   r   _vendor.packaging.specifiersr   _vendor.packaging.utilsr   metadatar   pathsr   groupsr   collections.abcr   r   r   nab_index.multi_indexr   _vendor.packaging.versionr   r   r   r   r    r!   r"   r#   r$   r%   r   r&   r'   r(   r)   r   r*   	getLoggerrA   r   __all__r/   rH   rR   r   r+   r,   r-   r   r   r   r   r   r   r   r   r  r8  r7  rO  r  r   r   r6   r;   r8   <module>r{     s|   #  # '  4 4 4 4  1 ) $ D 7 7 2  ;;13	 	 	 ML& 
		8	$h H 7 7t	z 		
 		J 	B03(c
 &(c $&c (,c FJcL"MJ"J4nOd 
 
 
 
+(&008?Dr;   