Ë
    Ìi("  ã                   óø   — d Z ddlZddlZddlmZ ddlmZ ddlmZm	Z	m
Z
mZ ddlmZ ddlmZ ddlmZ dd	lmZmZ  e«       Zd
„ Z G d„ d«      Z G d„ de«      Zd„ Zd„ Zdd„Zd„ Zd„ Zdd„Zd„ Z dd„Z!dd„Zy)zS
This module contains a collection of utility classes and functions used in
agate.
é    N)ÚOrderedDict)ÚSequence)ÚROUND_CEILINGÚROUND_FLOORÚDecimalÚ
getcontext©Úwraps)Úslugify)Úconfig)Úwarn_duplicate_columnÚwarn_unnamed_columnc                 ó6   ‡ ‡— dŠt        ‰ «      ˆ ˆfd„«       }|S )zŸ
    Dead-simple memoize decorator for instance methods that take no arguments.

    This is especially useful since so many of our classes are immutable.
    Nc                 ó   •— ‰�‰S  ‰| «      S ©N© )ÚselfÚfuncÚmemos    €€úL/var/www/html/strategist-ai/venv/lib/python3.12/site-packages/agate/utils.pyÚwrapperzmemoize.<locals>.wrapper   s   ø€ àÐØˆKá�D‹zÐó    r	   )r   r   r   s   ` @r   Úmemoizer      s'   ù€ ð €Dä
ˆ4ƒ[ôó ðð €Nr   c                   ó   — e Zd ZdZd„ Zd„ Zy)Ú	NullOrderzr
    Dummy object used for sorting in place of None.

    Sorts as "greater than everything but other nulls."
    c                  ó   — y)NFr   ©r   Úothers     r   Ú__lt__zNullOrder.__lt__.   s   € Ør   c                 ó
   — |€yy)NFTr   r   s     r   Ú__gt__zNullOrder.__gt__1   s   € Øˆ=Øàr   N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r!   r   r   r   r   r   (   s   „ ñò
ór   r   c                   ó:   — e Zd ZdZd„ Zd„ Zd„ Zd„ Zd„ Zd„ Z	d„ Z
y	)
Ú	Quantileszn
    A class representing quantiles (percentiles, quartiles, etc.) for a given
    column of Number data.
    c                 ó   — || _         y r   ©Ú
_quantiles)r   Ú	quantiless     r   Ú__init__zQuantiles.__init__=   s	   € Ø#ˆ�r   c                 ó8   — | j                   j                  |«      S r   )r*   Ú__getitem__)r   Úis     r   r.   zQuantiles.__getitem__@   s   € Ø�‰×*Ñ*¨1Ó-Ð-r   c                 ó6   — | j                   j                  «       S r   )r*   Ú__iter__©r   s    r   r1   zQuantiles.__iter__C   s   € Ø�‰×'Ñ'Ó)Ð)r   c                 ó6   — | j                   j                  «       S r   )r*   Ú__len__r2   s    r   r4   zQuantiles.__len__F   s   € Ø�‰×&Ñ&Ó(Ð(r   c                 ó,   — t        | j                  «      S r   )Úreprr*   r2   s    r   Ú__repr__zQuantiles.__repr__I   s   € Ü�D—O‘OÓ$Ð$r   c                 ó4   — | j                   |j                   k(  S r   r)   r   s     r   Ú__eq__zQuantiles.__eq__L   s   € Ø�‰ %×"2Ñ"2Ñ2Ð2r   c                 óV  — d}|| j                   d   k  rt        d«      ‚|| j                   d   kD  rt        d«      ‚|| j                   d   k(  r!t        t        | j                   «      dz
  «      S || j                   |dz      k\  r|dz  }|| j                   |dz      k\  rŒt        |«      S )zC
        Identify which quantile a given value is part of.
        r   z*Value is less than minimum quantile value.éÿÿÿÿz-Value is greater than maximum quantile value.é   )r*   Ú
ValueErrorr   Úlen)r   Úvaluer/   s      r   ÚlocatezQuantiles.locateO   s®   € ð ˆà�4—?‘? 1Ñ%Ò%ÜÐIÓJÐJà�4—?‘? 2Ñ&Ò&ÜÐLÓMÐMà�D—O‘O BÑ'Ò'Üœ3˜tŸ™Ó/°!Ñ3Ó4Ð4à�t—‘ q¨1¡uÑ-Ò-Ø�‰FˆAð �t—‘ q¨1¡uÑ-Ó-ô �q‹zÐr   N)r"   r#   r$   r%   r,   r.   r1   r4   r7   r9   r@   r   r   r   r'   r'   8   s*   „ ñò$ò.ò*ò)ò%ò3ór   r'   c                 óx   — t        | «      }|dz  dk(  r| |dz   dz  dz
     S |dz  }| |dz
     }| |   }||z   dz  S )z�
    Finds the median value of a given series of values.

    :param data_sorted:
        The values to find the median of. Must be sorted.
    é   r<   )r>   )Údata_sortedÚlengthÚhalfÚaÚbs        r   ÚmedianrH   d   sa   € ô �Ó€Fà��z�Q‚Ø˜V a™Z¨AÑ-°Ñ2Ñ3Ð3à�Q‰;€DØ�D˜1‘HÑ€AØ�DÑ€Aà�‰E�Q‰;Ðr   c                 ó@  — d}d}t        «       j                  }| D ]s  }|�*t        j                  |«      st        j                  |«      rŒ0|j                  «       j                  «       \  }}}|dz  }t        |«      |z
  }	|	|kD  r|	}||kD  sŒr|}Œu ||z   |kD  r||z
  }|S )z¸
    Given a series of values (such as a :class:`.Column`) returns the most
    significant decimal places present in any value.

    :param values:
        The values to analyze.
    r<   r   r;   )r   ÚprecÚmathÚisnanÚisinfÚ	normalizeÚas_tupler>   )
ÚvaluesÚmax_whole_placesÚmax_decimal_placesÚ	precisionr?   ÚsignÚdigitsÚexponentÚexponent_placesÚwhole_placess
             r   Úmax_precisionrY   w   s½   € ð ÐØÐÜ“×!Ñ!€Iàò 1ˆØˆ=œDŸJ™J uÔ-´·±¸EÔ1BØà!&§¡Ó!2×!;Ñ!;Ó!=Ñˆˆf�hà" R™-ˆÜ˜6“{ _Ñ4ˆàÐ*Ò*Ø+ÐàÐ/Ó/Ø!0Ñð1ð" Ð,Ñ,¨yÒ8Ø&Ð)9Ñ9ÐàÐr   c                 ól   — d| z  }|rt        j                  d«      nd}dj                  d||d||g«      S )a  
    Given a number of decimal places creates a formatting string that will
    display numbers with that precision.

    :param decimal_places:
        The number of decimal places
    :param add_ellipsis:
        Optionally add an ellipsis symbol at the end of a number
    Ú0Únumber_truncation_charsÚ z#,##0.z;-#,##0.)r   Ú
get_optionÚjoin)Údecimal_placesÚadd_ellipsisÚfractionÚellipsiss       r   Úmake_number_formatterrd   š   s@   € ð �^Ñ#€HÙ?KŒv× Ñ Ð!:Ô;ÐQS€HØ�7‰7�H˜h¨°*¸hÈÐQÓRÐRr   c                 ó¬  — | j                  «       j                  «       }|j                  «       j                  «       }t        t        |j                  «      |j
                  z   t        |j                  «      |j
                  z   «      }|dkD  rMt        d«      |dz
  z  }| |z  j                  t        ¬«      }||z  j                  t        ¬«      }||z  ||z  fS t        |j
                  |j
                  «      }t        d«      |dz   z  }	| j                  |	t        ¬«      j                  «       |j                  |	t        ¬«      j                  «       fS )aD  
    Rounds a pair of minimum and maximum values to form reasonable "round"
    values suitable for use as axis minimum and maximum values.

    Values are rounded "out": up for maximum and down for minimum, and "off":
    to one higher than the first significant digit shared by both.

    See unit tests for examples.
    r   Ú10r<   )Úrounding)rN   rO   Úmaxr>   rU   rV   r   Úto_integral_valuer   r   Úquantize)
ÚminimumÚmaximumÚmin_bitsÚmax_bitsÚ
max_digitsÚ
multiplierÚmin_fractionÚmax_fractionÚmax_exponentÚqs
             r   Úround_limitsru   ©   sD  € ð × Ñ Ó"×+Ñ+Ó-€HØ× Ñ Ó"×+Ñ+Ó-€HäÜˆH�O‰OÓ˜x×0Ñ0Ñ0ÜˆH�O‰OÓ˜x×0Ñ0Ñ0ó€Jð �A‚~Ü˜T“] z°A¡~Ñ6ˆ
à *Ñ,×?Ñ?ÌÐ?ÓUˆØ *Ñ,×?Ñ?ÌÐ?ÓWˆð ˜:Ñ%Ø˜:Ñ%ð
ð 	
ô
 �x×(Ñ(¨(×*;Ñ*;Ó<€Lô 	�‹˜,¨Ñ*Ñ+€Að 	×Ñ˜¤[ÐÓ1×;Ñ;Ó=Ø×Ñ˜¤]ÐÓ3×=Ñ=Ó?ðð r   c                 óZ   — t         j                  }t        |«      }|| |z     | |z  dz   z  S )z©
    Given a column index, assign a "letter" column name equivalent to
    Excel. For example, index ``4`` would return ``E``.
    Index ``30`` would return ``EE``.
    r<   )ÚstringÚascii_lowercaser>   )ÚindexÚlettersÚcounts      r   Úletter_namer|   Ò   s5   € ô ×$Ñ$€GÜ�‹L€Eà�5˜5‘=Ñ! e¨u¡n¸Ñ%9Ñ:Ð:r   c                 ó2  — t        | t        «      r| j                  «       }n5t        | t        t        f«      rt        | «      }n|j                  d«      | iS t        «       }|D ]1  \  }}t        |«      }|j                  t        |||z   dz   «      «       Œ3 |S )z¤
    Recursively parse JSON-like Python objects as a dictionary of paths/keys
    and values.

    Inspired by JSONPipe (https://github.com/dvxhouse/jsonpipe).
    ú/)Ú
isinstanceÚdictÚitemsÚlistÚtupleÚ	enumerateÚstripr   ÚstrÚupdateÚparse_object)ÚobjÚpathÚiteratorÚdÚkeyr?   s         r   rˆ   rˆ   Þ   s‰   € ô �#”tÔØ—9‘9“;‰Ü	�Cœ$¤˜Ô	'Ü˜S“>‰à—
‘
˜3“ Ð%Ð%ä‹€Aàò 8‰
ˆˆUÜ�#‹hˆØ	�‰”˜e T¨C¡Z°#Ñ%5Ó6Õ7ð8ð €Hr   c                 óH   — t        | t        «      xr t        | t        «       S )zv
    Returns :code:`True` if the given object is an instance of
    :class:`.Sequence` that is not also a string.
    )r   r   r†   )r‰   s    r   Ú
issequencer�   õ   s    € ô
 �cœ8Ó$ÒA¬Z¸¼SÓ-AÐ)AÐAr   c                 óN  — g }t        | «      D ]‹  \  }}|r8|st        |«      }t        ||«       n t        |t        «      r|}nt        d«      ‚|}|}d}||v r||z   t	        |dz   «      z   }|dz  }||v rŒ|r|dkD  rt        ||«       |j                  |«       Œ� t        |«      S )aÍ  
    Append a unique identifer to duplicate strings in a given sequence of
    strings. Identifers are an underscore followed by the occurance number of
    the specific string.

    ['abc', 'abc', 'cde', 'abc'] -> ['abc', 'abc_2', 'cde', 'abc_3']

    :param column_names:
        If True, values are treated as column names. Warnings will be thrown
        if column names are None or duplicates. None values will be replaced with
        letter indices.
    z%Column names must be strings or None.r   rB   r<   )	r„   r|   r   r   r†   r=   r   Úappendrƒ   )	rP   Úcolumn_namesÚ	separatorÚfinal_valuesr/   r?   Ú	new_valueÚfinal_valueÚ
duplicatess	            r   Údeduplicater˜   ý   sÇ   € ð €Lä˜fÓ%ò )‰ˆˆ5ÙÙÜ'¨›N�	Ü# A yÕ1Ü˜E¤3Ô'Ø!‘	ä Ð!HÓIÐIàˆIàˆØˆ
à˜\Ñ)Ø# iÑ/´#°jÀ1±nÓ2EÑEˆKØ˜!‰OˆJð ˜\Ò)ñ ˜J¨šNÜ! )¨[Ô9à×Ñ˜KÕ(ð-)ô0 �ÓÐr   c                 ó¢   ‡— ddiŠ‰j                  |«       |r$t        ˆfd„| D «       «      }t        |‰d   ¬«      S t        ˆfd„| D «       «      S )a”  
    Given a sequence of strings, returns a standardized version of the sequence.
    If ``ensure_unique`` is True, any duplicate strings will be appended with
    a unique identifier.

    agate uses an underscore as a default separator but this can be changed with
    kwargs.

    Any kwargs will be passed to the slugify method in python-slugify. See:
    https://github.com/un33k/python-slugify
    r“   Ú_c              3   ó6   •K  — | ]  }t        |fi ‰¤Ž–— Œ y ­wr   ©Úpslugify©Ú.0r?   Ú	slug_argss     €r   ú	<genexpr>zslugify.<locals>.<genexpr>7  s   øè ø€ ÒL¸Eœ8 EÑ7¨YÕ7ÑLùó   ƒ)r“   c              3   ó6   •K  — | ]  }t        |fi ‰¤Ž–— Œ y ­wr   rœ   rž   s     €r   r¡   zslugify.<locals>.<genexpr>:  s   øè ø€ ÒB°%”˜%Ñ- 9Õ-ÑBùr¢   )r‡   rƒ   r˜   )rP   Úensure_uniqueÚkwargsÚ
new_valuesr    s       @r   r   r   '  sS   ø€ ð ˜cÐ"€IØ×Ñ�VÔáÜÓLÀVÔLÓLˆ
Ü˜:°¸;Ñ1GÔHÐHäÓB¸6ÔBÓBÐBr   )F)r]   )Frš   )"r%   rK   rw   Úcollectionsr   Úcollections.abcr   Údecimalr   r   r   r   Ú	functoolsr
   r   r�   Úagater   Úagate.warnsr   r   ÚobjectÚdefaultr   r   r'   rH   rY   rd   ru   r|   rˆ   r�   r˜   r   r   r   ú<module>r¯      s‚   ðñó
 Û Ý #Ý $ß CÓ CÝ å 'å ß Bñ ‹(€ò÷$ñ ô )�ô )òXò& óFSò&òR	;óò.Bó'ôTCr   