+
    4jm                      a  0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t
^ RIt^ RIHt ^ RIHt ^ RIHt ^RIHtHt ^RIHtHt ^RIHt ]'       d   ^ R	IHt ^R
IHtHt . RMOtRt^t ^t!Rt"]#! RR]"R04      t$]
PJ                  ! R4      t& ! R R]PN                  4      t(]! RRR7       ! R R4      4       t) ! R R]PN                  4      t* ! R R4      t+ ! R R4      t,]! RRR7       ! R R4      4       t- ! R R ]PN                  4      t.]/]0],]13,          ,          R,          t2]*Pf                  ].Ph                  R3t5R!]6R"&    ! R# R$]74      t8 ! R% R&]74      t9R' R( lt:R) R* lt;R+ R, lt<R- R. lt=R/ R0 lt>R1 R2 lt?R3 R4 lt@R5 R6 ltAR7 R8 ltBR9 R: ltCR; R< ltDR= R> ltER? R@ ltFRA RB ltGRC RD ltHRE RF ltIRG RH ltJRIRRJ]/RK RL lltKR# )Na  HTTP range-request reader for a remote wheel's core metadata.

Recovers a wheel's ``METADATA`` by ranged reads of the remote ZIP when the
index publishes no PEP 658 sidecar. The reader drives an
:class:`~nab_index.transport.AsyncHttpTransport`, learns each host's range
capability once per run through a shared :class:`RangeCapabilityMemo`, and
navigates the ZIP with the standard library's :class:`zipfile.ZipFile` over a
sparse buffer so no EOCD scan, deflate, or CRC logic is hand-rolled.

Two kinds of exception travel outward: a
:class:`~nab_index.client.MalformedSimpleResponseError` for METADATA bytes
that are not valid UTF-8, and the transport's error when the wheel URL itself
cannot be served (a 404 on the file, a failing plain GET).  A server that
merely refuses the Range mechanism is stepped down instead, from a suffix
range to absolute ranges to a plain full-body GET.  Every other failure to
obtain metadata returns a result whose ``text`` is ``None``.
)annotationsN)	dataclass)TYPE_CHECKING)urlsplit)MalformedSimpleResponseErrorWheelHashMismatchError)UnsupportedWheelErrorwheel_metadata_member)IDENTITY_HEADERS)NormalizedName)AsyncHttpTransportHttpResponseRangeCapabilityRangeCapabilityMemoRangeMetadataResultRangeOutcomei (  i  i  i  i  zbytes\s+(\d+)-(\d+)/(\d+)c                  *    ] tR t^BtRtRtRtRtRtRt	R# )r   z=How rung 4 obtained (or failed to obtain) a wheel's METADATA.partial	full-bodyunsupportedmissing N)
__name__
__module____qualname____firstlineno____doc__PARTIAL	FULL_BODYUNSUPPORTEDMISSING__static_attributes__r       f/home/user/pdf2html-billing-ledger-validate/.venv/lib/python3.14/site-packages/nab_index/lazy_wheel.pyr   r   B   s    GGIKGr"   T)frozenslotsc                  0    ] tR t^Kt$ RtR]R&   R]R&   RtR# )r   z=The recovered METADATA text and the outcome that produced it.
str | Nonetextr   outcomer   N)r   r   r   r   r   __annotations__r!   r   r"   r#   r   r   K   s    G
r"   c                  .    ] tR t^StRtRtRtRtRtRt	Rt
R# )	r   a  The request shape to lead with on a netloc, monotonic toward more restrictive.

``SUFFIX_OK`` is optimistic: a host that volunteers a 200 full body for a
suffix range stays ``SUFFIX_OK``, since leading with the suffix form again
costs the same single request while a proxy that only ignores ranges while
filling its cache gets to serve cheap partial reads again.
``FULL_BODY_ONLY`` is for hosts that, once the suffix form was already
unusable, refused or ignored ranges or honoured one without reporting a
complete-length; their wheels are fetched whole.  An answer that speaks
for the one file never latches it: a 416 or a zero complete-length
describes an empty or shrunk artifact, not the netloc.
unknownz	suffix-okzabsolute-onlyzfull-body-onlyr   r   N)r   r   r   r   r   UNKNOWN	SUFFIX_OKABSOLUTE_ONLYFULL_BODY_ONLYr   r!   r   r"   r#   r   r   S   s"     GI#M%NKr"   c                  V    ] tR t^htRtR R ltR R ltR R ltR R	 ltR
 R lt	Rt
