+
    2jH                    z   R t ^ RIHt ^ RIt^ RIHt ^ RIHt ^RIH	t	H
t
Ht ^RIHtHt ^RIHt ]'       d   ^ RIHtHt ^ R	IHt ^R
IHt ^RIHt R.t^tRt ! R R]4      tRR+RR+/R R lltR R lt R R lt!R R lt"R R lt#R R l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# )-a-  Per-name marker disjointness validation for the PEP 751 emitter.

PEP 751 forbids two ``[[packages]]`` entries with the same name from
firing under one install context.  This module owns the validator
that decides, for every same-name pair, whether their markers can
hold together under the declared install-context universe (declared
environments, with conflict-forbidden co-selections excluded).

The universe is not expressible as a single PEP 508 marker string, so
the check runs through the marker algebra.  For each same-name pair and
each declared environment the validator restricts both markers to the
environment, then walks the conflict-respecting selections of the
membership names the pair references: each conflict set contributes at
most one active member, names in no conflict set are free, and
undeclared names stay absent.  The pair collides when both residuals
still fire together under some selection.  Only the referenced names
enter the walk, so the cost tracks the pair's own markers rather than
the ``powerset(extras) x powerset(groups)`` grid.
)annotationsN)defaultdict)TYPE_CHECKING)
KIND_EXTRA
KIND_GROUPMARKER_VARIABLE_FOR_KIND)IntractableMarkerSet	MarkerSet)canonicalize_name)MappingSequence)Set)Marker)PackageDisjointnessErrori c                      ] tR t^4tRtRtR# )r   a  Two same-name ``[[packages]]`` entries can fire under one context.

PEP 751 forbids ambiguous installer matches.  When more than one
same-name entry has a marker that holds for the same install
context, the consumer cannot pick deterministically.  The
validator surfaces the colliding name and the witness environment.
When the reported collision reduces to a concrete point it also
reports the active extras and groups and the colliding versions; when
that collision is an over-approximated ``contains`` region the algebra
cannot pin to a point, it reports only the name and environment.
Either way the producer can change the resolution or declare a
conflict.
 N)__name__
__module____qualname____firstlineno____doc____static_attributes__r       l/home/user/billing-ledger-validation/.venv/lib/python3.14/site-packages/nab_python/_lockfile/disjointness.pyr   r   4   s    r   exclusive_groupsdeclared_groupsc               4    V ^8  d   QhRRRRRRRRRR	R
R	RR/# )   packagesSequence[Package]environmentsMapping[str, Mapping[str, str]]extrasSequence[str]groupsr   &Sequence[AbstractSet[tuple[str, str]]]r   returnNoner   )formats   "r   __annotate__r*   D   sY     H HH 2H 	H
 H =H <H 
Hr   c          
     &   V'       g   R# \        \        4      pV  F.  pV\        VP                  4      ,          P	                  V4       K0  	  VP                  4        Uu. uF  p\        V4      ^8  g   K  VNK  	  p	pV	'       g   R# \        V4      p
\        V4      p\        W#4      pV	 F  pV Uu. uF  p\        VP                  4      NK  	  ppV Uu. uF  qP                  4       NK  	  pp\        P                  ! \        \        V4      4      ^4       F`  w  ppVV,          VV,          ,          p\!        VW4      p\#        VV,          VV,          VV
4      pVf   KK  Vw  ppp\%        WVVVV4       Kb  	  K  	  R# u upi u upi u upi )a  Confirm same-name ``[[packages]]`` entries are pairwise disjoint.

For every same-name pair the validator asks the marker algebra
whether the two markers can hold together within the declared
install-context universe.  The universe is the declared
environments on the environment axes, with the extras and
dependency-group axes restricted so that no conflict set has two
active members (``exclusive_groups``) and no name outside the
declared ``extras`` / ``groups`` is ever selected.  A pair collides
when, in some declared environment, both markers still fire under a
conflict-respecting selection of the membership names they
reference.

The empty-environments path skips validation: a producer that
does not declare a universe cannot specify what "all envs" means
and the validator would over-report when entries have ``marker
is None``.  Every resolve declares one environment per target, so
that path is reached only by a caller that builds a
:class:`~nab_python.lockfile.LockInput` with no targets of its own.

