o
    3i>                     @   s  d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlmZm	Z	 d dl
mZm
Z
mZ d dlmZ d dlmZmZ d dlmZ d dlZd dlZd dlZd dlZd dlmZmZ ed	Zd
d Zdd Zdd Zdd Z dd Z!dd Z"dd Z#dd Z$dedee% fddZ&de'fddZ(G d d! d!eZ)G d"d# d#Z*G d$d% d%Z+G d&d' d'Z,d(d) Z-d*d+ Z.d,d- Z/d.d/ Z0de1e%ef fd0d1Z2dS )2    N)defaultdict)asdictis_dataclass)datedatetimetimezone)Decimal)AnyOptional)UUID)tzlocaltzutcposthogc                 C   s   | j du p| j | du S )z1Determines if a given datetime.datetime is naive.N)tzinfo	utcoffset)dt r   [/lsinfo/ai/hellotax_ai/llm_service/venv_embed/lib/python3.10/site-packages/posthog/utils.pyis_naive   s   r   c                 C   s"   | j | j| jd d  d  d S )z2Determines total seconds with python < 2.7 compat.     g    .A)microsecondssecondsdays)deltar   r   r   total_seconds   s   "r   c                 C   s@   t | rt |  }t|dk r| jt dS | jt dS | S )z:Attempts to convert a naive datetime to an aware datetime.   r   )r   r   nowr   replacer   r   )r   r   r   r   r   guess_timezone!   s   r    c                 C   s   |  dr| d d S | S )N/)endswith)hostr   r   r   remove_trailing_slash2   s   
r%   c              
   C   s  t | tr	t| S t | trt| S t | tjttj	t
ttd fr#| S t | tttfr/t| S zt| dr?t| jr?|  } nt| drMt| jrM|  } W n tyh } ztd|  W Y d }~nd }~ww t | trrt| S t| rt | tst| S t| S )N
model_dumpdictz)Could not serialize Pydantic-like model: )
isinstancer   floatr   strsixstring_typesboolnumbersNumberr   r   typesetlisttuple_clean_listhasattrcallabler&   r'   	TypeErrorlogdebug_clean_dictr   _clean_dataclass_coerce_unicode)itemer   r   r   clean8   s4   



r?   c                 C   s   dd | D S )Nc                 S   s   g | ]}t |qS r   )r?   ).0r=   r   r   r   
<listcomp>V   s    z_clean_list.<locals>.<listcomp>r   )list_r   r   r   r4   U      r4   c                 C   sR   i }t | D ]\}}zt|||< W q ty&   td||t| Y qw |S )NzXDictionary values must be serializeable to JSON "%s" value %s of type %s is unsupported.)r+   	iteritemsr?   r7   r8   warningr0   )dict_datakvr   r   r   r:   Y   s   r:   c                 C   s   t | }t|}|S N)r   r:   )
dataclass_rG   r   r   r   r;   h   s   r;   cmplxreturnc              
   C   s   d}zt | tr| dd}W |S t | tr| }W |S W |S  ty? } zdtt|j}t	d| W Y d}~dS d}~ww )a  
    In theory, this method is only called
    after many isinstance checks are carried out in `utils.clean`.
    When we supported Python 2 it was safe to call `decode` on a `str`
    but in Python 3 that will throw.
    So, we check if the input is bytes and only call `decode` in that case.

    Previously we would always call `decode` on the input
    That would throw an error.
    Then we would call `decode` on the stringified error
    That would throw an error.
    And then we would return `None`

    To avoid a breaking change, we can maintain the behavior
    that anything which did not have `decode` in Python 2
    returns None.
    Nzutf-8strict:zError decoding: %s)
r(   bytesdecoder*   	Exceptionjoinmapargsr8   rE   )rL   r=   	exceptionr   r   r   r<   n   s    