R# )r   a>  Per-netloc range capability, single-flight per host within one run.

Touched only on the fetcher event loop's single thread, so its state
needs no lock. Discovery of an ``UNKNOWN`` host is kept to one probe
under a burst by an :class:`asyncio.Event` per netloc: the first task
probes while later tasks await the event, then read the settled state.
The owner releases the probe as soon as the capability settles, so
waiters overlap with its remaining growth and member reads.  An owner
whose acquisition fails settles nothing; its released waiters then probe
for themselves.
c                   V ^8  d   QhRR/# )   returnNoner   )formats   "r#   __annotate__ RangeCapabilityMemo.__annotate__u   s     6 6$ 6r"   c                "    / V n         / V n        R# )z;Start with every netloc ``UNKNOWN`` and no probe in flight.N)_states	_inflightselfs   &r#   __init__RangeCapabilityMemo.__init__u   s    3535r"   c                    V ^8  d   QhRRRR/# )r3   netlocstrr4   r   r   )r6   s   "r#   r7   r8   z   s     A A A Ar"   c                V    V P                   P                  V\        P                  4      # )z-Return the learned capability for ``netloc``.)r:   getr   r-   r=   rA   s   &&r#   
capabilityRangeCapabilityMemo.capabilityz   s    ||(?(?@@r"   c               $    V ^8  d   QhRRRRRR/# )r3   rA   rB   rF   r   r4   r5   r   )r6   s   "r#   r7   r8   ~   s!     * *S *o *$ *r"   c                "    W P                   V&   R# )z/Store the capability discovered for ``netloc``.N)r:   )r=   rA   rF   s   &&&r#   recordRangeCapabilityMemo.record~   s    )Vr"   c                    V ^8  d   QhRRRR/# )r3   rA   rB   r4   boolr   )r6   s   "r#   r7   r8      s        r"   c                   "   V P                   P                  V4      pVe   VP                  4       G Rj  xL
  R# \        P                  ! 4       V P                   V&   R#  L*5i)zCoordinate single-flight discovery for ``netloc``.

Returns ``True`` when the caller owns the probe and must discover
the capability. Returns ``False`` when another task is already
probing; the caller awaits it and then re-reads
:meth:`capability`.
NFT)r;   rD   waitasyncioEvent)r=   rA   events   && r#   await_probeRangeCapabilityMemo.await_probe   sO      ""6***,!(v s   3A"A +A"c                    V ^8  d   QhRRRR/# )r3   rA   rB   r4   r5   r   )r6   s   "r#   r7   r8      s     ) )3 )4 )r"   c                X    V P                   P                  V4      P                  4        R# )z6Wake tasks waiting on ``netloc``'s probe and clear it.N)r;   popsetrE   s   &&r#   finish_probe RangeCapabilityMemo.finish_probe   s    6"&&(r"   )r;   r:   N)r   r   r   r   r   r>   rF   rJ   rS   rY   r!   r   r"   r#   r   r   h   s&    
6
A*) )r"   c                      ] tR t^tRtR R ltR R ltR R ltR R	 lt]	P                  3R
 R lltR R ltRR R lltRtR# )_SparseFilea  A read-only file-like over sparse byte spans of a remote file.

