+
    2j                      a  0 t $ R t^ RIHt ^ RIt^ RIHtHt ^ RIH	t	H
t
 ^ RIHt ^ RIHt ^ RIHt ^ RIHtHt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 H!t! ^RI"H#t#H$t$H%t%H&t&H't'H(t(H)t) ^RI*H+t+ ^RI,H-t- ^RI.H/t/ ^RI0H1t1H2t2 ^RI3H4t4 ^RI5H6t6 ^RI7H8t8 ^RI9H:t: ]'       d%   ^ RI;H<t<H=t=H>t> ^ RI;H?t@ ^RIAHBtBHCtCHDtDHEtEHFtF ^RIGHHtH . ROtIRtJR]KR&   RtLR]KR &   R!tMR]KR"&   ]N! 4       tOR ]KR#&   ]	! R$R$R%7       ! R& R'4      4       tP]	! R$R$R%7       ! R( R)4      4       tQ]	! R$R$R%7       ! R* R+4      4       tRR, R- ltSR. R/ ltT ! R0 R]U4      tV ! R1 R]U4      tWR2R/R3 R4 lltXR5R/R6 R7 lltYR5R/R8 R9 lltZR: R; lt[R< R= lt\R> R? lt]R@ RA lt^RRBR/RC RD lllt_RE RF lt`RG RH ltaRI RJ ltbRRK RL lltcRM RN ltdRRO RP llteRQ RR ltfRS RT ltgRU RV lthRW RX ltiRY RZ ltjR[ R\ ltkR] R^ ltlR_ R` ltmRa Rb ltnRc Rd ltoRe Rf ltpRg Rh ltqRi Rj ltrRk Rl ltsRm Rn lttRo Rp ltuRq Rr ltvRs Rt ltwRu Rv ltx]N! 4       3Rw Rx lltyRy Rz ltzR{ R| lt{R} R~ lt|R R lt}R R lt~R R ltR R ltR R ltR R ltR# )al  PEP 751 ``pylock.toml`` emission.

Owns ``write_lock`` and ``build_pylock`` plus the
:class:`LockInput` -> :class:`Pylock` shape conversion.  The targets a
resolve ran against collapse into one or more ``Package`` entries per
name, with a marker attached when they disagree; the emit-time
disjointness validation lives in
:mod:`nab_python._lockfile.disjointness`.
)annotationsN)Counterdefaultdict)	dataclassreplace)reduce)product)Path)TYPE_CHECKINGAny	TypeAlias)atomic_write_text)
KIND_GROUPMARKER_VARIABLE_FOR_KINDMarker)DecisionStoreIntractableMarkerSet	MarkerSetUnserializableMarkerSet)PackagePackageArchivePackageDirectoryPackageSdist
PackageVcsPackageWheelPylock)SpecifierSetcanonicalize_name)Version)conflict_exclusion_groupsconflict_member_groups)require_artifact_hashes)validate_marker_coverage)validate_marker_disjointnessBASE_MEMBER)IterableMappingSequence)Set)	LockInputPinShapeSdistArtifact
TargetLockWheelArtifact)ResolveTargetDivergentBaseDependencyErrorUnsoundSimplificationErrortuple[tuple[str, str], ...]r   _EnvSignaturezfrozenset[tuple[str, str]]_Membersztuple[_EnvSignature, _Members]_ForkKey_NO_MEMBERST)frozenslotsc                  X    ] tR t^Qt$ RtR]R&   R]R&   R]R&   R]R	&   R
]R&   R]R&   RtR# )	_ForkAxesaR  The declared conflict sets a lock's forks vary along.

``exclusion_groups`` are the ``(kind, name)`` member sets an install
context may activate at most one member of, restricted to the members
the resolve forked over (:func:`_forked_exclusion_groups`).  ``forks``
indexes every target by its environment and its selection, which is how
:func:`_project_fork` walks one set's members with the other sets
held fixed.  ``markers`` is each fork's unprojected selection marker,
which does not vary by package, and ``gates`` each fork's
:attr:`~nab_python.lockfile.TargetLock.package_gates` as sets.
(tuple[AbstractSet[tuple[str, str]], ...]exclusion_groupszMapping[_ForkKey, str]forksMapping[str, TargetLock]targetsMapping[str, _EnvSignature]env_signatureszMapping[str, str]markersz"Mapping[tuple[str, str], _Members]gates N__name__
__module____qualname____firstlineno____doc____annotations____static_attributes__rF       f/home/user/billing-ledger-validation/.venv/lib/python3.14/site-packages/nab_python/_lockfile/pylock.pyr<   r<   Q   s-    
 ?>!!%%//--rO   r<   c                  0    ] tR t^gt$ RtR]R&   R]R&   RtR# )_GatedMarkerzlThe environments one gate selects a package in.

``marker`` is ``None`` when the gate holds on all of them.
Marker | Nonemarkerr4   gaterF   NrG   rF   rO   rP   rR   rR   g   s    
 
%%rO   rR   c                  0    ] tR t^rt$ RtR]R&   R]R&   RtR# )_ProjectionzOne package's marker shape at one fork.

``dropped`` are the selection members whose clauses fall away, and
``gate`` is the membership gate that stands in for the fork's own
once they do (:func:`_merged_fork_gate`).
r6   droppedrU   rF   NrG   rF   rO   rP   rW   rW   r   s     
NrO   rW   c               $    V ^8  d   QhRRRRRR/# )   rA   r@   rC   rB   returnzdict[_ForkKey, str]rF   )formats   "rP   __annotate__r]      s&      %/ rO   c                    V P                  4        UUu/ uF-  w  r#W,          \        VP                  P                  4      3VbK/  	  upp# u uppi )zIndex every target by its environment and its selection.

A conflict-forked environment holds one target per point of the
cartesian product across the engaged sets, so this is the lookup that
answers "which fork agrees with this one everywhere but here".
)items	frozensettarget	selection)rA   rC   labellocks   &&  rP   _fork_indexre      sM     #==?*KE 
		$++*?*? @A5H*  s   3Ac               $    V ^8  d   QhRRRRRR/# )rZ   r>   &Sequence[AbstractSet[tuple[str, str]]]rA   r@   r[   r=   rF   )r\   s   "rP   r]   r]      s&     ? ?<?%? .?rO   c                   a \        R VP                  4        4       4      o\        ;QJ d    . V3R lV  4       F  NK  	  5# ! V3R lV  4       4      # )a<  Restrict each declared conflict set to the members a fork selects.

A set forks only over the members the run selected, so a declared
member the selection omits has no fork for :func:`_project_fork` to
swap in and no place in the lock's ``extras`` or ``dependency-groups``
arrays for an install context to activate.
c              3  \   "   T F"  qP                   P                   F  q"x  K  	  K$  	  R # 5iN)ra   rb   ).0rd   members   &  rP   	<genexpr>+_forked_exclusion_groups.<locals>.<genexpr>   s%      +4++:O:O:O+s   *,c              3  4   <"   T F  qS,          x  K  	  R # 5irj   rF   )rk   groupforkeds   & rP   rm   rn      s     >-=E-=s   )r`   valuestuple)r>   rA   rq   s   &&@rP   _forked_exclusion_groupsrt      sI      ">>+ F 5>-=>5>5>-=>>>rO   c                      ] tR t^tRtRtR# )r3   zA simplified per-package marker disagrees with the original over the universe.

Checked on the serialised and reparsed bytes at emission, so a mismatch is a
bug in the algebra and emission refuses rather than ship a marker that would
install differently.
rF   NrH   rI   rJ   rK   rL   rN   rF   rO   rP   r3   r3      s    rO   c                      ] tR t^tRtRtR# )r2   aR  An environment's conflict forks disagree on a base dependency's pin.