r<   c                 C   s(   zt |  W dS  t jy   Y dS w )NTF)recompileerror)valuer   r   r   is_valid_regex   s   
r[   c                       s(   e Zd Z fddZ fddZ  ZS )SizeLimitedDictc                    s   t  j|i | || _d S rJ   )super__init__max_size)selfr_   rU   kwargs	__class__r   r   r^      s   
zSizeLimitedDict.__init__c                    s(   t | | jkr|   t || d S rJ   )lenr_   clearr]   __setitem__)r`   keyrZ   rb   r   r   rf      s   zSizeLimitedDict.__setitem__)__name__
__module____qualname__r^   rf   __classcell__r   r   rb   r   r\      s    r\   c                   @   s(   e Zd Zd	ddZdd Zd
ddZdS )FlagCacheEntryNc                 C   s   || _ || _|pt | _d S rJ   )flag_resultflag_definition_versiontime	timestamp)r`   rm   rn   rp   r   r   r   r^      s   zFlagCacheEntry.__init__c                 C   s    || j  |k }| j|k}|o|S rJ   )rp   rn   )r`   current_timettlcurrent_flag_version
time_validversion_validr   r   r   is_valid   s   
zFlagCacheEntry.is_validr   c                 C   s   || j  |k S rJ   )rp   )r`   rq   max_stale_ager   r   r   is_stale_but_usable   rC   z"FlagCacheEntry.is_stale_but_usablerJ   r   )rh   ri   rj   r^   rv   rx   r   r   r   r   rl      s    
rl   c                   @   sH   e Zd ZdddZdd Zddd	Zd
d Zdd Zdd Zdd Z	dS )	FlagCache'  ,  c                 C   s   i | _ i | _|| _|| _d S rJ   )cacheaccess_timesr_   default_ttl)r`   r_   r   r   r   r   r^      s   
zFlagCache.__init__c                 C   sX   t   }|| jvrd S | j| }||vrd S || }||| j|r*|| j|< |jS d S rJ   )ro   r}   rv   r   r~   rm   )r`   distinct_idflag_keyrs   rq   
user_flagsentryr   r   r   get_cached_flag   s   


zFlagCache.get_cached_flagr   c                 C   sJ   t   }|| jvrd S | j| }||vrd S || }|||r#|jS d S rJ   )ro   r}   rx   rm   )r`   r   r   rw   rq   r   r   r   r   r   get_stale_cached_flag   s   

zFlagCache.get_stale_cached_flagc                 C   sb   t   }|| jvrt| j| jkr|   || jvri | j|< t|||| j| |< || j|< d S rJ   )ro   r}   rd   r_   
_evict_lrurl   r~   )r`   r   r   rm   rn   rq   r   r   r   set_cached_flag   s   

zFlagCache.set_cached_flagc                 C   s   g }| j  D ](\}}g }| D ]\}}|j|kr|| q|D ]}||= q"|s/|| q|D ]}| j |= || jv rA| j|= q2d S rJ   )r}   itemsrn   appendr~   )r`   old_versionusers_to_remover   r   flags_to_remover   r   r   r   r   invalidate_version   s$   



zFlagCache.invalidate_versionc                 C   sp   | j sd S t| j  dd d}tdt|d }|d | D ]\}}|| jv r,| j|= || j v r5| j |= qd S )Nc                 S   s   | d S )N   r   )xr   r   r   <lambda>  s    z&FlagCache._evict_lru.<locals>.<lambda>)rg   r   r   )r~   sortedr   maxrd   r}   )r`   sorted_users	to_remover   _r   r   r   r     s   

zFlagCache._evict_lruc                 C   s   | j   | j  d S rJ   )r}   re   r~   )r`   r   r   r   re     s   
zFlagCache.clearN)r{   r|   ry   )
rh   ri   rj   r^   r   r   r   r   r   re   r   r   r   r   rz      s    

