o
    Vhft                     @  s  d Z ddlmZ ddlZddlZddlZddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ erddlm Z  ddlm!Z! ddl"m#Z# ddlm$Z$ ddl%m&Z& ddl'm(Z( ddl)m*Z* e+e,Z-G dd de.Z/G dd de/Z0G dd  d e/Z1G d!d" d"e/Z2G d#d$ d$e/Z3d6d,d-Z4G d.d/ d/Z5G d0d1 d1ee6 Z7G d2d3 d3e7Z8G d4d5 d5e8Z9dS )7zLazy ZIP over HTTP    )annotationsN)bisect_left)bisect_right)contextmanager)NamedTemporaryFile)IO)TYPE_CHECKING)Any)ClassVar)urlparse)
BadZipFile)ZipFile)parse_email)CONTENT_CHUNK_SIZE)	HTTPError)Response)codes)Iterable)Iterator)TracebackType)RawMetadata)Session)Self)Authenticatorc                   @     e Zd ZdZdS )LazyWheelUnsupportedErrorz(Raised when a lazy wheel is unsupported.N__name__
__module____qualname____doc__ r!   r!   p/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/poetry/inspection/lazy_wheel.pyr   +       r   c                   @  r   ) HTTPRangeRequestUnsupportedErrorzDRaised when the remote server appears unable to support byte ranges.Nr   r!   r!   r!   r"   r$   /   r#   r$   c                   @  r   )!HTTPRangeRequestNotRespectedErrorzrRaised when the remote server tells us that it supports byte ranges
    but does not respect a respective request.Nr   r!   r!   r!   r"   r%   3   r#   r%   c                   @  r   )UnsupportedWheelErrorzUnsupported wheel.Nr   r!   r!   r!   r"   r&   8   r#   r&   c                   @  s$   e Zd ZdZdddZdd	d
ZdS )InvalidWheelErrorzInvalid (e.g. corrupt) wheel.locationstrnamereturnNonec                 C  s   || _ || _d S N)r(   r*   )selfr(   r*   r!   r!   r"   __init__?   s   
zInvalidWheelError.__init__c                 C  s   d| j  d| j dS )NzWheel z located at z is invalid.)r*   r(   r.   r!   r!   r"   __str__C   s   zInvalidWheelError.__str__N)r(   r)   r*   r)   r+   r,   r+   r)   )r   r   r   r    r/   r1   r!   r!   r!   r"   r'   <   s    
r'   r*   r)   urlsessionSession | Authenticatorr+   r   c              
   C  s   z#t ||}|| }W d   n1 sw   Y  t|\}}|W S  ttfy1   t||  ty[ } zt|tr?|t	
dt|j| || td|  d| d|d}~ww )ai  Fetch metadata from the given wheel URL.

    This uses HTTP range requests to only fetch the portion of the wheel
    containing metadata, just enough for the object to be constructed.

    :raises HTTPRangeRequestUnsupportedError: if range requests are unsupported for ``url``.
    :raises InvalidWheelError: if the zip file contents could not be parsed.
    NzYThere was an unexpected %s when handling lazy wheel metadata retrieval for %s from %s: %sz2Attempts to use lazy wheel metadata retrieval for z from z failed)LazyWheelOverHTTPread_metadatar   r   r&   r'   	Exception
isinstancer   loggerdebugtyper   )r*   r3   r4   	lazy_filemetadata_bytesmetadata_er!   r!   r"   metadata_from_wheel_urlG   s2   


rB   c                   @  s@   e Zd ZdZddddd	d
ZdddZdddZdddZdS )MergeIntervalsz.Stateful bookkeeping to merge interval graphs.r!   )leftrightrD   Iterable[int]rE   r+   r,   c                C  s   t || _t || _d S r-   )list_left_right)r.   rD   rE   r!   r!   r"   r/   w   s   
zMergeIntervals.__init__r)   c                 C  s(   t | j dt| j dt| j dS )Nz(left=z, right=))r<   r   tuplerH   rI   r0   r!   r!   r"   __repr__{   s   zMergeIntervals.__repr__startintendIterator[tuple[int, int]]c           
      c  s    | j || | j|| }}t|g|dd   }}t|g|dd  }t||D ]\}}	||kr<||d fV  |	d }q-||krJ||fV  |g|g| j ||< | j||< dS )a  Return an iterator of intervals to be fetched.

        Args:
            start: Start of needed interval
            end: End of needed interval
            left: Index of first overlapping downloaded data
            right: Index after last overlapping downloaded data
        N   )rH   rI   minmaxzip)