Implements the subset :class:`zipfile.ZipFile` drives: ``read``,
``seek``, ``tell``, ``seekable``. Populated spans are kept sorted and
non-overlapping; a read across an unpopulated gap returns only the bytes
up to the gap (zero bytes when the start is unpopulated), which makes
ZipFile raise :class:`zipfile.BadZipFile`, the signal to fetch more or
give up.
c                    V ^8  d   QhRRRR/# )r3   lengthintr4   r5   r   )r6   s   "r#   r7   _SparseFile.__annotate__   s     & &s &t &r"   c                <    Wn         ^ V n        . V n        . V n        R# )z:Create a file of ``length`` bytes with no spans populated.N)_length_pos_starts_spans)r=   r^   s   &&r#   r>   _SparseFile.__init__   s    	"$#%r"   c               $    V ^8  d   QhRRRRRR/# )r3   startr_   databytesr4   r5   r   )r6   s   "r#   r7   r`      s!     ( (c ( (4 (r"   c                0   V'       g   R# \         P                  ! V P                  V4      pV\        V P                  4      8  d   V P                  V,          V8X  d   R# V P                  P	                  W14       V P
                  P	                  W24       R# )z6Populate ``[start, start + len(data))`` with ``data``.N)bisectbisect_leftrd   leninsertre   )r=   rh   ri   indexs   &&& r#   add_span_SparseFile.add_span   sf    ""4<<73t||$$e)<)EE)5'r"   c               $    V ^8  d   QhRRRRRR/# )r3   rh   r_   endr4   rM   r   )r6   s   "r#   r7   r`      s!     ( (s ( ( (r"   c                    V P                   pWn         V P                  W!,
          4      pW0n         \        V4      W!,
          8H  # )z3Return whether ``[start, end)`` is fully populated.)rc   readrn   )r=   rh   rt   savedri   s   &&&  r#   	populated_SparseFile.populated   s6    			yy%	4yCK''r"   c                   V ^8  d   QhRR/# )r3   r4   rM   r   )r6   s   "r#   r7   r`      s      $ r"   c                    R# )zReport the file as seekable.Tr   r<   s   &r#   seekable_SparseFile.seekable   s    r"   c               $    V ^8  d   QhRRRRRR/# )r3   offsetr_   whencer4   r   )r6   s   "r#   r7   r`      s!      3  c r"   c                V   V\         P                  8X  d   Wn        V P                  # V\         P                  8X  d&   V ;P                  V,          un        V P                  # V\         P                  8X  d%   V P
                  V,           V n        V P                  # RV 2p\        V4      h)z%Move the read position and return it.zunsupported whence: )osSEEK_SETrc   SEEK_CURSEEK_ENDrb   
ValueError)r=   r   r   msgs   &&& r#   seek_SparseFile.seek   s    R[[ I yy r{{"III yy r{{"v-DI yy )1CS/!r"   c                   V ^8  d   QhRR/# )r3   r4   r_   r   )r6   s   "r#   r7   r`      s      c r"   c                    V P                   # )z!Return the current read position.)rc   r<   s   &r#   tell_SparseFile.tell   s    yyr"   c                    V ^8  d   QhRRRR/# )r3   size
int | Noner4   rj   r   )r6   s   "r#   r7   r`      s       U r"   c                   Ve   V^ 8  d   V P                   V P                  ,
          MTp\        4       pV P                  pV^ 8  d   \        P                  ! V P
                  V4      ^,
          pV^ 8  d   MV P
                  V,          pV P                  V,          pWF\        V4      ,           8  d   MGWF,
          p\        \        V4      V,
          V4      p	W7WV	,            ,          pWI,          pW),          pK  W@n        \        V4      # )zReturn up to ``size`` bytes from the current position.

``None`` or a negative ``size`` reads to the end, as on a file object.
Reads across contiguous spans and stops at the first gap, so a
short return is the caller's cue that more bytes are needed.
)
rb   rc   	bytearrayrl   bisect_rightrd   re   rn   minrj   )
r=   r   	remainingresultposrp   rh   ri   r   takes
   &&        r#   rv   _SparseFile.read   s     15qDLL499,d	ii!m''c:Q>EqyLL'E;;u%Dc$i''[Fs4y6)95D6TM22FKCI	V}r"   )rb   rc   re   rd   N))r   r   r   r   r   r>   rq   rx   r|   r   r   r   r   rv   r!   r   r"   r#   r\   r\      s8    &(( /1kk  r"   r\   c                  P    ] tR t^t$ RtR]R&   ^ tR]R&   ^ tR]R&   RtR]R	&   R