rz   c                   @   s\   e Zd Z	dddZdd Zdd	d
Zdd Zdd ZdddZdd Z	dd Z
dd ZdS )RedisFlagCacher|   r   posthog:flags:c                 C   s(   || _ || _|| _|| _| d| _d S )Nversion)redisr   	stale_ttl
key_prefixversion_key)r`   redis_clientr   r   r   r   r   r   r^     s
   zRedisFlagCache.__init__c                 C   s   | j  | d| S )NrO   )r   )r`   r   r   r   r   r   _get_cache_key   s   zRedisFlagCache._get_cache_keyNc                 C   s.   |d u rt   }t|}|||d}t|S )N)rm   flag_versionrp   )ro   r?   jsondumps)r`   rm   rn   rp   serialized_resultr   r   r   r   _serialize_entry#  s   
zRedisFlagCache._serialize_entryc              
   C   sH   zt |}|d }t||d |d dW S  t jttfy#   Y d S w )Nrm   r   rp   )rm   rn   rp   )r   loadsrl   JSONDecodeErrorKeyError
ValueError)r`   rG   r   rm   r   r   r   _deserialize_entry1  s   
z!RedisFlagCache._deserialize_entryc                 C   sb   z&|  ||}| j|}|r$| |}|r$|t | j|r$|jW S W d S  ty0   Y d S w rJ   )	r   r   getr   rv   ro   r   rm   rR   )r`   r   r   rs   	cache_keyrG   r   r   r   r   r   >  s   
zRedisFlagCache.get_cached_flagc                 C   sl   z+|d u r| j }| ||}| j|}|r)| |}|r)|t |r)|jW S W d S  ty5   Y d S w rJ   )	r   r   r   r   r   rx   ro   rm   rR   )r`   r   r   rw   r   rG   r   r   r   r   r   O  s   
z$RedisFlagCache.get_stale_cached_flagc                 C   sV   z |  ||}| ||}| j|| j| | j| j| W d S  ty*   Y d S w rJ   )r   r   r   setexr   r1   r   rR   )r`   r   r   rm   rn   r   serialized_entryr   r   r   r   a  s   zRedisFlagCache.set_cached_flagc              
   C   s   zWd}| j  d}	 | jj||dd\}}|D ]8}| | jkr!qz| j|}|r<t|}|d|kr<| j| W q tj	t
fyO   | j| Y qw |dkrWW d S q
 tya   Y d S w )Nr   *Td   matchcountr   )r   r   scanrQ   r   r   r   r   deleter   r   rR   )r`   r   cursorpatternkeysrg   rG   
entry_dictr   r   r   r   t  s0   
z!RedisFlagCache.invalidate_versionc                 C   s^   z$d}| j  d}	 | jj||dd\}}|r| jj|  |dkr$W d S q
 ty.   Y d S w )Nr   r   Tr   r   )r   r   r   r   rR   )r`   r   r   r   r   r   r   re     s   zRedisFlagCache.clear)r|   r   r   rJ   )rh   ri   rj   r^   r   r   r   r   r   r   r   re   r   r   r   r   r     s    
	

!r   c                 C   s   | j d u r| jtjd} | S )Nr   )r   r   r   utc)date_objr   r   r   convert_to_datetime_aware  s   
r   c                 C   s   t | t |  v S )a  
    Check if a string contains another string, ignoring case.

    Args:
        source: The string to search within
        search: The substring to search for

    Returns:
        bool: True if search is a substring of source (case-insensitive), False otherwise

    Examples:
        >>> str_icontains("Hello World", "WORLD")
        True
        >>> str_icontains("Hello World", "python")
        False
    r*   casefold)sourcesearchr   r   r   str_icontains     r   c                 C   s   t |  t | kS )a  
    Check if a string equals another string, ignoring case.

    Args:
        value: The string to compare
        comparand: The string to compare with

    Returns:
        bool: True if value and comparand are equal (case-insensitive), False otherwise

    Examples:
        >>> str_iequals("Hello World", "hello world")
        True
        >>> str_iequals("Hello World", "hello")
        False
    r   )rZ   	comparandr   r   r   str_iequals  r   r   c                  C   s   d} d}t j}|dr!d} ttdrt d }|r|}| |fS |dkr:d} ttdr6t d }|r6|}| |fS |d	rQd
} t }|d rM|d }| |fS |dred} ttdrat }| |fS |} ttdrpt }| |fS )zr
    Returns standardized OS name and version information.
    Similar to how user agent parsing works in JS.
     winWindows	win32_verr   darwinzMac OS Xmac_verlinuxLinuxr   freebsdFreeBSDrelease)	sysplatform
startswithr5   r   r   distroinfor   )os_name
os_versionplatform_namewin_versionmac_version
linux_infor   r   r   get_os_info  s@   






r   c                  C   s*   t  \} }t dtjd d  | |dS )Nz%s.%s.%s   )z$python_runtimez$python_versionz$osz$os_version)r   r   python_implementationr   version_info)r   r   r   r   r   system_context  s   
r   )3r   loggingr.   rW   ro   collectionsr   dataclassesr   r   r   r   r   decimalr   typingr	   r
   uuidr   r   r   r   r+   dateutil.tzr   r   	getLoggerr8   r   r   r    r%   r?   r4   r:   r;   r*   r<   r-   r[   r\   rl   rz   r   r   r   r   r   r'   r   r   r   r   r   <module>   sJ    
 e +