r.   rM   rO   rD   rE   lslicersliceijkr!   r!   r"   _merge   s   

&zMergeIntervals._mergec                 c  s4    t | j|}t| j|}| ||||E dH  dS )a^  Provide the intervals needed to cover from ``start <= x <= end``.

        This method mutates internal state so that later calls only return intervals not
        covered by prior calls. The first call to this method will always return exactly
        one interval, which was exactly the one requested. Later requests for
        intervals overlapping that first requested interval will yield only the ranges
        not previously covered (which may be empty, e.g. if the same interval is
        requested twice).

        This may be used e.g. to download substrings of remote files on demand.
        N)r   rI   r   rH   r[   )r.   rM   rO   rD   rE   r!   r!   r"   minimal_intervals_covering   s   z)MergeIntervals.minimal_intervals_coveringN)rD   rF   rE   rF   r+   r,   r2   )
rM   rN   rO   rN   rD   rN   rE   rN   r+   rP   )rM   rN   rO   rN   r+   rP   )r   r   r   r    r/   rL   r[   r\   r!   r!   r!   r"   rC   t   s    

rC   c                   @  s  e Zd ZdZdNddZdOd	d
ZdPddZdQddZdRddZe	dSddZ
e	dSddZdTdd ZdUd!d"Ze	dTd#d$ZdVd&d'ZdUd(d)ZdTd*d+ZdTd,d-ZdWdXd0d1ZdWdYd3d4ZdWdZd7d8Zd[d\d<d=ZdVd>d?Zd]d^dBdCZdTdDdEZd_dHdIZd`dLdMZd@S )aReadOnlyIOWrapperzImplement read-side ``IO[bytes]`` methods wrapping an inner ``IO[bytes]``.

    This wrapper is useful because Python currently does not distinguish read-only
    streams at the type level.
    inner	IO[bytes]r+   r,   c                 C  s
   || _ d S r-   )_file)r.   r^   r!   r!   r"   r/         
zReadOnlyIOWrapper.__init__r   c                 C  s   | j   | S r-   )r`   	__enter__r0   r!   r!   r"   rb      s   
zReadOnlyIOWrapper.__enter__exc_typetype[BaseException] | None	exc_valueBaseException | None	tracebackTracebackType | Nonec                 C  s   | j ||| d S r-   )r`   __exit__r.   rc   re   rg   r!   r!   r"   ri      s   zReadOnlyIOWrapper.__exit__Iterator[bytes]c                 C     t r-   NotImplementedErrorr0   r!   r!   r"   __iter__      zReadOnlyIOWrapper.__iter__bytesc                 C  rl   r-   rm   r0   r!   r!   r"   __next__   rp   zReadOnlyIOWrapper.__next__r)   c                 C     dS )z!Opening mode, which is always rb.rbr!   r0   r!   r!   r"   mode   s   zReadOnlyIOWrapper.modec                 C     | j jS )zPath to the underlying file.)r`   r*   r0   r!   r!   r"   r*         zReadOnlyIOWrapper.nameboolc                 C  rs   )z9Return whether random access is supported, which is True.Tr!   r0   r!   r!   r"   seekable      zReadOnlyIOWrapper.seekablec                 C  s   | j   dS )zClose the file.N)r`   closer0   r!   r!   r"   r{      s   zReadOnlyIOWrapper.closec                 C  rv   )zWhether the file is closed.)r`   closedr0   r!   r!   r"   r|      rw   zReadOnlyIOWrapper.closedrN   c                 C  
   | j  S r-   )r`   filenor0   r!   r!   r"   r~      ra   zReadOnlyIOWrapper.filenoc                 C  s   | j   d S r-   )r`   flushr0   r!   r!   r"   r      s   zReadOnlyIOWrapper.flushc                 C  rs   )NFr!   r0   r!   r!   r"   isatty   rp   zReadOnlyIOWrapper.isattyc                 C  rs   )z3Return whether the file is readable, which is True.Tr!   r0   r!   r!   r"   readable   rz   zReadOnlyIOWrapper.readablerR   sizec                 C     | j |S )zRead up to size bytes from the object and return them.

        As a convenience, if size is unspecified or -1,
        all bytes until EOF are returned.  Fewer than
        size bytes may be returned if EOF is reached.
        )r`   readr.   r   r!   r!   r"   r      s   zReadOnlyIOWrapper.readlimitc                 C  rl   r-   rm   )r.   r   r!   r!   r"   readline   rz   zReadOnlyIOWrapper.readlinehintlist[bytes]c                 C  rl   r-   rm   )r.   r   r!   r!   r"   	readlines   rp   zReadOnlyIOWrapper.readlinesr   offsetwhencec                 C  s   | j ||S )a-  Change stream position and return the new absolute position.

        Seek to offset relative position indicated by whence:
        * 0: Start of stream (the default).  pos should be >= 0;
        * 1: Current position - pos may be negative;
        * 2: End of stream - pos usually negative.
        )r`   seek)r.   r   r   r!   r!   r"   r      s   zReadOnlyIOWrapper.seekc                 C  r}   )zReturn the current position.)r`   tellr0   r!   r!   r"   r     s   