``exclusive_groups`` declares mutually-exclusive selections from
``[tool.nab].conflicts``: each entry is a set of ``(kind, name)``
members (``kind`` is ``"extra"`` or ``"group"``) of which at most
one may be active.  Their co-selection points are removed from the
universe, so a same-name pair that can fire together only at a
forbidden co-selection is not counted as a collision.  A collision
outside every pruned point still raises, hinting at the
``conflicts`` key when extras or groups drive the colliding markers.

``declared_groups`` carries every conflict set regardless of policy
so the hint can distinguish an undeclared collision (suggest adding
a declaration) from one already declared under ``at-least-one``
(suggest tightening to ``at-most-one`` or ``exactly-one``).
N)r   liststrnameappendvalueslen_distinct_environments_canonical_exclusion_sets_declared_membership_literals_marker_setmarkermembership_literals	itertoolscombinationsrange_conflict_respecting_selections_pair_collision_raise_collision)r   r!   r#   r%   r   r   by_namepkgentriessame_name_entriesdistinct_environmentsexclusion_setsdeclared_membersmarker_setsmsliteralsijnames
selections	collisionlabelenvwitness_envs   &$$$$$                  r   validate_marker_disjointnessrP   D   si   V /:4/@GCHH%%c* 070@U0@WCLSTDT0@U2<@./?@N4VD$:AB'3{3::.'B7BC{**,{C**5W+>BDAqQK(1+-E8~J (AA
<QI $*3'sK %k? C % V CCs    F7F3F	Fc                    V ^8  d   QhRRRR/# )r   r!   r"   r'   z#list[tuple[str, Mapping[str, str]]]r   )r)   s   "r   r*   r*      s      1(r   c                    \        4       p. pV P                  4        FR  w  r4\        \        VP                  4       4      4      pWQ9   d   K/  VP	                  V4       VP                  W434       KT  	  V# )af  Collapse the environment axis to one label per distinct env dict.

A conflict-forked universal lock repeats a python/platform under
several selection labels, so identical env dicts would otherwise be
re-checked once per fork with no added coverage.  The first label
seen for each signature is kept so the error message matches the
pre-dedup iteration order.
)setitemstuplesortedaddr/   )r!   seendistinctrM   env_dict	signatures   &     r   r2   r2      sf     .1UD46H'--/&!123	)* 0 Or   c                    V ^8  d   QhRRRR/# )r   r6   zMarker | Noner'   r	   r   )r)   s   "r   r*   r*      s     ) ) )) )r   c                `    V f   \         P                  ! 4       # \         P                  ! V 4      # )z@Return the algebra set for ``marker``; the full set when absent.)r	   fullfrom_marker)r6   s   &r   r5   r5      s%    ~~~  ((r   c                    V ^8  d   QhRRRR/# )r   r   r&   r'   z list[frozenset[tuple[str, str]]]r   )r)   s   "r   r*   r*      s      <%r   c                P    V  Uu. uF  p\        R V 4       4      NK  	  up# u upi )aR  Project each conflict set to ``(marker variable, canonical name)`` pairs.

``exclusive_groups`` members are ``(kind, name)`` with ``kind`` one
of ``"extra"`` / ``"group"``; the axis a marker tests them on is the
membership variable, so they are keyed by it here to compare against
the markers' membership literals under canonicalisation.
c              3  V   "   T F  w  r\         V,          \        V4      3x  K!  	  R # 5iN)r   r
   ).0kindr.   s   &  r   	<genexpr>,_canonical_exclusion_sets.<locals>.<genexpr>   s)      
%
 &d+->t-DE%s   '))	frozenset)r   memberss   & r   r3   r3      s?     (
 (G	 	 
%
 	
 (  s   #c               $    V ^8  d   QhRRRRRR/# )r   r#   r$   r%   r'   frozenset[tuple[str, str]]r   )r)   s   "r   r*   r*      s$      #0r   c           
         \         \        ,          p\         \        ,          p\        V  Uu0 uF  qB\	        V4      3kK  	  upV Uu0 uF  qC\	        V4      3kK  	  up,          4      # u upi u upi )zReturn every ``(variable, canonical name)`` the universe may select.

A membership literal outside this set names an extra or group the
producer never declared, so no install context selects it; the
universe pins it absent.
)r   r   r   rh   r
   )r#   r%   