A base dependency present in every fork of an environment drops its
membership clause so it installs even when no conflicting member is
selected, which requires the forks to agree on one (version, source).
When they diverge, every candidate entry keeps a membership clause,
so nothing would fire in the no-member install context and the
dependency would silently not install.  Surface the divergence with
the offending package and per-fork pins so the producer can
reconcile the forks rather than commit an incomplete lock.
rF   Nrv   rF   rO   rP   r2   r2      s    
rO   output_pathc               $    V ^8  d   QhRRRRRR/# )rZ   
lock_inputr,   rx   zstr | os.PathLike[str] | Noner[   strrF   )r\   s   "rP   r]   r]      s(       / 		rO   c                   Ve   \        V4      P                  MRp\        WR7      pVe   \        \        V4      V4       V# )a  Serialise ``lock_input`` to PEP 751 TOML text.

Returns the TOML text.  When ``output_path`` is provided, also
writes it there; the caller chooses the path (PEP 751 does not
mandate one).  The write is staged and renamed into place, so a
failed write leaves any existing file intact.

Directory, wheel and sdist paths are written relative to
``output_path``'s parent so the lockfile stays portable between
machines (PEP 751 records those paths relative to the lock file).
With no ``output_path`` the current directory is the base.
Nlock_dir)r	   parentrender_lockr   )rz   rx   r~   texts   &$  rP   
write_lockr      s?    " ,7+BtK ''Hz5D${+T2KrO   r~   c               $    V ^8  d   QhRRRRRR/# )rZ   rz   r,   r~   Path | Noner[   r{   rF   )r\   s   "rP   r]   r]      s!     1 1I 1K 13 1rO   c                   \        V 4       \        WR7      pVP                  4        \        P                  ! \        VP                  4       4      4      # )aX  Serialise ``lock_input`` to PEP 751 TOML text without writing a file.

``lock_dir`` is the directory the lock will live in; directory, wheel
and sdist paths are emitted relative to it so the lock stays portable.
Defaults to the current directory.  Used by ``write_lock`` and by
``nab lock --locked`` to render the would-be lock for comparison.
r}   )r#   build_pylockvalidatetomli_wdumpsdictto_dict)rz   r~   pylocks   &$ rP   r   r      s;     J'*8F
OO==fnn./00rO   c               $    V ^8  d   QhRRRRRR/# )rZ   rz   r,   r~   r   r[   r   rF   )r\   s   "rP   r]   r]      s&     D DY D[ DF DrO   c                  ^RI Hp \        V 4      p Ve   TM\        P                  ! 4       P                  4       p\        V P                  4      p\        V 4      p\        4       p\        WWEV4      pVP                  \        R7       \        VV P                  V P                  V P                   V\#        V P                  4      R7       \%        V P&                  P)                  4        Uu. uF  qP*                  NK  	  upV P,                  VR7       V P.                  e   RV P.                  P1                  4       /MRp	\3        \5        V4      \7        V P,                  4      ;'       g    RV P8                  '       d   \;        V P8                  4      MRV P                  '       dA   \6        ;QJ d    . R V P                   4       F  NK  	  5M! R V P                   4       4      MR\=        V P>                  V P@                  V PB                  4      \=        V PD                  V PD                  '       g   V P@                  MR4      V PF                  VV	R7	      # u upi )	a  Build a :class:`Pylock` from the input shape.

The resolver-side data structures have already been simplified
when this function runs.  The remaining work is shape conversion:
``Pin`` -> ``Package``, plus marker attachment from the per-target
map.

``lock_dir`` is the directory the lockfile will be written to;
local-directory, wheel and sdist paths are emitted relative to it
so the lockfile is portable.  It defaults to the current working
directory when the caller has no path in mind (e.g. stdout).
)LOCK_VERSIONNkey)environmentsextrasgroupsexclusive_groupsdeclared_groups)r   storenabc              3  8   "   T F  p\        V4      x  K  	  R # 5irj   r   )rk   es   & rP   rm   build_pylock.<locals>.<genexpr>  s     B0A1#A&&0A   )	lock_versionr   requires_pythonr   dependency_groupsdefault_groups
created_bypackagestool)$lockfiler   _name_base_groupr	   cwdresolver!   	conflicts_emission_universer   _build_packagessort_package_sort_keyr%   marker_envsr   active_groupsr"   r$   rA   rr   ra   r   
provenanceto_blockr   r    rs   r   r   _group_arrayr   
base_groupbuild_groupr   r   )
rz   r~   r   baser>   universer   package_recordsrd   r   s
   &$        rP   r   r      s     (!*-J ,H$((*EEGD01E1EF!*-HOE%*eO ./ ++  '').z/C/CD !+!3!3!:!:!<=!<!<=,,   , 

%%..01 	
 \*:223;;t ))) 334     EB
0A0ABEEB
0A0ABB&((!!""

 $%%)3)B)B)BJ!!
 (( 1  	>s   +Ic                    V ^8  d   QhRRRR/# )rZ   rz   r,   r[   rF   )r\   s   "rP   r]   r]   $  s     0 0 0y 0rO   c                  a V P                   p\        V3oV P                  P                  4        UUUUu/ uF  w  r#T\	        TVP
                  P                  4        UUu/ uFI  w  rEVf   \        V9  g   K  T\        ;QJ d    . V3R lV 4       F  NK  	  5M! V3R lV 4       4      bKK  	  uppR7      bK  	  ppppp\	        WR7      # u uppi u uppppi )a1  Return ``lock_input`` with the base member named, or cut from every gate.

The builder records :data:`~nab_python.lockfile.BASE_MEMBER` on every
package the project's own dependencies reach.  With ``base-group``
unset there is no name to give it, so those packages lose their gate
and stay unconditional.
c              3  B   <"   T F  pV\         8X  d   SMTx  K  	  R # 5irj   r&   )rk   gate_memberrl   s   & rP   rm   #_name_base_group.<locals>.<genexpr>2  s$      '+ *[8FkI'+s   )package_gates)rA   )r   r   rA   r_   r   r   r'   rs   )rz   namerc   rd   gatedrU   rA   rl   s   &      @rP   r   r   $  s       D$F &--335 6KE 	w $(#5#5#;#;#=
 $>KE#{$'>uu '+uu '+   $>

 
	
 6   ://s#   +C
 C8C+C/C
C
c               $    V ^8  d   QhRRRRRR/# )rZ   r   Sequence[str]
configuredz
str | Noner[   ztuple[str, ...] | NonerF   )r\   s   "rP   r]   r]   ?  s$         (2  rO   c                    \         P                  R V  4       4      pV F   pVf   K	  RV\        \        V4      4      &   K"  	  \	        V4      ;'       g    R# )a'  Render one of the lock's group arrays, or ``None`` when it is empty.

Every name is canonicalized here and deduplicated in order.  Which
arrays a ``configured`` name belongs in is the caller's decision:
``build-group`` joins ``dependency-groups`` alone, and ``base-group``
joins it too, since an installer that offers only those names would
otherwise never reach it.  ``base-group`` joins ``default-groups``
only when the project declares none of its own, because a declared
``default-groups`` replaces the default selection rather than
extending it.
c              3  J   "   T F  p\        \        V4      4      x  K  	  R # 5irj   )r{   r   )rk   rp   s   & rP   rm   _group_array.<locals>.<genexpr>M  s     LVE#/677Vs   !#N)r   fromkeysr{   r   rs   )r   r   namesr   s   &*  rP   r   r   ?  sQ     MMLVLLE26E#'-./  <4rO   c               $    V ^8  d   QhRRRRRR/# )rZ   ra   zstr | os.PathLike[str]r~   r	   r[   r{   rF   )r\   s   "rP   r]   r]   T  s"        3  t    rO   c                     \         P                  P                  W4      p\        V4      P                  4       #   \         d    \         P                  ! T 4      p L<i ; i)a  Return ``target`` as a POSIX path relative to ``lock_dir``.

PEP 751 records ``packages.directory.path`` and the wheel/sdist
``path`` fields relative to the lock file so the lockfile stays
portable between machines.  :func:`os.path.relpath` is used
rather than :meth:`pathlib.Path.relative_to` so a ``target``
outside ``lock_dir`` still resolves, to a ``../``-prefixed path.
The result uses POSIX separators, which the spec recommends for
portable relative paths.