t	R# )_SuffixOutcomez'The result of one suffix-range attempt.rB   kindr_   totallowr"   rj   bodyr   N)
r   r   r   r   r   r*   r   r   r   r!   r   r"   r#   r   r      s&    1
IE3NCLD%r"   r   c                  &    ] tR t^tRtRtRtRtRtR# )_AcqKindz0Which shape of bytes an acquisition handed back.sparser   noner   N)	r   r   r   r   r   SPARSEr   NONEr!   r   r"   r#   r   r      s    :FIDr"   r   -tuple[RangeCapability, _AcqKind, _AcqPayload]_UNSUPPORTED_NONEc                  2   a  ] tR tRtRtR V 3R lltRtV ;t# )_RangeRefusedErrori  zFA growth or member range was refused after the tail had been honoured.c                    V ^8  d   QhRRRR/# )r3   statusr_   r4   r5   r   )r6   s   "r#   r7   _RangeRefusedError.__annotate__  s      s t r"   c                	8   < \         SV `  R V 24       Wn        R# )zrange refused with HTTP N)superr>   r   )r=   r   	__class__s   &&r#   r>   _RangeRefusedError.__init__  s    3F8<=r"   )r   )r   r   r   r   r   r>   r!   __classcell__)r   s   @r#   r   r     s    P r"   r   c                      ] tR tRtRtRtR# )_UnreadableWheelErrori  zEThe zip machinery cannot read the fetched bytes as an archive at all.r   N)r   r   r   r   r   r!   r   r"   r#   r   r     s    Or"   r   c                    V ^8  d   QhRRRR/# )r3   responser   r4   rM   r   )r6   s   "r#   r7   r7     s     C CL CT Cr"   c                v    V P                   P                  R4      pVRJ;'       d    VP                  4       R8g  # )zDReturn whether the response carries a non-identity Content-Encoding.zcontent-encodingNidentity)headersrD   lower)r   encodings   & r#   _non_identityr     s8    ##$67H4BBHNN$4
$BBr"   c                    V ^8  d   QhRRRR/# )r3   valuer'   r4   ztuple[int, int, int] | Noner   )r6   s   "r#   r7   r7     s      
 /J r"   c                    V f   R# \         P                  V P                  4       4      pVf   R#  \        V^,          4      \        V^,          4      \        V^,          4      3#   \         d     R# i ; i)z:Parse ``bytes start-end/total`` into a tuple, or ``None``.N)_CONTENT_RANGE_REmatchstripr_   r   )r   r   s   & r#   _parse_content_ranger     sd    }##EKKM2E}E!Hs58}c%(m<< s   4A& &A54A5c               (    V ^8  d   QhRRRRRRRR/# )r3   	transportr   urlrB   range_headerr4   r   r   )r6   s   "r#   r7   r7   )  s2     Y Y!Y(+Y;>YYr"   c                X   "   V P                  V/ \        CRV/CR7      G Rj  xL
 #  L5i)zBGET ``url`` for ``range_header`` bytes, forcing identity encoding.Ranger   N)rD   r
   )r   r   r   s   &&&r#   