zReadOnlyIOWrapper.tellN
int | Nonec                 C  r   )zResize the stream to the given size in bytes.

        If size is unspecified resize to the current position.
        The current stream position isn't changed.

        Return the new file size.
        )r`   truncater   r!   r!   r"   r     s   zReadOnlyIOWrapper.truncatec                 C  rs   )zReturn False.Fr!   r0   r!   r!   r"   writable  rz   zReadOnlyIOWrapper.writablesr	   c                 C  rl   r-   rm   )r.   r   r!   r!   r"   write  rp   zReadOnlyIOWrapper.writelinesIterable[Any]c                 C  rl   r-   rm   )r.   r   r!   r!   r"   
writelines  rp   zReadOnlyIOWrapper.writelines)r^   r_   r+   r,   r+   r   rc   rd   re   rf   rg   rh   r+   r,   )r+   rk   )r+   rq   r2   )r+   rx   r+   r,   r+   rN   rR   r   rN   r+   rq   )r   rN   r+   rq   )r   rN   r+   r   )r   )r   rN   r   rN   r+   rN   r-   )r   r   r+   rN   )r   r	   r+   rN   )r   r   r+   r,   )r   r   r   r    r/   rb   ri   ro   rr   propertyru   r*   ry   r{   r|   r~   r   r   r   r   r   r   r   r   r   r   r   r   r!   r!   r!   r"   r]      s8    










	




r]   c                      s   e Zd ZdZ	d6d7 fddZd8 fddZd9 fddZd:d; fddZed<dd Z	d=d!d"Z
d=d#d$Zd>d%d&Zd>d'd(Zd?d,d-Zd@d/d0ZedAd2d3ZdBd4d5Z  ZS )CLazyFileOverHTTPa  File-like object representing a fixed-length file over HTTP.

    This uses HTTP range requests to lazily fetch the file's content into a temporary
    file. If such requests are not supported by the server, raises
    ``HTTPRangeRequestUnsupportedError`` in the ``__enter__`` method.Tr3   r)   r4   r5   delete_backing_filerx   r+   r,   c                   s8   t |d}t | d | _d | _d| _|| _|| _d S )N)deleter   )r   superr/   _merge_intervals_length_request_count_session_url)r.   r3   r4   r   r^   	__class__r!   r"   r/   $  s   

zLazyFileOverHTTP.__init__r   c                   s   t    |   | S r-   )r   rb   _setup_contentr0   r   r!   r"   rb   4  s   
zLazyFileOverHTTP.__enter__rc   rd   re   rf   rg   rh   c                   s   |    t ||| d S r-   )_reset_contentr   ri   rj   r   r!   r"   ri   9  s   zLazyFileOverHTTP.__exit__rR   r   rN   rq   c                   s   | j du r	td|  }td||| j |dk r'|| j ks!J | j | }n|dkr-dS |}t|| | j }| || t 	|S )a-  Read up to size bytes from the object and return them.

        As a convenience, if size is unspecified or -1,
        all bytes until EOF are returned.  Fewer than
        size bytes may be returned if EOF is reached.

        :raises ValueError: if ``__enter__`` was not called beforehand.
        Nz4.__enter__() must be called to set up content lengthz$read size %d at %d from lazy file %sr       )
r   
ValueErrorr   r:   r;   r*   rS   _ensure_downloadedr   r   )r.   r   curdownload_sizestopr   r!   r"   r   B  s   
	zLazyFileOverHTTP.readdict[str, str]c                 C  s
   dddS )a  HTTP headers to bypass any HTTP caching.

        The requests we perform in this file are intentionally small, and any caching
        should be done at a higher level.

        Further, caching partial requests might cause issues:
        https://github.com/pypa/pip/pull/8716
        identityzno-cache)zAccept-EncodingzCache-Controlr!   clsr!   r!   r"   _uncached_headersZ  s   
z"LazyFileOverHTTP._uncached_headersc                 C  s`   | j du r	t | _ | jdu r'td |  | _td| j | | j dS td| j dS )a!  Initialize the internal length field and other bookkeeping.

        Ensure ``self._merge_intervals`` is initialized.

        After parsing the remote file length with ``self._fetch_content_length()``,
        this method will truncate the underlying file from parent abstract class
        ``ReadOnlyIOWrapper`` to that size in order to support seek operations against
        ``io.SEEK_END`` in ``self.read()``.

        Called in ``__enter__``, and should make recursive invocations into a no-op.
        Subclasses may override this method.Nzbegin fetching content lengthz%done fetching content length (is: %d)z'content length already fetched (is: %d))r   rC   r   r:   r;   _fetch_content_lengthr   r0   r!   r!   r"   r   i  s   