A Windows cross-drive ValueError falls back to the absolute path.
)ospathrelpath
ValueErrorfspathr	   as_posix)ra   r~   rels   && rP   _relativize_pathr   T  sM     ggoof/ 9   ii s   : !AAc               (    V ^8  d   QhRRRRRRRR/# )	rZ   r   r{   labelszIterable[str]rA   r@   r[   list[dict[str, str]] | NonerF   )r\   s   "rP   r]   r]   h  s,     3 3
3$3/G3 3rO   c                    \        4       pV F4  pVP                  W$,          P                  P                  V R4      4       K6  	  V'       g   R# \	        V4       Uu. uF  pRV/NK	  	  up# u upi )as  Render a package's forward edges as PEP 751 dependency tables.

One entry covers the targets in ``labels``, which may disagree on
what ``name`` depends on (a dep gated by a marker one target answers
differently), so the edges are the union over those targets.  Each
target's edges already point only at packages it locked, so every
edge names a package the lock carries.
Nr   rF   )setupdatedependenciesgetsorted)r   r   rA   depsrc   deps   &&&   rP   _dependency_entriesr   h  s\     UDGN//33D"=> %+D\2\cVSM\222s   A,r   c          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )rZ   pinr-   rT   rS   r~   r	   r   r   r[   r   rF   )r\   s   "rP   r]   r]   {  sA     K K	KK 	K
 .K KrO   c                 a ^RI HpHpHpHp \        W4      '       Ed    \        \        V P                  4      \        V P                  4      TTV P                  '       d   \        V P                  4      MRV P                  V P                  '       d   \        V P                  SR7      MR\         ;QJ d0    . V3R l\#        V P$                  \&        R7       4       F  NK  	  5M)! V3R l\#        V P$                  \&        R7       4       4      ;'       g    RR7      # \        W4      '       dX   \        \        V P                  4      RVV\)        \+        V P,                  S4      V P.                  V P0                  R7      R7      # \        W4      '       dd   \        \        V P                  4      RVV\3        V P4                  V P6                  V P8                  V P0                  V P:                  R	7      R
7      # \        W4      '       dj   \        \        V P                  4      \        V P                  4      VV\=        V P>                  \A        V PB                  4      V P0                  R7      R7      # RV : 2p\E        V4      h)rZ   
ArchivePinIndexPinLocalPinVcsPinNr}   c              3  >   <"   T F  p\        VSR 7      x  K  	  R# 5i)r}   N)_wheel_to_package)rk   wr~   s   & rP   rm   "_pin_to_package.<locals>.<genexpr>  s"      @A "!h77@s   r   )r   versionrT   r   r   indexsdistwheels)r   editablesubdirectory)r   r   rT   r   	directory)typeurl	commit_idr   requested_revision)r   r   rT   r   vcs)r   hashesr   )r   r   rT   r   archiveunknown pin shape: )#r   r   r   r   r   
isinstancer   r   r   r    r   r   r   r   r   _sdist_to_packagers   r   r   _wheel_sort_keyr   r   r   r   r   r   vcs_typebare_repo_urlr   r   r   r   r   r   	TypeError)	r   rT   r~   r   r   r   r   r   msgs	   &&d$     rP   _pin_to_packager   {  s    BA#  "388,CKK(%585H5H5HS001d))CF999!#))h?RV5 

@55 

@    !
 	
$ #   "388,%&%chh9 --

 
	
 # "388,%\\%%-- --#&#9#9
 	
 #"" "388,CKK(%"GGCJJ' --

 
	
  w
'C
C.rO   c               $    V ^8  d   QhRRRRRR/# )rZ   wheelr0   r~   r	   r[   r   rF   )r\   s   "rP   r]   r]     s!      ]  , rO   c          
        V P                   em   \        V P                  \        V P                   P	                  4       V4      V P
                  \        \        V P                  4      4      V P                  R7      # \        V P                  V P                  V P
                  \        \        V P                  4      4      V P                  R7      # )a  Convert a wheel artefact to its PEP 751 ``packages.wheels`` entry.

A wheel from a local find-links directory carries its on-disk
``local_path``; it is written as a ``path`` relative to the lock
file so the lockfile stays portable.  A remote wheel records its
``url`` verbatim.
r   r   sizer   upload_timer   r   r  r   r  )
local_pathr   filenamer   r   r  r   r   r   r  r   )r  r~   s   &$rP   r   r     s     #!%"2"2":":"<hGu||,-))
 	
 ^^IIZZF5<<()%% rO   c               $    V ^8  d   QhRRRRRR/# )rZ   r   r.   r~   r	   r[   r   rF   )r\   s   "rP   r]   r]     s!      ]  , rO   c          
        V P                   em   \        V P                  \        V P                   P	                  4       V4      V P
                  \        \        V P                  4      4      V P                  R7      # \        V P                  V P                  V P
                  \        \        V P                  4      4      V P                  R7      # )zConvert an sdist artefact to its PEP 751 ``packages.sdist`` entry.

See :func:`_wheel_to_package` for the ``local_path`` handling.
r  r  )r  r   r  r   r   r  r   r   r   r  r   )r   r~   s   &$rP   r   r     s    
 #!%"2"2":":"<hGu||,-))
 	
 ^^IIZZF5<<()%% rO   c                    V ^8  d   QhRRRR/# )rZ   rz   r,   r[   r   rF   )r\   s   "rP   r]   r]     s     < <9 < <rO   c                   V P                   '       g   \        P                  ! 4       # V P                    Uu. uF  p\        P                  ! V4      NK  	  pp \        ;QJ d    R V 4       F  '       d   K   RM	  RM! R V 4       4      pV'       d   \        P                  ! 4       # \        \        P                  V\        P                  ! 4       4      # u upi   \
         d    Rp L_i ; i)a  Return the environment universe simplification must agree over.

The union of the declared ``environments`` rows, or the full set when none
are declared.  PEP 751 step 4 has a conforming installer read a per-package
marker only in an environment some row admits, so within-universe
equivalence is the sound contract.