_range_getr   )  s.      s,W/?,W,,WXXXXs   !*(*c               (    V ^8  d   QhRRRRRRRR/# )	r3   r   r   r   rB   	tail_sizer_   r4   r   r   )r6   s   "r#   r7   r7   0  s,     ' '!'(+'8;''r"   c                p  "   \        WRV 24      G Rj  xL
 pVP                  pV\        8X  d)   \        V4      '       g   \	        RVP
                  R7      # V\        8X  d   \        V4      '       g   VP
                  p\        VP                  P                  R4      4      pVf   \	        R4      # Vw  rxp	W^,
          8X  d,   W,
          ^,           \        V4      8X  d   \	        RWVR7      # \	        R4      # V\        9  d"   V\        \        39  d   VP                  4        \	        R4      #  EL5i)	a  Try a suffix range, classifying the server's answer.

A 206 whose Content-Range is absent, unparseable, or of unknown length
(``bytes a-b/*``) gives no offset to anchor the returned bytes, so it
steps down to absolute ranges rather than guessing what the body is.
zbytes=-Nfull)r   content-range	downgradesuffix)r   r   r   )r   status_code_HTTP_OKr   r   content_HTTP_PARTIALr   r   rD   rn   _RANGE_REJECT_STATUSESraise_for_status)
r   r   r   r   r   r   parsedrh   rt   r   s
   &&&       r#   _suffix_attemptr   0  s      	')0EFFH!!F-"9"9f8+;+;<<}X'>'>%h&6&6&:&:?&KL>!+.."E!)a3t9 <!(%NNk**++? 1 	!!#+&&% Gs   D6D3DD6c               (    V ^8  d   QhRRRRRRRR/# )	r3   r   r   r   rB   r   r_   r4   r   r   )r6   s   "r#   r7   r7   N  s2     F F!F(+F8;F2Fr"   c                  "   \        WR4      G Rj  xL
 pVP                  \        9   d'   \        WVP                  \        8g  R7      G Rj  xL
 # VP                  \
        8X  d=   \        V4      '       g,   \        P                  \        P                  VP                  3# VP                  \        8w  g   \        V4      '       d   VP                  4        \        # \        VP                   P#                  R4      4      pVe   V^,          ^ 8X  d   \        WVRJ R7      G Rj  xL
 # \%        WV^,          V4      G Rj  xL
 #  EL6 L L% L5i)a]  Learn the length with ``bytes=0-0``, then read the tail absolutely.

A probe that is refused, or that reports no usable total, steps down to
the plain GET: neither answer says the file is unserveable, so only the
plain GET is authoritative for whether the wheel can be served at all.
Any other 4xx/5xx raises through, whatever its Content-Encoding.
z	bytes=0-0Nlatchr   )r   r   r   _fallback_full_body_HTTP_RANGE_NOT_SATISFIABLEr   r   r   r0   r   r   r   r   r   r   r   r   rD   _absolute_tail)r   r   r   prober   s   &&&  r#   _absolute_attemptr   N  s     Y[99E22(%"3"37R"R
 
 	
 H$]5-A-A..0B0BEMMRRM)]5-A-A   !%--"3"3O"DEF~a )v~NNN	q	9EEE! :
 OEsF   EE:EECE'E(EEEEEEc          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
r3   r   r   r   rB   r   r_   r   r4   r   r   )r6   s   "r#   r7   r7   k  s;     K K!K(+K47KDGK2Kr"   c           	       "   \        ^ W#,
          4      p\        WRV RV^,
           24      G Rj  xL
 pVP                  \        9   d'   \	        WVP                  \
        8g  R7      G Rj  xL
 # VP                  \        8X  d=   \        V4      '       g,   \        P                  \        P                  VP                  3# VP                  \        8w  g   \        V4      '       d   VP                  4        \        # \!        V4      pVP#                  WEP                  4       \        P$                  \        P&                  Wd33#  EL L5i)a  Read the tail window with an absolute range once the length is known.

A tail refused after an honoured probe still steps down to the plain GET,
since a shrunk file or a flaky proxy can 416 a range the probe implied.
Any other 4xx/5xx raises through, whatever its Content-Encoding.
bytes=-Nr   )maxr   r   r   r   r   r   r   r   r0   r   r   r   r   r   r   r\   rq   r/   r   )r   r   r   r   r   tailr   s   &&&&   r#   r   r   k  s     a"
#CIfSE519+,FGGD11($"2"26Q"Q
 
 	
 8#M$,?,?..0B0BDLLQQ=(M$,?,?  F
OOC&))8??VMJJ H
s"   /EE:E,E	-CE	Ec               $    V ^8  d   QhRRRRRR/# )r3   r   r   r   rB   r4   bytes | Noner   )r6   s   "r#   r7   r7     s"      &8 s | r"   c                   "   V P                  V\        R7      G Rj  xL
 pVP                  \        8X  d   \	        V4      '       g   VP
                  # VP                  4        R#  LH5i)a  Fetch the whole wheel with a plain GET, leaving the Range mechanism out.

Reached for a netloc memoed ``FULL_BODY_ONLY`` and as the last step down
after a refused range: the file may still be served without the Range
header, and this GET is the authoritative check.  A 4xx/5xx here raises
through and fails the resolve, since the listing advertised a file the
index cannot serve; a non-identity encoding returns ``None``, no usable
bytes.
r   N)rD   r
   r   r   r   r   r   )r   r   r   s   && r#   _full_body_fetchr     sV      ]]30@]AAHx'h0G0G	 Bs   A(A&A	A(c               (    V ^8  d   QhRRRRRRRR/# )	r3   r   r   r   rB   r   rM   r4   r   r   )r6   s   "r#   r7   r7     s,     ? ?!?(+?7;?2?r"   c                  "   \        W4      G Rj  xL
 pVf   \        # V'       d"   \        P                  \        P
                  V3# \        P                  \        P
                  V3#  LX5i)aw  Step an unusable range down to the plain GET, choosing what it teaches.

``latch`` records the netloc ``FULL_BODY_ONLY``, so later wheels skip the
wasted probes; it is for an answer that leaves the Range mechanism
unusable on this host.  An answer that speaks for the one file (a 416, or
a zero complete-length) teaches the memo nothing, and later wheels probe
ranges again.
N)r   r   r   r0   r   r   r-   )r   r   r   r   s   &&$ r#   r   r     sY      ")11D|  ..0B0BDII##X%7%7>> 2s   A,A*A,AA,c          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )r3   r   r   r   rB   rF   r   r   r_   r4   r   r   )r6   s   "r#   r7   r7     s:     > >!>	>  > 	>
 3>r"   c                  "   V\         P                  J d   \        # V\         P                  J d?   \	        W4      G Rj  xL
 pVf   \        # \         P                  \
        P                  V3# V\         P                  \         P                  39   d   \        WV4      G Rj  xL
 pVP                  R8X  dh   \        VP                  4      pVP                  VP                  VP                  4       \         P                  \
        P                   WeP                  33# VP                  R8X  d,   \         P                  \
        P                  VP                  3# \#        WV4      G Rj  xL
 #  EL1 L L	5i)zFFetch bytes per the netloc's known capability, learning it if unknown.Nr   r   )r   r   r   r0   r   r   r   r-   r.   r   r   r\   r   rq   r   r   r   r   )r   r   rF   r   r   r   r   s   &&&&   r#   _acquirer     s     _000  _333%i55<$$..0B0BDIIo--/H/HII&yyAA;;(" .FOOFJJ4#--x@TUU;;& #--x/A/A6;;OO"99=== 6
 B >s6   =E7E0 A#E7#E3$CE7+E5,E73E75E7c          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )r3   r   r   r   r\   partial_lowr_   
wheel_hashtuple[str, str] | Noner4   r   r   )r6   s   "r#   r7   r7     s:        '	
 r"   c                   V P                   \        8X  dF   \        V 4      '       g5   \        V P                  V4       VP                  ^ V P                  4       ^ # V P                   \        9   d   \        V P                   4      hV P                   \        8w  g   \        V 4      '       d   V P                  4        R# VP                  W P                  4       V# )ap  Absorb a growth or member range response into ``sparse``.

Returns the low offset at which bytes were populated, or ``None`` when the
response yielded no usable bytes.  A volunteered 200 full body is checked
against ``wheel_hash`` (raising :class:`WheelHashMismatchError` on a
mismatch) and then populates the whole file from offset 0, used rather than
discarded.  A range refused mid-read raises :class:`_RangeRefusedError` so
the reader can step down to the plain GET.  Any other 4xx/5xx on the wheel
URL raises through and fails the resolve, matching the first round trip; a
non-identity encoding yields no usable bytes.
N)
r   r   r   _verify_full_bodyr   rq   r   r   r   r   )r   r   r   r   s   &&&&r#   _absorb_ranger     s    " x'h0G0G(**J78++,55 !5!566},h0G0G!!#
OOK!1!12r"   c                    V ^8  d   QhRRRR/# )r3   r   r\   r4   zipfile.ZipFile | Noner   )r6   s   "r#   r7   r7     s     - -k -&< -r"   c                     \         P                  ! V 4      #   \         P                   d     R# \         d   p\        ThRp?ii ; i)a  Open a ZipFile over the current spans, or ``None`` if more bytes are needed.

A window with a gap always reads as a truncated directory, which is
:class:`zipfile.BadZipFile`, the grow signal.  Anything else the zip
machinery raises comes from the archive's own bytes (an undecodable
member name, offsets outside the file), so it marks the wheel unreadable
rather than the window short.
N)zipfileZipFile
BadZipFile	Exceptionr   )r   excs   & r#   	_try_openr    s?    -v&&  -#,-s    AAAAAc               0    V ^8  d   QhRRRRRRRRR	R
RR/# )r3   r   r   r   rB   r   r\   tail_lowr_   r   r   r4   r   r   )r6   s   "r#   r7   r7     sD      !	  	
 ' r"   c           	       "   VP                   p \        V4      pVe   V# WS,
          pWu8  d   R# \        V^,          V4      pWX,
          p	\        WRV	 RV^,
           24      G Rj  xL
 p
\	        WW4      pVf   R# TpKt   L5i)zDOpen a ZipFile over the sparse buffer, growing the window on demand.Nr   r   )rb   r  r   r   r   )r   r   r   r  r   r   openedhavenew_sizenew_lowr   r   s   &&&&&       r#   	_open_zipr
    s      NNE
6"M=tax'"#IfWIQxRS|n4UVVHgB;	 Ws   A&B(B)Bc               $    V ^8  d   QhRRRRRR/# )r3   zip_filezzipfile.ZipFilememberrB   r4   ztuple[int, int]r   )r6   s   "r#   r7   r7   
  s!      ? C O r"   c                    V P                  V4      P                  pV P                  4        Uu. uF!  q3P                  V8  g   K  VP                  NK#  	  ppV'       d   \        V4      MV P                  pW%3# u upi )a5  Return the ``[header_offset, next)`` byte span of ``member``.

``next`` is the smallest other entry offset greater than this one, or
the central-directory start when this entry is the last by offset. This
avoids parsing the local file header, whose extra-field length can
differ from the central directory's.
)getinfoheader_offsetinfolistr   	start_dir)r  r  rh   infolatersrt   s   &&    r#   _member_spanr  
  sw     V$22E'/'8'8':':t>P>PSX>X':    #f+X%7%7C<	s   A9A9c               4    V ^8  d   QhRRRRRRRRR	R
RRRR/# )r3   r   r   r   rB   r   r\   r  r_   canonical_namer   r   r   r4   r   r   )r6   s   "r#   r7   r7     sN     $ $!$	$ $ 	$
 #$ '$ $r"   c           	       "    \        WW#V4      G Rj  xL
 pVf   RM\        VP                  4       V4      pTe   Tf   R# \        Yg4      w  rTP                  Y4      '       g2   \        YRT RT	^,
           24      G Rj  xL
 p
\        YY4      f   R#  TP                  T4      #  L  \        \        3 d     R# i ; i L@  \         d     R# i ; i5i)a   Read the METADATA member out of the sparse buffer, or ``None``.

Only :class:`_RangeRefusedError`, :class:`WheelHashMismatchError`, and the
transport's errors travel out of the growth and member requests; every way
the zip machinery can choke on the fetched bytes reads back as ``None``.
Nr   r   )r
  r	   namelistr   r   r  rx   r   r   rv   r   )r   r   r   r  r  r   r  r  rh   rt   r   s   &&&&&&     r#   _read_sparser    s     "96ZPP  &x'8'8':NK 	 6>h/JEE''#IfUG1S1WI4NOO5=E}}V$$! Q "#89  P
   	sh   CB, B*$B, A
CCCC )C*B, ,C=C CCCCCCc               $    V ^8  d   QhRRRRRR/# )r3   r   rj   r   r   r4   r5   r   )r6   s   "r#   r7   r7   A  s"     * *E */E *$ *r"   c                    Vf   R# Vw  r#\         P                  ! W 4      P                  4       pWC8w  d   RV RV RV 2p\        V4      hR# )a  Raise :class:`WheelHashMismatchError` if a full body fails its published hash.

``wheel_hash`` is ``None`` when the listing published no accepted digest, so
no check runs. Only a full body can be verified this way; a partial read
holds just a slice of the wheel.
Nzwheel z mismatch: expected z, got )hashlibnew	hexdigestr   )r   r   algoexpectedactualr   s   &&    r#   r   r   A  sZ     ND[[$..0Ftf0
&I$S)) r"   c               $    V ^8  d   QhRRRRRR/# )r3   r   rj   r  r   r4   r   r   )r6   s   "r#   r7   r7   R  s!      %  L r"   c                     \         P                  ! \        P                  ! V 4      4      p\	        VP                  4       V4      pVf   R# VP                  V4      #   \         d     R# i ; i)zHRead the METADATA member out of a complete in-memory wheel, or ``None``.N)r   r   ioBytesIOr	   r  rv   r   )r   r  r  r  s   &&  r#   _read_full_bodyr'  R  s^    ??2::d#34&x'8'8':NK>}}V$$ 
 s   AA A A,+A,c                    V ^8  d   QhRRRR/# )r3   rawrj   r4   rB   r   )r6   s   "r#   r7   r7   b  s     9 9 93 9r"   c                n     V P                  R4      #   \         d   pRT 2p\        T4      ThRp?ii ; i)z9Decode METADATA bytes as UTF-8, raising on invalid input.zutf-8z(range-read METADATA is not valid UTF-8: N)decodeUnicodeDecodeErrorr   )r)  r  r   s   &  r#   _decoder-  b  s?    9zz'"" 98>*3/S89s    4/4r   r   c               4    V ^8  d   QhRRRRRRRRR	R