extras_var
groups_varr.   s   &&   r   r4   r4      sg     **5J)*5J;AB64'-	.6B=C
DVT)$/0V
D	E B
Ds   A)A.
c               (    V ^8  d   QhRRRRRRRR/# )r   rJ   rk   rC   r&   rD   r'   zlist[dict[str, frozenset[str]]]r   )r)   s   "r   r*   r*      s0     , ,%,:, 1, %	,r   c                "   \        R V  4       4      pW,          pV Uu. uF$  qUV,          '       g   K  \        WT,          4      NK&  	  ppV UUu0 uF  qw F  qkK  	  K  	  p	pp\        WI,
          4      p
V Uu. uF  p\        V4      ^,           NK  	  up^.\        V
4      ,          ,           p^pV F*  pW,          pV\        8  g   K  R\         2p\	        V4      h	  V UUu. uF/  p\        4       .V Uu. uF  p\        V04      NK  	  up,           NK1  	  ppp. p\
        P                  ! V!   F  p\        4       P                  ! V!  p\        VV4      '       g   K/  \        ^\        V
4      ,          4       Fh  pT\        \        V
4      4       Uu0 uF$  pV^V,          ,          '       g   K  V
V,          kK&  	  up,          pVP                  \        VV4      4       Kj  	  K  	  V# u upi u uppi u upi u upi u uppi u upi )aU  Enumerate the membership selections the pair's markers can see.

A selection binds every membership variable the pair references to a
concrete set of active names.  Only declared names can be active, so
an undeclared reference stays absent in every selection.  Each
conflict set that touches the referenced names contributes at most
one active member; names in no conflict set are free and appear in
both states.  The count is the product of the per-conflict-set
choices and the free powerset, guarded by :data:`_MAX_SELECTIONS` so
a pathological input fails loud rather than iterating unbounded.
c              3  *   "   T F	  w  rVx  K  	  R # 5irc   r   )rd   variable_s   &  r   rf   2_conflict_respecting_selections.<locals>.<genexpr>   s     BE[XEs   z&conflict-respecting selections exceed )rh   rV   r1   _MAX_SELECTIONSr   r8   productunion_conflict_respectingr:   r/   _selection_env)rJ   rC   rD   referenced_varsdeclaredri   conflict_choiceschoicememberconstrainedfreecountssizecountmsggroup_optionsrK   combobasemaskkactives   &&&                   r   r;   r;      s      BEBBO'H2@2@whDVDV"w!".   )9N(8fvV6v6(8KN(()D,<=,<&c&kAoo,<=c$iOFD/!:?:KLC&s++	  '&F 
6B6F8,6BBB&   35J""M2{  %(#D.99!s4y.)DeCI.>R.>$!q&//WT!WW.>RRFn_fEF *	 3 5 O > C Ss:   G1G1G6:G<'H:HHH
6H
Hc               $    V ^8  d   QhRRRRRR/# )r   r   rk   rC   r&   r'   boolr   )r)   s   "r   r*   r*      s&      &: 
r   c                x   a  \         ;QJ d    V 3R lV 4       F  '       d   K   R# 	  R# ! V 3R lV 4       4      # )z=Whether no conflict set has two active members in ``active``.c              3  V   <"   T F  p\        VS,          4      \        8  x  K   	  R # 5irc   )r1   _MUTUALLY_EXCLUSIVE_LIMIT)rd   ri   r   s   & r   rf   '_conflict_respecting.<locals>.<genexpr>  s$      IWgGf 99s   &)FT)all)r   rC   s   f&r   rx   rx      s@    
 3 IW33 3 3 IW  r   c               $    V ^8  d   QhRRRRRR/# )r   rz   frozenset[str]r   rk   r'   zdict[str, frozenset[str]]r   )r)   s   "r   r*   r*   	  s)     O O#O-GOOr   c                    V  Uu/ uF  q"\        4       bK  	  ppV F  w  r$W2,          P                  V4       K  	  VP                  4        UUu/ uF  w  r%V\        V4      bK  	  upp# u upi u uppi )a  Group an active selection into a per-variable ``restrict`` mapping.