A union admitting no environment makes every set vacuously equivalent to
every other, so the full set stands in for it: a simplification sound in
every environment is sound inside an empty one too.  A union is empty
exactly when every row is, so rows are tested one at a time rather than as a
whole-matrix product, and a row too wide to decide counts as inhabited.
c              3  @   "   T F  qP                  4       x  K  	  R # 5irj   )is_empty)rk   rows   & rP   rm   %_emission_universe.<locals>.<genexpr>
  s     9DS,,..Ds   FT)	r   r   fullfrom_markerallr   r   unionempty)rz   mrowsuninhabiteds   &   rP   r   r     s     """~~.8.E.EF.EI!!!$.EDFc9D9ccc9D99 ~~)//4):;; G   s   CC 7C C,+C,c          
     ,    V ^8  d   QhRRRRRRRRR	R/# )
rZ   rawrS   withinr   r   r{   r   DecisionStore | Noner[   rF   )r\   s   "rP   r]   r]     s:     ' '	'' '  	'
 'rO   c                   V f   R#  \         P                  ! V 4      P                  WR7      pVP                  4       pVf   RM
\	        V4      pVf   \         P
                  ! 4       M\         P                  ! V4      pVf   RM
\        V4      p\        WW4      p	T	'       g"   T RT: R\        T 4      : R2p
\        T
4      hT#   \        \        3 d    T u # i ; i)a  Return ``raw`` in its shortest form equivalent over ``within``.

``None`` passes through, and a set full over the universe serialises back to
``None``.  The simplified set is serialised, reparsed, and checked equivalent
to ``raw`` over ``within``; a mismatch raises
:class:`UnsoundSimplificationError`.

Simplification is only a compaction, so every way the algebra can decline to
answer ships ``raw`` instead: :class:`IntractableMarkerSet` when a decision
overruns the cell budget or the marker nests past the stack, and
:class:`UnserializableMarkerSet` when the simplified set has no marker
spelling, which is what a marker selecting nothing inside ``within``
collapses to.
N)r  r   z	no markerz: emitted marker z is not equivalent to z over the declared environments)r   r  simplifyto_marker_stringr   r  r{   _sound_within_universer   r   r3   )r  r  r   r   
simplifiedr   rebuiltemittedshownsoundr   s   &&&&       rP   _finalize_markerr&    s    ( {
**3/888T
**,,$F4L 'INNY5J5J75S 	  'CL&sVC f%eY /C|:< 	 )--N !"9: 
s   BC CCc               0    V ^8  d   QhRRRRRRRRR	R
RR/# )rZ   r  rS   r  r   r   r{   memodict[str, Marker | None]r   r   r[   rF   )r\   s   "rP   r]   r]   <  sD      	  #	
  rO   c                \    V f   R# \        V 4      pWS9  d   \        WW$4      W5&   W5,          # )z:func:`_finalize_marker` memoised for the span of one lock.

``within`` is fixed for a whole build, so two packages carrying the same raw
marker have the same shortest form, and a universal lock repeats one
platform or python gate across many packages.
N)r{   r&  )r  r  r   r(  r   r   s   &&&&& rP   _finalize_cachedr+  <  s0     {
c(C
$S$>	9rO   c          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
rZ   r  r   r#  r   r  r   r  r[   boolrF   )r\   s   "rP   r]   r]   Q  sA     V V	VV V  	V
 
VrO   c                P    \         P                  ! V 4      P                  WVR7      # )a  Whether ``emitted`` and ``raw`` agree on every environment in ``within``.

``emitted`` is what the lock ships: the reparsed marker bytes, or
:meth:`MarkerSet.full` when no marker field is emitted.  Decided per universe
row, under the same budget as the operator it checks.
)r   )r   r  equivalent_within)r  r#  r  r   s   &&&&rP   r   r   Q  s%       %77u7UUrO   c               0    V ^8  d   QhRRRRRRRRR	R
RR/# )rZ   rz   r,   r~   r	   r>   rg   r   r   r   r   r[   zlist[Package]rF   )r\   s   "rP   r]   r]   `  sL     i iii =i 	i
 i irO   c                   . pV P                   p\        V4      p\        V4      p\        VP	                  4       4      p	\        WhWP                  4      p
VP                  4        UUu/ uF  w  rV\        V4      bK  	  ppp/ p\        W&4      p\        T\        Wh4      TTVP                  4        UUu/ uF  w  ppV\        VP                  V4      bK  	  uppVP                  4        UUUUu/ uF8  w  ppVP                  P                  4        F  w  ppVV3\        V4      bK  	  K:  	  uppppR7      p\!        VWV
4      pVP                  4        Fw  w  pp\#        VW{,          VVV	V
4       V FU  w  pp\%        VVV	V
VV4      p\'        VW;W4      pVP)                  \+        \-        V4      VV\/        VVV4      R7      4       KW  	  Ky  	  V# u uppi u uppi u uppppi )aw  Collapse the per-target pins into Package entries with markers.

For each canonical package name:
* Group targets by (version, source-shape).
* Emit a Package per group; the marker is the OR of the matching
  targets' markers.  When the group's targets cover every target
  the resolve ran against, the package is unconditional and the
  marker is omitted, which is every package of a lock with one
  target.
* Within a group, the artefact sets (wheels and sdist) are
  unioned across the contributing targets so target-specific
  wheels (e.g. cp310-manylinux vs cp311-macos) survive.

Each emitted marker is finalised to its shortest form equivalent over
the declared environments (:func:`_finalize_marker`).

A package carries the gate of every install context that reaches it,
which with ``[tool.nab].base-group`` set includes the project's own
dependencies.  See :func:`_build_marker`.

A conflict fork injects a membership clause into every target's
marker, including the forks' base dependencies.  A base dependency
present in every fork of an environment must install regardless of
which member is selected, so for that environment it contributes the
membership-free env-only marker rather than the OR of the per-fork
membership markers.  A package is recognised as a base dependency
through ``lock_input.env_base_names``: a dep required by every member
but not by the base is absent from that set, so it keeps the
membership clause and does not install when no member is selected.
See :class:`LockInput.env_base_names` for the missing-signature
contract.  The base-name set is first closed under the emitted
dependency edges (:func:`_close_base_names`) so a transitive dep the
forks pull in through a base dep counts as base too.  Forks of one
environment that disagree on a base dependency's pin raise
:class:`DivergentBaseDependencyError` instead of emitting a lock
whose no-member context misses it.
)r>   r?   rA   rC   rD   rE   )r~   r   )rA   _group_by_name_env_signatures_countrr   _close_base_namesenv_base_namesr_   _group_pins_by_pinrt   r<   re   _selection_markerra   r   r`   _fork_projections_check_base_fork_agreement_build_marker_finalize_partsappendr   _merge_pins_in_groupr   )rz   r~   r>   r   r   outrA   by_namerC   env_fork_counts
base_namescanonical_name
per_target
pin_groups	shortenedforked_groupsrc   rd   r   rU   axesprojectionsr   pinsr   partsrT   s   &&&&&                      rP   r   r   `  s   X C  GW%G$W-N^2245O"2K2KJ
 +2--/*9&N 	*:66*9   +-I,-=GM&'2%  '}}
.t $T[[-@@.
  '}}
.t"00668
d 5M9T?*8 .
D  $D*zRK","2"2"4"#	
 #LD&!E %UHiWFJJ(.%!4^VW!U	 # #5: Jk

s   'G3#G.>Gc                    V ^8  d   QhRRRR/# )rZ   rA   r@   r[   zdict[str, dict[str, PinShape]]rF   )r\   s   "rP   r]   r]     s      %#rO   c                    \        \        4      pV P                  4        F<  w  r#VP                  P                  4        F  w  rEWQ\	        V4      ,          V&   K  	  K>  	  V# )zDPivot ``{label: TargetLock}`` to ``{canonical name: {label: pin}}``.)r   r   r_   rJ  r   )rA   r?  rc   rd   raw_namer   s   &     rP   r2  r2    sQ     2=T1BC}}!YY__.MH69!(+,U3 / ' JrO   c                    V ^8  d   QhRRRR/# )rZ   rD  zdict[str, PinShape]r[   &list[tuple[list[PinShape], list[str]]]rF   )r\   s   "rP   r]   r]     s     ! !#!+!rO   c                   / p\        V 4       F^  pW,          p\        V4      pWA9  d   . . 3W&   W,          ^ ,          P                  V4       W,          ^,          P                  V4       K`  	  \        VP	                  4       4      # )zBucket targets by pin discriminator, keeping every pin.

Walked in sorted label order so the output is independent of dict
insertion order.
)r   _pin_discriminatorr=  listrr   )rD  by_keyrc   r   r   s   &    rP   r7  r7    sv     =?F
# %r(FKAc"Ae$ $   rO   c                    V ^8  d   QhRRRR/# )rZ   r   r-   r[   rs   rF   )r\   s   "rP   r]   r]     s      H  rO   c                L   ^RI HpHpHpHp \        W4      '       d   RV P                  V P                  3# \        W4      '       d:   RV P                  V P                  V P                  V P                  ;'       g    R3# \        W4      '       d:   RV P                  V P                  V P                  V P                  ;'       g    R3# \        W4      '       d:   RV P                  V P                  V P                  V P                  ;'       g    R3# RV : 2p\!        V4      h)zFReturn a hashable key that identifies the source + version of ``pin``.r   r   local r   r   r   )r   r   r   r   r   r   r   r   r   r   r   r   r   repo_urlr   r   r   )r   r   r   r   r   r   s   &     rP   rR  rR    s    AA#  cii00#   KKHHLL""
 	
 # LLMMLL""
 	
 #""3;;S=M=M=S=SQSTTw
'C
C.rO   c                    V ^8  d   QhRRRR/# )rZ   rJ  zlist[PinShape]r[   r-   rF   )r\   s   "rP   r]   r]   
  s     * *~ *( *rO   c                   ^RI Hp V ^ ,          p\        W!4      '       g   V# / pVP                  p\	        4       pRpV  F  p\        Wq4      '       g   Q hVP
                   F  pVP                  VP                  V4       K!  	  Vf   VP                  e   VP                  pVP                  f   RpKu  VP                  VP                  4       K  	  V'       g%   \        V4      ^8X  d   \        \        V4      4      MRp	V! VP                  VP                  VP                  V\!        \#        VP%                  4       \&        R7      4      V	R7      # )a  Combine pins sharing a discriminator into one with unioned artefacts.

For :class:`IndexPin`, accumulates every distinct wheel filename
across the contributing targets and keeps the first non-``None``
sdist.  ``requires_python`` survives only when every target carried
the same value and none was unconstrained, matching
:func:`_common_requires_python`'s rule.
Non-IndexPin shapes are already fully discriminated, so the first
pin is returned unchanged.
)r   FNTr   )r   r   r   r   r   r   )r   r   r   r   r   r   
setdefaultr  r   addlennextiterr   r   r   rs   r   rr   r   )
rJ  r   headseen_wheelsr   requires_python_setany_unconstrainedr   r  r   s
   &         rP   r>  r>  
  s"    $7Dd%%,.KJJE$'E#((((ZZE""5>>59  =SYY2IIE& $##C$7$78  !S)<%=%B 	T%&' 
 YYjjVK..0oFG' rO   c          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )rZ   rA   r@   rC   )Mapping[str, tuple[tuple[str, str], ...]]rA  )Mapping[tuple[tuple[str, str], ...], int]r6  4Mapping[tuple[tuple[str, str], ...], frozenset[str]]r[   z1dict[tuple[tuple[str, str], ...], frozenset[str]]rF   )r\   s   "rP   r]   r]   7  s;     & &%&=& ?& I	&
 7&rO   c                   V'       g   \        V4      # \        WV4      p/ pVP                  4        F  w  rgVP                  V/ 4      p\	        V4      p	\        V4      p
V
'       dT   VP                  V
P                  4       R4       F-  pW9  g   K  V	P                  V4       V
P                  V4       K/  	  K[  \        V	4      WV&   K  	  V# )a  Close each env's base-name set under the emitted dependency edges.

``env_base_names`` records the names an independent base pass
resolved, at that pass's versions, which emission discards in favour
of the conflict-fork versions.  When the forks pin a base dependency
lower than the base pass did, its emitted transitive closure differs:
a package the forks pull in through the base dep is missing from
``env_base_names`` and would keep its membership clause, so it drops
out of the no-member install context even though the base dep that
requires it installs there.  Following the base (unconditional) edges
present in every fork of the environment restores the closure, keeping
the no-member context closed under the lock's own dependency graph.

Preserves the missing-signature contract: only signatures present in
``env_base_names`` appear in the result, so an env with no base pass
stays absent and its base status stays unknowable.
rF   )
r   _shared_fork_edgesr_   r   r   rS  popr]  r=  r`   )rA   rC   rA  r6  sharedclosed	signaturer   	adjacency	reachablestackr   s   &&&&        rP   r5  r5  7  s    . N##IF@BF)//1	JJy"-	I	T
 }}UYY["5'MM#&LL% 6 &i0 2 MrO   c               (    V ^8  d   QhRRRRRRRR/# )	rZ   rA   r@   rC   rf  rA  rg  r[   z7dict[tuple[tuple[str, str], ...], dict[str, list[str]]]rF   )r\   s   "rP   r]   r]   `  s0      %= ? =	rO   c                    \        \        4      pV P                  4        Fi  w  rEW1V,          ,          pVP                  P                  4        F7  w  rx\        P                  V4       F  p	WgV	3;;,          ^,          uu&   K  	  K9  	  Kk  	  / p
VP                  4        F[  w  rW+,          p\        \        4      pVP                  4        F'  w  w  rypW8X  g   K  W,          P                  V	4       K)  	  WV&   K]  	  V
# )a  Per-env adjacency of the base edges present in every fork of the env.

Walks ``base_dependencies`` (a package's unconditional edges), never
the extra-folded ``dependencies``, so a dep a conflict member pulls in
through an extra is not an edge here even when every fork activates
that extra.  A base edge only some forks carry (a base dep pinned to a
version whose deps differ) is dropped too.  Following these edges thus
never promotes a member-only dep to base.
)r   r   r_   base_dependenciesr   r   rS  r=  )rA   rC   rA  edge_countsrc   rd   countersourcer   r   rl  rn  countro  seens   &&&            rP   rj  rj  `  s     	G  }}U34 2288:LF}}T*$)$ + ; ' GIF)//1	*1<T1B	#*==?MV4}!((- $3 &y 2 MrO   c               4    V ^8  d   QhRRRRRRRRR	R
RRRR/# )rZ   r   r{   rD  zMapping[str, PinShape]r   rP  rC   rf  rA  rg  r6  rh  r[   NonerF   )r\   s   "rP   r]   r]     sO     %0 %0
%0&%0 3%0 >	%0
 ?%0 I%0 
%0rO   c                  aa \        \        4      p\        S4       F!  pWcV,          ,          P                  V4       K#  	  VP	                  4        F  w  r\        V	4      WH,          8  d   K  WP                  V\        4       4      9  d   K=  \        V	4      o\        V3R lV 4       4      p
WV,          8  d   Kl  RP                  V3R lV	 4       4      pV  RV R2p\        V4      h	  R# )a~  Reject a base dep whose forks within one env pin it differently.

The env-only collapse in :func:`_build_marker` needs a single
(version, source) group spanning every fork of the environment.
Divergent pins split the forks across groups, so every entry would
keep its membership clause and none would fire when no member is
selected: the base dependency would silently not install.
c              3  R   <"   T F  w  r\        V3R  lV 4       4      x  K  	  R# 5i)c              3  8   <"   T F  qS9   g   K  ^x  K  	  R# 5i)   NrF   )rk   rc   in_envs   & rP   rm   7_check_base_fork_agreement.<locals>.<genexpr>.<genexpr>  s     ?|e|s   
N)sum)rk   _group_labelsr  s   &  rP   rm   -_check_base_fork_agreement.<locals>.<genexpr>  s(      
#) ?|???#)   $'z, c              3  R   <"   T F  q R SV,          P                    2x  K  	  R# 5i)z -> N)r   )rk   rc   rD  s   & rP   rm   r    s(     XQWG4
5(9(A(A'BCQWr  zN: the conflict forks of one environment pin this base dependency differently (zL); no lockfile entry would install it when no conflicting member is selectedN)r   rS  r   r=  r_   r^  r   r`   r   maxjoinr2   )r   rD  r   rC   rA  r6  by_envrc   rn  r   widestr?   r   r  s   &f&&&&       @rP   r:  r:    s      CNdBSF
#e$%,,U3 $#\\^	v;33)))Y[AAV 
#)
 
 Y//		XQWXXf ((-w /AA 	
 +3//% ,rO   c               4    V ^8  d   QhRRRRRRRRR	R
RRRR/# )rZ   r   r{   r   r   rA  rg  r6  rh  rH  r<   rI  %Mapping[tuple[str, str], _Projection]r[   ztuple[_GatedMarker, ...]rF   )r\   s   "rP   r]   r]     sX     o o
oo ?o I	o
 o 7o orO   c                  a VP                   p\        \        4      pV F+  pWtP                  V,          ,          P	                  V4       K-  	  V Uu/ uF%  qWh,          P
                  P                  V R4      bK'  	  upo\        \        4      p	. p
\        V4      \        V4      8  pVP                  4        EFD  w  r\        WW#4      p\        V Uu0 uF  p\        Wh,          SV,          4      kK  	  up4      ^8H  p\        V4      W,,          8  ;'       d    TpWm^ ,          ,          P                  pV'       dK   V'       dC   \        V3R lV 4       4      pV	V,          P	                  \        VP                  4      4       K  V'       dI   \        V3R lV 4       4      pV'       d,   V	V,          P	                  \        VP                  4      4       V
P!                  R \#        WEW4       4       4       RpEKG  	  \$        ;QJ d"    . R V	P                  4        4       F  NK  	  5M! R V	P                  4        4       4      pV
'       d   V\'        \)        V
4      R4      3,          pV'       g   V# \+        V	4      R08X  d   \'        RR4      3# \        V	4      ^8X  d    \'        R\-        \/        V	4      4      4      3# V# u upi u upi )a	  Return the marker selecting ``labels``, split by gate.

For each environment the package appears in, the contribution is
the membership-free env-only marker when the package is present in
every fork of that env AND ``env_base_names`` lists it as a base
dep there; otherwise the contribution is the OR of the per-fork
membership-carrying markers.  The result is the OR of those
contributions, or ``None`` when the package covers every target
AND every env collapsed to its env-only marker, which is every
package of a single-target lock.

A dep required by every member of an ``at-most-one`` set but not
by the base is absent from ``env_base_names``, so it keeps the
membership OR and does not install when no member is selected.
An environment with no base-name set (no conflict fork ran) leaves
the gate open.

A membership contribution carries the fork's positive selection AND
the negation of every co-member of the conflict sets it selects from
(``"cpu" in extras and "gpu" not in extras``), so the forks are
mutually exclusive in the marker itself: a PEP 751 consumer that never
reads ``[tool.nab].conflicts`` still installs at most one fork.  See
:func:`_selection_marker`.

The selection is projected per package first: a conflict set the
package does not vary over contributes no clause, so with two sets
engaged a dep reached through one of them names only that one and
still installs for a selection that leaves the other set empty.  See
:func:`_fork_projections`.  The projection makes several forks render
the same contribution, which is emitted once.

A package carries the gate of every install context that reaches it
(see :attr:`~nab_python.lockfile.TargetLock.package_gates`), joined
by ``and`` onto each contribution.  A fork whose gate names
its own selection needs no gate: its marker already asserts that
member.  An env collapses only when its forks agree on the rest of
the gate, and the collapsed entry carries their union, so a package
one fork reaches through its own member and another through a
non-conflicting extra installs for either.  When the package covers
every target, every env collapsed, and every env gates it the same
way, the env clauses are dropped and the gate stands alone: a
selection is a property of the install context, not of the platform,
so ``"cli" in extras`` is the whole marker.
c              3  6   <"   T F  pSV,          x  K  	  R # 5irj   rF   rk   rc   rE   s   & rP   rm    _build_marker.<locals>.<genexpr>       !GJ5%,,J   c              3  6   <"   T F  pSV,          x  K  	  R # 5irj   rF   r  s   & rP   rm   r    r  r  c              3  8   "   T F  p\        V4      x  K  	  R # 5irj   r   )rk   r   s   & rP   rm   r    s      
P 4LLPr   Fc              3  P   "   T F  w  r\        \        V4      V4      x  K  	  R # 5irj   )rR   _or_markers)rk   rU   r   s   &  rP   rm   r  	  s)      "1D 	[.55"1s   $&NrF   )rA   r   rS  rC   r=  r   r   r^  r_   _is_base_shared_gatera   _merge_gatesr   environment_marker_string_common_gateextend_fork_contributionsrs   rR   r  r   r_  r`  )r   r   rA  r6  rH  rI  rA   r  rc   by_gatelooseunconditionalrn  
env_labelsis_baseagreed_gate	collapsesra  mergedrl  rK  rE   s   &&&&&&               @rP   r;  r;    sX   h llGBMdBSF""5)*11%8  MSSF5GN0044T2>>FSE GRRVFWGEK3w</M!'	4OLTgneEl;TU 	
 
O'AAMMg	!}%,,!!GJ!GGFFO""6$*H*H#IJ
 !!GJ!GGF&&vd.L.L'MN 
+DtP
 	
 7 "0: E ")--/EE ")--/ E ,{512688
 7|tT2&((
7|qT4W#6799Lm T Us   +K"K
c          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )rZ   rH  r<   rI  r  r   r{   r  r   r[   z	list[str]rF   )r\   s   "rP   r]   r]     s:      
6  	
 rO   c           
        / pV F  pV P                   V,          P                  pWV3,          pVP                  '       g   V P                  V,          M\	        W`P
                  VP                  4      p\        VP                  4      VP                  ,
          p	RV\        V\        WP                  4      4      &   K  	  \        V4      # )a7  Render one environment's per-fork markers, projected and deduped.

Each fork drops the clauses of the conflict sets the package does not
vary over (:func:`_fork_projections`), which leaves the forks of a
dropped set rendering the same text; the duplicates are folded into
one contribution, in first-seen order.
N)rA   ra   rX   rD   r8  r>   r`   rb   
_with_gate
_fork_gaterU   rS  )
rH  rI  r   r  ry  rc   ra   
projectionr   kepts
   &&&&      rP   r  r    s     De$++ u-
 %%% LL"6+@+@*BTBTU 	
 ))*Z-?-??DHZj?@A  :rO   c          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )rZ   rH  r<   rE  z8Mapping[str, Sequence[tuple[list[PinShape], list[str]]]]rA  Mapping[_EnvSignature, int]r6  &Mapping[_EnvSignature, frozenset[str]]r[   z"dict[tuple[str, str], _Projection]rF   )r\   s   "rP   r]   r]   7  s:     3 3
3H3 13 ;	3
 (3rO   c                >  a a / p/ pVP                  4        FG  w  opV F;  w  rx\        V4      p	\        V V3R lV 4       4      p
V F  pWSV3&   WSV3&   K  	  K=  	  KI  	  V Uu/ uF:  q\        S P                  V^,          ,          P                  P                  4      bK<  	  pp/ p\        V4      pV'       d   V FJ  w  op\        S SVVSV3,          VSV3,          \        SS P                  V,          W#4      R7      VSV3&   KL  	  VP                  4        UUUu/ uF)  w  w  pppVV3V\        S WVVV3,          4      ,          bK+  	  ppppVP                  4        UUu0 uF  w  ppVW,          8w  g   K  VkK  	  pppTpK  V# u upi u upppi u uppi )a  Return, per (package, fork), the selection clauses its marker can drop.

Every fork starts free to drop its whole selection and
:func:`_project_fork` keeps only what the fork space justifies.  The
dependency edges then narrow it: an entry that fires where one of its
own dependencies does not is a lock that cannot be installed, so a
package keeps every member its dependencies at that fork keep.  The
allowances only shrink, so the loop settles.
c              3     <"   T F;  pSP                   V,          P                  P                  SR4       F  pVx  K	  	  K=  	  R # 5i)NrF   )rA   r   r   )rk   peerr   rH  r   s   &  rP   rm   $_fork_projections.<locals>.<genexpr>K  sA      !"D<<-::>>tRHC H "s   AA)r  )
r_   r`   rA   ra   rb   r   _project_forkr  rC   _dependency_drops)rH  rE  rA  r6  same_pinedgesr   r  r   rp   declaredrc   r   limitsrI  staler   limitnarroweds   f&&&            `  rP   r9  r9  7  s    79H35E"((*fIAf%E  !"! H
  (-u%%-dEk"     + PXXx9T\\#a&188BBCCxFX68KME
 KD%'4tU{#u% $--e4o	(Ke$ ! )/
 )7$uu 5M5k%e:LMN N(6 	 

 (0~~'7P'7e5FK;O'7P- Y

 Qs   &A F!/F'F>Fc          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )rZ   rH  r<   rI  r  rc   r{   r  AbstractSet[str]r[   r6   rF   )r\   s   "rP   r]   r]   m  s:      
6  	
 rO   c                    \        V P                  V,          P                  P                  4      pV F1  pVP	                  WR34      pYFe   VP
                  M\        ,          pK3  	  V# )a  Return the members every dependency an entry declares drops at one fork.

:func:`_dependency_entries` unions the edges over the entry's forks,
so an edge only one fork has still rides on the whole entry; a fork
that does not carry that dependency at all can drop nothing.
)r`   rA   ra   rb   r   rX   r8   )rH  rI  rc   r  rl  r   r  s   &&&&   rP   r  r  m  sY     t||E*11;;<F __c\2
(>*$$KO  MrO   c               4    V ^8  d   QhRRRRRRRRRR	R
RRR/# )rZ   rH  r<   r   r{   rc   r  r6   r  r  r  r-  r[   rW   rF   )r\   s   "rP   r]   r]     sN     =& =&
=&
=& =& 	=&
 =& =& =&rO   c          	        V P                   P                  W3\        4      p\        V P                  V,          P
                  P                  4      pV P                  V,          p\        4       p	Tp
. pV P                   F  pW,          V,          p\        V4      ^8w  d   K$  . VOVNp\        P                  ! V!  pW,
          p\        R V 4       !   Uu. uF  pVV\        V4      ,          3NK  	  ppV Uu. uF)  pVV P                  9   g   K  V P                  V,          NK+  	  pp\        V4      \        V4      8w  g   VP                  V4      '       g   K  \        WVV4      pVf   K  TpW,          p	Tp
K  	  V'       g+   V
'       g#   Wy,
          '       g   \        \        4       V4      # \        W4      # u upi u upi )aU  Return the clauses one fork's entry for ``name`` can drop.

A conflict set is irrelevant to a package when swapping the fork's
member of that set for any other member, every other set held fixed,
leaves the package at the same pin reached the same way.
Conjoining such a set's clauses narrows the entry to the forks that
vary something the package does not depend on, so a selection naming
a member of one set alone matches no entry and the package silently
does not install.

Sets are folded in one at a time and each candidate is checked over
the whole sub-cube of the sets folded in so far rather than one axis
at a time.  Two axes that are each flat through this fork can still
meet at a fork with a different pin; dropping both would leave two
entries of one package overlapping, and the forks have to stay
mutually exclusive in the marker itself.
c              3  8   "   T F  p\        V4      x  K  	  R # 5irj   )r   )rk   memberss   & rP   rm    _project_fork.<locals>.<genexpr>  s     !Kg&//r   )rE   r   r8   r`   rA   ra   rb   rC   r>   r^  r  r   r?   
issuperset_merged_fork_gaterW   )rH  r   rc   r  r  r  own_gaterb   rn  rX   rU   varyingrp   rl   	candidateerasedheldswapkeysr   peersr  s   &&&&&$                rP   r  r    s   4 zz~~tm[9H$,,u-44>>?I##E*I!GD24G&&"U*v;!%g%u%	""I.!  !K!KL
L y./L 	 
 -1FDSC4::4ECDFu:T"(*=*=e*D*D"4uf=>+ '4 4	(;(;9;11w%%)
 Gs   F=:GGc          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )rZ   rH  r<   r   r{   r  r   r  r6   r[   z_Members | NonerF   )r\   s   "rP   r]   r]     s:      

  	
 rO   c                (  a V Uu/ uF$  qDV P                   P                  W3\        4      bK&  	  pp\        VP	                  4        Uu0 uF  p\        V4      kK  	  up4      ^8w  d   R# WR^ ,          ,          S,
          p\        V3R lVP	                  4        4       4      pVP                  4        FJ  w  rFWgV\        V P                  V,          P                  P                  4      ,          ,          8w  g   KI   R# 	  Wx,          # u upi u upi )a  Return the gate the sub-cube's forks share, or ``None`` when they do not.

Dropping a set replaces the fork's own gate with one that holds at
every point of the sub-cube: the part naming nothing in the dropped
sets, plus every dropped member that reaches the package in the forks
that select it.  The forks share such a gate only when each one's is
exactly that, so a member that reaches the package under one fork of
the other dropped sets but not another refuses the drop rather than
guessing which way the projected entry should fire.
Nc              3  D   <"   T F  qS,           F  q"x  K  	  K  	  R # 5irj   rF   )rk   rU   rl   r  s   &  rP   rm   $_merged_fork_gate.<locals>.<genexpr>  s     V>4vf>s    )rE   r   r8   r^  rr   r-  r`   r_   r   rA   ra   rb   )	rH  r   r  r  r  rE   rU   residualcarrieds	   &&&f     rP   r  r    s      JOO4::>>4,<<EO
 5<<>2>4DJ>23q81X'HV5<<>VVGkkm
wT\\$-?-F-F-P-P)QQRR $  P
 3s   *D
	Dc          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )rZ   r   r{   rn  r5   rA  r  r6  r  r[   r-  rF   )r\   s   "rP   r]   r]     s:      
 1 ;	
 
rO   c                J    VP                  V4      pVf   W!,          ^8H  # W9   # )a  Say whether an environment's base pass reached ``name``.

When no base pass ran for the env (the signature is missing), treat
the dep as base only if no fork ran either; with forks but no base
attribution, base status is unknowable and the safe answer is to keep
the membership OR.
)r   )r   rn  rA  r6  rB  s   &&&& rP   r  r    s1      ##I.J)Q..rO   c               $    V ^8  d   QhRRRRRR/# )rZ   rd   r/   rU   r4   r[   rF   )r\   s   "rP   r]   r]     s)     	A 	A
	A7	A 	ArO   c                    \        \        \        V4      \        V P                  P                  4      ,
          4      4      # )zReturn the part of a gate the fork's own selection does not supply.

Two forks of one environment gate a package the same way when these
agree; each fork's own member necessarily differs, and
:func:`_merge_gates` folds it back in.
)rs   r   r   ra   rb   )rd   rU   s   &&rP   r  r    s,     D	C(=(=$>>?@@rO   c               $    V ^8  d   QhRRRRRR/# )rZ   r  AbstractSet[tuple[str, str]]rU   r[   r4   rF   )r\   s   "rP   r]   r]     s$      
&.J rO   c                J    W,          '       d   R# \        \        V4      4      # )aI  Return the gate to conjoin onto one fork's own membership marker.

A gate that names a member the fork's marker still asserts is already
satisfied there, so it drops whole rather than narrowing the fork's
marker to the gate's other selections.  A member whose clause the
projection dropped asserts nothing, so it does not count.
rF   )rs   r   )r  rU   s   &&rP   r  r    s     {{	rO   c                    V ^8  d   QhRRRR/# rZ   rE   %Iterable[tuple[tuple[str, str], ...]]r[   r4   rF   )r\   s   "rP   r]   r]     s     ' '0' 'rO   c                    RpV  F$  pVf   \        V4      MV\        V4      ,          pK&  	  \        \        T;'       g    R4      4      # )zReturn the members every fork of one environment gates a package on.

A gate is a disjunction, so a member every fork names implies every
fork's gate: the package is reached under that member whichever fork
the install context selects.
NrF   r   rs   r   )rE   commonrU   s   &  rP   r  r    sA     +/F$nT&3t92D "%&&rO   c                    V ^8  d   QhRRRR/# r  rF   )r\   s   "rP   r]   r]     s     ! !0! !rO   c                    \        4       pV  F!  pV'       g   Ru # V\        V4      ,          pK#  	  \        \        V4      4      # )zOR the per-fork gates of one collapsing environment into one gate.

A fork with an empty gate installs the package whenever its own
member is selected, so the merged gate is empty too.
rF   r  )rE   r  rU   s   &  rP   r  r    s<     $'5FI#d)    rO   c               (    V ^8  d   QhRRRRRRRR/# )	rZ   ra   r1   r>   rg   rX   r  r[   r{   rF   )r\   s   "rP   r]   r]   -  s0     # ##<# *# 		#rO   c                   \        V P                  4      \        V4      ,
          p\        4       pV F"  pWS,          '       g   K  WEV,
          ,          pK$  	  V P                  p\        V4       F!  w  rx\        V,          p	VRV RV	 2,          pK#  	  \        V4       F!  w  rx\        V,          p	VRV RV	 2,          pK#  	  V# )a  Return the fork's per-package marker with its co-members negated.

Conjoins ``'name' in <variable>`` for every member of the selection
onto the target's environment marker, then ``'name' not in
<variable>`` for every other member of every conflict set the
selection draws from, so at most one fork installs.  With no
``dropped`` members this is the target's
:attr:`~nab_python.target.ResolveTarget.marker_string` plus the
negations, and a selection drawing from no exclusion group is
``marker_string`` unchanged.

``dropped`` are the members of conflict sets the package does not
vary over (:func:`_project_fork`); both their positive clause and
their set's negations fall away, since a set nothing is kept from is
no longer drawn from.
z and "" in z	" not in )r   rb   r  r   r   )
ra   r>   rX   selected
co_membersrp   rT   kindr   variables
   &&&       rP   r8  r8  -  s    * 6##$s7|3H'*uJ!(**J " --FX&
+D1F4&hZ00 ' Z(
+D1F4&	(44 ) MrO   c                    V ^8  d   QhRRRR/# )rZ   rU   Sequence[tuple[str, str]]r[   r{   rF   )r\   s   "rP   r]   r]   S  s     	 	0 	S 	rO   c                D    RP                  R \        V 4       4       4      # )zRender a package's membership gate as a PEP 508 clause.

Each ``(kind, name)`` member becomes ``'name' in extras`` or
``'name' in dependency_groups``; a package two selections reach
disjoins them, since either one installs it.
 or c              3  L   "   T F  w  rR V R\         V,           2x  K  	  R# 5i)"r  N)r   )rk   r  r   s   &  rP   rm   _gate_clause.<locals>.<genexpr>Z  s)      JVJD!D6/567,s   "$)r  r   )rU   s   &rP   _gate_clauser  S  s'     ;; JPQU,  rO   c               0    V ^8  d   QhRRRRRRRRR	R
RR/# )rZ   rK  zSequence[_GatedMarker]r   r   r   r{   r(  r)  r   r   r[   rS   rF   )r\   s   "rP   r]   r]   _  sL     Q Q!QQ Q #	Q
 Q QrO   c                v   . pV  Fj  p\        VP                  WW44      pVP                  '       g   Vf    R# VP                  V4       KF  VP                  \	        WvP                  4      4       Kl  	  \        V 4      ^8X  d#   V ^ ,          P                  '       g
   V^ ,          # \        \        V4      WW44      # )aN  Simplify each gate's environments, then the marker they assemble into.

Simplifying the whole marker in one pass walks a cell space the
membership variables multiply.  Each gate's environments carry no
membership variable, so they shrink first, and the marker they
assemble into is small by the time the second pass canonicalises it.
N)r+  rT   rU   r=  _gated_markerr^  r  )rK  r   r   r(  r   	assembledpartr!  s   &&&&&   rP   r<  r<  _  s     !I%dkk84O
yyy!Z(z99=>  5zQuQx}}}|K	2HDPPrO   c               $    V ^8  d   QhRRRRRR/# )rZ   rT   rS   rU   r  r[   r   rF   )r\   s   "rP   r]   r]   }  s"     3 3- 3/H 3V 3rO   c                d    V f   \        \        V4      4      # \        \        RV  R2V4      4      # )zConjoin a gate onto the simplified environments it selects in.

With no environments the gate is the whole marker.  Otherwise they
are parenthesised, since they may disjoin and ``and`` binds tighter.
())r   r  r  )rT   rU   s   &&rP   r  r  }  s3     ~l4())*q]D122rO   c               $    V ^8  d   QhRRRRRR/# )rZ   rT   r{   rU   r  r[   rF   )r\   s   "rP   r]   r]     s"     $ $s $"; $ $rO   c                f    V'       g   V # \        V4      p\        V4      ^8  d   RV R2pV  RV 2# )z>AND a package's membership gate onto the marker of one target.r  r  z and )r  r^  )rT   rU   clauses   && rP   r  r    s=    $F
4y1}VHAXU6(##rO   c                    V ^8  d   QhRRRR/# )rZ   rA   r@   r[   z&dict[str, tuple[tuple[str, str], ...]]rF   )r\   s   "rP   r]   r]     s      %+rO   c                    V P                  4        UUu/ uF<  w  rV\        \        VP                  P                  P                  4       4      4      bK>  	  upp# u uppi )zMap each target label to a hashable signature of its environment.

Two labels share an environment (they differ only by conflict-fork
selection) when their marker environments are equal, so the sorted
items form a stable, hashable key.
)r_   rs   r   ra   
marker_env)rA   rc   rd   s   &  rP   r3  r3    sS     #==?*KE 	uVDKK2288:;<<*  s   AAc                    V ^8  d   QhRRRR/# )rZ   
signaturesr  r[   z&dict[tuple[tuple[str, str], ...], int]rF   )r\   s   "rP   r]   r]     s      5+rO   c                ^    \        \        4      pV  F  pW;;,          ^,          uu&   K  	  V# )z6Count how many forks each environment signature spans.)r   int)r  countsrn  s   &  rP   r4  r4    s,     =H<LF	Q  MrO   c                    V ^8  d   QhRRRR/# )rZ   rD   zSequence[Marker]r[   r   rF   )r\   s   "rP   r]   r]     s     
& 
&) 
&f 
&rO   c                    V '       g   Rp\        V4      h\        V 4      ^8X  d
   V ^ ,          # \        V \        R7       Uu. uF	  pRV R2NK  	  pp\	        RP                  V4      4      # u upi )z?Return a Marker that evaluates True if any of ``markers`` does.z(_or_markers requires at least one markerr   r  r  r  )r   r^  r   r{   r   r  )rD   r   r  rK  s   &   rP   r  r    sj    8o
7|qqz  &g3787!q1X7E8&++e$%% 9s   A-c                    V ^8  d   QhRRRR/# )rZ   r  r0   r[   tuple[str, str, str]rF   )r\   s   "rP   r]   r]     s     J J= J-A JrO   c                    V P                   V P                  ;'       g    R\        V P                  ;'       g    R4      3# )zStable sort key for a wheel: filename, then url, then local path.

Wheel tags are not used as a key; they parse to a ``frozenset``,
which has no total order.
rX  )r  r   r{   r  )r  s   &rP   r   r     s2     NNEIIOOS1A1A1G1GR-HIIrO   c                    V ^8  d   QhRRRR/# )rZ   packager   r[   r
  rF   )r\   s   "rP   r]   r]     s     
 
w 
+? 
rO   c                    \        V P                  4      V P                  '       d   \        V P                  4      MRV P                  '       d   \        V P                  4      3# R3# )zStable sort key for a package row: name, version, marker string.

The marker tiebreak separates two rows that share a name and version
but differ by environment marker, as a universal resolve emits.
rX  )r{   r   r   rT   )r  s   &rP   r   r     sS     	GLL 'GOOR&~~~GNN  46 rO   )r2   r3   r   r   rj   )rX  N)__conditional_annotations__rL   
__future__r   r   collectionsr   r   dataclassesr   r   	functoolsr   	itertoolsr   pathlibr	   typingr
   r   r   r   nab_index.atomicr   _conflict_kindr   r   _vendor.packaging.markersr   _vendor.packaging.markersetsr   r   r   r   _vendor.packaging.pylockr   r   r   r   r   r   r   _vendor.packaging.specifiersr   _vendor.packaging.utilsr   _vendor.packaging.versionr    configr!   r"   builderr#   coverager$   disjointnessr%   r   r'   collections.abcr(   r)   r*   r+   AbstractSetr   r,   r-   r.   r/   r0   ra   r1   __all__r5   rM   r6   r7   r`   r8   r<   rR   rW   re   rt   r   r3   r2   r   r   r   r   r   r   r   r   r   r   r   r&  r+  r   r   r2  r7  rR  r>  r5  rj  r:  r;  r  r9  r  r  r  r  r  r  r  r  r8  r  r<  r  r  r3  r4  r  r   r   )r  s   @rP   <module>r&     sU   # 	 , *    0 0  . A .    8 7 / F , . 6 ;;2  ' 9y 82) 26) 6!X # $d#. . $.* $d#& & $& $d#	 	 $	 ?" :  2601$ 1D4 DN06 * (3&K
 15K K\2,<4'T*ViX!&@*Z&RD%0Pod63l&=&@@&	A'!& -6K#L	Q<3$
&J
rO   