zLazyFileOverHTTP._setup_contentc                 C  sH   | j durtdt| j  d| _ | jdur"td| j d| _dS dS )zUnset the internal length field and merge intervals.

        Called in ``__exit__``, and should make recursive invocations into a no-op.
        Subclasses may override this method.Nz$unsetting merge intervals (were: %s)z"unsetting content length (was: %d))r   r:   r;   reprr   r0   r!   r!   r"   r     s   



zLazyFileOverHTTP._reset_contentc                 C  sr   |  j d7  _ | jj| j|  dd}|  |jtjksJ |j	
dd}|dkr2td| dt|j	d	 S )
zPerforms a HEAD request to extract the Content-Length.

        :raises HTTPRangeRequestUnsupportedError: if the response fails to indicate support
                                             for "bytes" ranges.rQ   T)headersallow_redirectsAccept-RangesNrq   z1server does not support byte ranges: header was ''Content-Length)r   r   headr   r   raise_for_statusstatus_coder   okr   getr$   rN   )r.   r   accepted_ranger!   r!   r"   _content_length_from_head  s   
z*LazyFileOverHTTP._content_length_from_headc                 C  s   |   S )zGet the remote file's length.)r   r0   r!   r!   r"   r     s   z&LazyFileOverHTTP._fetch_content_lengthrM   rO   r   c                 C  s   |   }d| d| |d< td|d  |  jd7  _| jj| j|dd}z&|  t|j	d || d krKt
d	|| d  d
|j	d  d|W S  tyY   |   w )zDReturn streaming HTTP response to a range request from start to end.zbytes=-Rangezstreamed bytes request: %srQ   Tr   streamr   z5server did not respect byte range request: requested z bytes, got z bytes)r   r:   r;   r   r   r   r   r   rN   r   r%   BaseExceptionr{   )r.   rM   rO   r   responser!   r!   r"   _stream_response  s(   
z!LazyFileOverHTTP._stream_responserk   c                 c  sD    |  ||}|tE dH  W d   dS 1 sw   Y  dS )a7  Perform a series of HTTP range requests to cover the specified byte range.

        NB: For compatibility with HTTP range requests, the range provided to this
        method must *include* the byte indexed at argument ``end`` (so e.g. ``0-1`` is 2
        bytes long, and the range can never be empty).
        N)r   iter_contentr   )r.   rM   rO   r   r!   r!   r"   _fetch_content_range  s   "z%LazyFileOverHTTP._fetch_content_rangeIterator[None]c              	   c  s.    |   }zdV  W | | dS | | w )zyReturn a context manager keeping the position.

        At the end of the block, seek back to original position.
        N)r   r   )r.   posr!   r!   r"   _stay  s
   zLazyFileOverHTTP._stayc                 C  s   | j du r	td|d8 }|  ) | j ||D ]\}}| | | ||D ]}| j| q(qW d   dS 1 s=w   Y  dS )zEnsures bytes start to end (inclusive) have been downloaded and written to
        the backing file.

        :raises ValueError: if ``__enter__`` was not called beforehand.
        Nz5.__enter__() must be called to set up merge intervalsrQ   )r   r   r   r\   r   r   r`   r   )r.   rM   rO   range_start	range_endchunkr!   r!   r"   r     s   


"z#LazyFileOverHTTP._ensure_downloaded)T)r3   r)   r4   r5   r   rx   r+   r,   r   r   r   r   )r+   r   r   r   )rM   rN   rO   rN   r+   r   )rM   rN   rO   rN   r+   rk   )r+   r   )rM   rN   rO   rN   r+   r,   )r   r   r   r    r/   rb   ri   r   classmethodr   r   r   r   r   r   r   r   r   r   __classcell__r!   r!   r   r"   r     s$    
	






r   c                   @  sx   e Zd ZU dZe Zded< edZ	dd	d
Z
edddZdddZedddZd ddZd!ddZd"ddZdS )#r6   zFile-like object mapped to a ZIP file over HTTP.

    This uses HTTP range requests to lazily fetch the file's content, which should be
    provided as the first argument to a ``ZipFile``.
    zClassVar[set[str]]_domains_without_negative_rangez^[^/]*\.dist-info/METADATA$r*   r)   r+   rq   c                 C  s@   t | }| |}||W  d   S 1 sw   Y  dS )z:Download and read the METADATA file from the remote wheel.N)r   _prefetch_metadatar   )r.   r*   zffilenamer!   r!   r"   r7     s   

$zLazyWheelOverHTTP.read_metadatarN   c                 C  rs   )a<  Return the size of the chunk (in bytes) to download from the end of the file.

        This method is called in ``self._fetch_content_length()``. As noted in that
        method's docstring, this should be set high enough to cover the central
        directory sizes of the *average* wheels you expect to see, in order to avoid
        further requests before being able to process the zip file's contents at all.
        If we choose a small number, we need one more range request for larger wheels.
        If we choose a big number, we download unnecessary data from smaller wheels.
        If the chunk size from this method is larger than the size of an entire wheel,
        that may raise an HTTP error, but this is gracefully handled in
        ``self._fetch_content_length()`` with a small performance penalty.
        i'  r!   r   r!   r!   r"   _initial_chunk_length  s   z'LazyWheelOverHTTP._initial_chunk_lengthc           	   	   C  s2  |   }| |\}}| | |du r#td|| }| || |S |  h |M t|jd }|t||ks;J | 	| t
j |tD ]}| j| qH|| }|d }| jdus`J ||fft| j||kspJ W d   n1 szw   Y  W d   |S W d   |S 1 sw   Y  |S )a  Get the total remote file length, but also download a chunk from the end.

        This method is called within ``__enter__``. In an attempt to reduce
        the total number of requests needed to populate this lazy file's contents, this
        method will also attempt to fetch a chunk of the file's actual content. This
        chunk will be ``self._initial_chunk_length()`` bytes in size, or just the remote
        file's length if that's smaller, and the chunk will come from the *end* of
        the file.

        This method will first attempt to download with a negative byte range request,
        i.e. a GET with the headers ``Range: bytes=-N`` for ``N`` equal to
        ``self._initial_chunk_length()``. If negative offsets are unsupported, it will
        instead fall back to making a HEAD request first to extract the length, followed
        by a GET request with the double-ended range header ``Range: bytes=X-Y`` to
        extract the final ``N`` bytes from the remote resource.
        Nr   r   rQ   )r   _extract_content_lengthr   rT   r   r   rN   r   rS   r   ioSEEK_ENDr   r   r`   r   r   rK   r\   )	r.   initial_chunk_size
ret_lengthtailinitial_startresponse_lengthr   init_chunk_startinit_chunk_endr!   r!   r"   r     s6   

(z'LazyWheelOverHTTP._fetch_content_lengthargc                 C  s2   t d| }|du rtd|  dt|dS )zParse the file's full underlying length from the Content-Range header.

        This supports both * and numeric ranges, from success or error responses:
        https://www.rfc-editor.org/rfc/rfc9110#field.content-range.
        zbytes [^/]+/([0-9]+)Nz could not parse Content-Range: 'r   rQ   )rematchr$   rN   group)r   mr!   r!   r"   %_parse_full_length_from_content_rangeH  s   
z7LazyWheelOverHTTP._parse_full_length_from_content_ranger   tuple[int, Response]c                 C  s   |   }d| |d< td|d  |  jd7  _| jj| j|dd}zN|  |j}|t	j
krX|t	jkrQ|jdd}t|jd	 }|d
krQ||krQ||fW S td| d|jvrftd| j d| |jd }||fW S  ty~   |   w )zIAttempt to fetch a chunk from the end of the file with a negative offset.zbytes=-r   zinitial bytes request: %srQ   Tr   r   Nr   rq   z*did not receive partial content: got code Content-Rangez%file length cannot be determined for z2, did not receive content range header from server)r   r:   r;   r   r   r   r   r   r   r   partial_contentr   r   rN   r$   r   r   r   r{   )r.   r   r   r   codeaccept_rangescontent_lengthfile_lengthr!   r!   r"   _try_initial_chunk_requestV  s<   




z,LazyWheelOverHTTP._try_initial_chunk_requesttuple[int, Response | None]c              
   C  s  t | jj}|| jv r|  dfS z	| |\}}W nQ tyk } zE|j}|dur,|jnd}|t	j
krN|durNd|jv rN| |jd }|dfW  Y d}~S td|| | j| |  dfW  Y d}~S d}~ww t|jd |ks|jdddr|  d}| j| ||fS )zFGet the Content-Length of the remote file, and possibly a chunk of it.Nr   znNegative byte range not supported for domain '%s': using HEAD request before lazy wheel from now on (code: %s)r    zbytes -)r   r   netlocr   r   r   r   r   r   r   requested_range_not_satisfiabler   r   r:   r;   addrN   r   
startswithr{   )r.   r   domainr   r   rA   respr   r!   r!   r"   r     sB   


%z)LazyWheelOverHTTP._extract_content_lengthc                 C  s   t d| d}d}t| }d}| D ]!}|du r)| j|jr(|j}|j}qq| j|js5|j} nq|du rItd| jd| d| j	 |du rP|j
}t d|  | || t d| |S )	aO  Locate the *.dist-info/METADATA entry from a temporary ``ZipFile`` wrapper,
        and download it.

        This method assumes that the *.dist-info directory (containing e.g. METADATA) is
        contained in a single contiguous section of the zip file in order to ensure it
        can be downloaded in a single ranged GET request.z!begin prefetching METADATA for %sNr   zno z found for z in zfetch z done prefetching METADATA for %s)r:   r;   r   infolist_metadata_regexsearchr   header_offsetr&   r*   	start_dirr   )r.   r*   rM   rO   r   r   infor!   r!   r"   r     s4   z$LazyWheelOverHTTP._prefetch_metadataN)r*   r)   r+   rq   r   )r   r)   r+   rN   )r   rN   r+   r   )r   rN   r+   r   )r*   r)   r+   r)   )r   r   r   r    setr   __annotations__r   compiler   r7   r   r   r   staticmethodr   r   r   r   r!   r!   r!   r"   r6     s   
 


<

19r6   )r*   r)   r3   r)   r4   r5   r+   r   ):r    
__future__r   r   loggingr   bisectr   r   
contextlibr   tempfiler   typingr   r   r	   r
   urllib.parser   zipfiler   r   packaging.metadatar   requests.modelsr   r   r   requests.status_codesr   collections.abcr   r   typesr   r   requestsr   typing_extensionsr   poetry.utils.authenticatorr   	getLoggerr   r:   r8   r   r$   r%   r&   r'   rB   rC   rq   r]   r   r6   r!   r!   r!   r"   <module>   sR    

-6s L