RRRR/# )r3   r   r   	wheel_urlrB   r  r   memor   r   r   r   r_   r4   r   r   )r6   s   "r#   r7   r7   k  sW     K6 K6!K6K6 #K6 	K6 'K6 K6 K6r"   c                 "   \        V4      P                  pRpVP                  V4      \        P                  J d   VP                  V4      G Rj  xL
 p VP                  V4      p\        WW4      G Rj  xL
 w  rpV	\        P                  Jd   VP                  Wi4       V'       d   VP                  V4       T
\        P                  J d   \        R\        P                  4      # T
\        P                  J d@   \        T\         4      '       g   Q h\#        Y4       \%        Y4      p\        P                  pMB\        T\&        4      '       g   Q hTw  r \)        YYY$4      G Rj  xL
 p\        P*                  pTf   \        R\        P0                  4      # \        \9        T4      T4      #  ELb EL?  T'       d   TP                  T4       i i ; i Ll  \,         d   p\/        Y4      G Rj  xL 
 pTf    \        R\        P0                  4      u Rp?# \#        TT4       TP2                  \4        8w  d!   TP                  T\        P6                  4       \%        TT4      p\        P                  p Rp?LRp?ii ; i5i)a   Recover a remote wheel's METADATA text by ranged reads of its ZIP.