Every referenced membership variable is bound, even to the empty set,
so a marker's membership atoms all fold to constants under the
resulting restriction rather than leaving a residual axis.
)rS   rW   rT   rh   )rz   r   rr   groupedr.   rJ   s   &&    r   ry   ry   	  sn     ET#TOceOOG#T d# !>EmmoNo?8Hi&&oNN $U Os   A*A/c          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
r   leftr	   rightrK   z#Sequence[dict[str, frozenset[str]]]rB   z'Sequence[tuple[str, Mapping[str, str]]]r'   zLtuple[str, Mapping[str, str], dict[str, str | frozenset[str]] | None] | Noner   )r)   s   "r   r*   r*     s<      
 4 C	
 Rr   c                <   V F  w  rEV P                  V4      pVP                  V4      pV Fh  pVP                  V4      VP                  V4      ,          p	V	P                  4       '       d   KB  V	P                  4       p
V
f	   WER3u u # WE/ V
CVC3u u # 	  K  	  R# )a  Return a declared env where both markers can fire together, or None.

Each marker is restricted to the environment (its environment atoms
fold to constants, leaving the membership residual).  Each
conflict-respecting selection binds the membership variables, so the
pair collides in that environment when both bound residuals stay
non-empty together.  On a collision the label, the environment, and a
concrete satisfying assignment (the selection merged with
:meth:`MarkerSet.witness`) are returned; the witness is ``None`` when
the first colliding selection is an opaque-``contains``
over-approximation the algebra cannot reduce to a point.
N)restrictis_emptywitness)r   r   rK   rB   rM   rN   	left_here
right_here	selectionrL   r   s   &&&&       r   r<   r<     s    $ ,
MM#&	^^C(
#I!**95
8K8KI8VVI!!##'')G4''7'7Y777 $ , r   c               $    V ^8  d   QhRRRRRR/# )r   rO   z"Mapping[str, str | frozenset[str]]rr   r-   r'   r   r   )r)   s   "r   r*   r*   8  s$      3?Br   c                h    V P                  V4      p\        V\        4      '       d   V# \        4       # )z>Return the set the witness selected for a membership variable.)get
isinstancerh   )rO   rr   values   && r   _membership_selectionr   8  s,     OOH%E%##;r   c               4    V ^8  d   QhRRRRRRRRR	R
RRRR/# )r   r@   r    rE   Sequence[MarkerSet]rM   r-   rN   zMapping[str, str]rO   z&dict[str, str | frozenset[str]] | Noner   r&   r'   r(   r   )r)   s   "r   r*   r*   B  sN     6! 6!6!$6! 6! 
	6!
 86! <6! 
6!r   c                   \        V ^ ,          P                  4      pVf   V RV: 2p\        V4      h\        \        ,          p\        \
        ,          p	\        WH4      p
\        WI4      p/ VCVCWW/Cp\        WRR7       UUu. uF/  w  rVP                  V4      P                  4       '       d   K,  W3NK1  	  ppp\        V
4      p\        V4      p\        R V 4       4      p\        V UUu. uF  w  pqNK	  	  uppVVV4      pV R\        V4       RV: RV: RV: R	V V 2p\        V4      hu uppi u uppi )
a  Raise :class:`DisjointnessError` with a concrete witness context.