``wheel_hash`` is the wheel's published ``(algorithm, hex_digest)`` from the
Simple-API listing, or ``None`` when none was published.  Whenever the whole
wheel comes back as one body, whether from a host that ignores or refuses
ranges or from a 200 volunteered while a partial read is growing its window,
the bytes are checked against ``wheel_hash`` before their METADATA is read,
so bytes that disagree with the published digest never drive the resolve.  A
ranged read is left unverified, even one whose window grew to cover the
whole file.

Raises :class:`~nab_index.client.WheelHashMismatchError` when a full-body
wheel fails ``wheel_hash``, and
:class:`~nab_index.client.MalformedSimpleResponseError` when the recovered
METADATA is not valid UTF-8.  Re-raises a transport error when the wheel URL
itself cannot be served (a 404, a failing plain GET).  A refused Range
mechanism is stepped down, not raised.  Every other failure to obtain
metadata returns a result with ``text=None``.
FN)r   rA   rF   r   r-   rS   r   rJ   rY   r   r   r   r   r   r   
isinstancerj   r   r'  tupler  r   r   r   r    r   r   r0   r-  )r   r/  r  r0  r   r   rA   
owns_proberF   new_capabilityr   payloadr)  r)   r   r  refusalr   s   &&&&$$            r#   read_wheel_metadata_over_ranger8  k  s    8 i ''FJv/"9"99++F33
&__V,
.6*/
 )
%g !8!88 KK/ f%x}}"4)A)ABBx!!!'5))))'.g6(('5))))"	-$f C #**G {"4)=)=>>ws|W55Y 4)
 f%  " 	- *)???D|*41E1EFFdJ/~~!<<FO$B$BC!$7C",,G	-s   AJF3J F9 7F68,F9 $B6JG +G,G  4J6F9 9GJG J%I>3G64"I>JJAI>9J>JJ)r   r   r   r   r8  )L__conditional_annotations__r   
__future__r   rP   rl   enumr  r%  r   rer   dataclassesr   typingr   urllib.parser   clientr   r   local_indexr   r	   r   r
   packaging.utilsr   r   r   __all___DEFAULT_TAILr   r   r   	frozensetr   compiler   Enumr   r   r   r   r\   r   r   rj   r3  r_   _AcqPayloadr   r   r   r*   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r
  r  r  r   r'  r-  r8  )r9  s   @r#   <module>rI     s  $ #     	 	 	  !   ! H E '.; ! 
 #C.I3#OP JJ;< 499  $d#  $ dii  *+) +)\Q Qh $d#  $tyy  eK,--4 MMD @  PI PCY'<F:K2"?&>4<-"2 $N*" 9K6 *.K6 #K6 K6r"   