The witness names one install context where the pair holds together,
so the message reports the environment, the active ``(extras,
groups)`` selection, the entries that fire there, and their versions.
When the reported collision has no pinned point (an opaque-``contains``
over-approximation), the pair is still reported as non-disjoint,
without a point.
z/: same-name entries are not disjoint under env=T)strictc              3  x   "   T F0  w  rVP                   '       d   \        VP                   4      MR x  K2  	  R# 5i) N)versionr-   )rd   prs   s   &  r   rf   #_raise_collision.<locals>.<genexpr>n  s'     Ohda			c!))nr9hs   8:z: z entries fire under env=z extras=z groups=z: versions=)r-   r.   r   r   r   r   r   zipr   r   rV   _conflict_hintr1   )r@   rE   rM   rN   rO   r   r.   r   rm   rn   extra_selectiongroup_selectionpointr?   rF   matchingextra_subsetgroup_subsetversionsrs   hints   &&&&&&               r   r=   r=   B  sj   " wqzDEeYO$$)*5J)*5J+KDO+KDO
0
0
0 		0E 7==GC{{5!**, 		=   /*L/*LOhOOH!"2"L,D &3x=/ "y 0
<"+hZ&	  C
  % 	#s   )D44D40D:
c          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
r   rE   r   r   r$   r   r   r&   r'   r-   r   )r)   s   "r   r*   r*   {  s:     . .$..  . <	.
 	.r   c                  a \        V \        \        ,          V4      p\        V \        \        ,          V4      pV'       g   V'       g   R# V Uu0 uF  p\        \	        V4      3kK  	  upV Uu0 uF  p\        \	        V4      3kK  	  up,          o\
        ;QJ d    V3R lV 4       F  '       g   K   RM	  RM! V3R lV 4       4      pV'       d    R#  R# u upi u upi )a  Return a one-line hint about declaring a conflict, when relevant.

Relevant means a membership variable actually drives the witness
point: a referenced extra or dependency group is active in the
colliding context, so declaring the pair mutually exclusive in
``[tool.nab].conflicts`` could prune that point.  A purely
environment-driven collision (no membership variable referenced, or
the witness selects none of the referenced ones) gets no hint
because a conflict declaration would not help.

When ``declared_groups`` already covers the active members, the
hint instead suggests tightening the policy: an ``at-least-one``
declaration permits co-selection, so the validator still raises and
the user has to switch to an exclusive policy to prune the point.
r   c              3  T   <"   T F  p\        V3R  lV 4       4      ^8  x  K  	  R# 5i)c              3  @   <"   T F  w  rW3S9   g   K  ^x  K  	  R# 5i)   Nr   )rd   re   r.   r   s   &  r   rf   +_conflict_hint.<locals>.<genexpr>.<genexpr>  s     C*$TLF,BAAs   
N)sum)rd   r{   r   s   & r   rf   !_conflict_hint.<locals>.<genexpr>  s(      'H 	CCCqH's   %(TFz. These members are declared in [tool.nab].conflicts under a policy that permits co-selection; switch to at-most-one or exactly-one to prune the colliding contextzx. If these are intentionally mutually exclusive, declare them in [tool.nab].conflicts so the colliding context is pruned)_membership_drives_pointr   r   r   r
   any)	rE   r   r   r   extras_drivengroups_drivennalready_declaredr   s	   &&&&    @r   r   r   {  s    * --j9<M --j9<M ]:FG,Qz,Q/0,G4@K4@q&q)*LK F s 'sss '  :	
	C H Ks   C0C c               (    V ^8  d   QhRRRRRRRR/# )	r   rE   r   rr   r-   subsetr$   r'   r   r   )r)   s   "r   r*   r*     s,     6 6$6036=J6	6r   c                F  a V  UUUu0 uF&  pVP                  4        F  w  rEWA8X  g   K  VkK  	  K(  	  ppppV'       g   R# V Uu0 uF  p\        V4      kK  	  upo\        ;QJ d    V3R lV 4       F  '       g   K   R# 	  R# ! V3R lV 4       4      # u upppi u upi )a>  Return True when a referenced ``variable`` literal is active here.

A membership variable drives the witness only when the witness
``subset`` is non-empty and intersects the literals the colliding
markers test for membership in ``variable`` (compared under
canonicalisation, matching the universe's axis restriction).
Fc              3  ,   <"   T F	  qS9   x  K  	  R # 5irc   r   )rd   r.   r   s   & r   rf   +_membership_drives_point.<locals>.<genexpr>  s     5*$v~*s   T)r7   r
   r   )rE   rr   r   
marker_setvarr.   
referencedr   s   &&&    @r   r   r     s     &%J#779IC? 	9 	%   289&$%&9F35*53353535*555 :s   B
BBr   )r   ),r   
__future__r   r8   collectionsr   typingr   _conflict_kindr   r   r   _vendor.packaging.markersetsr   r	   _vendor.packaging.utilsr
   collections.abcr   r   r   AbstractSet_vendor.packaging.markersr   _vendor.packaging.pylockr   __all__r   ru   
ValueErrorr   rP   r2   r5   r3   r4   r;   rx   ry   r<   r   r=   r   r   r   r   r   <module>r      s   ( #  #   M M J 71222    
  H @BH ?AHV,)&",^O@6!r.b6r   