
    i>                        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j        d	          Zd
 Zd Zd Zd Z d Z!d Z"d Z#d Z$dedee%         fdZ&de'fdZ( G d de          Z) G d d          Z* G d d          Z+ G d d          Z,d Z-d Z.d  Z/d! Z0de1e%ef         fd"Z2dS )#    N)defaultdict)asdictis_dataclass)datedatetimetimezone)Decimal)AnyOptional)UUID)tzlocaltzutcposthogc                 L    | j         du p| j                             |           du S )z1Determines if a given datetime.datetime is naive.N)tzinfo	utcoffset)dts    @/var/www/icac/venv/lib/python3.11/site-packages/posthog/utils.pyis_naiver      s)    9?	 3 3B 7 74 ??    c                 H    | j         | j        | j        dz  dz  z   dz  z   dz  S )z2Determines total seconds with python < 2.7 compat.     g    .A)microsecondssecondsdays)deltas    r   total_secondsr      s/     %-%*r/D2H"HC!OOSVVVr   c                     t          |           rmt          j                    | z
  }t          |          dk     r"|                     t                                S |                     t                                S | S )z:Attempts to convert a naive datetime to an aware datetime.   r   )r   r   nowr   replacer   r   )r   r   s     r   guess_timezoner$   !   sn    || 
. #!## ::WYY:/// ::UWW:---Ir   c                 D    |                      d          r
| d d         S | S )N/)endswith)hosts    r   remove_trailing_slashr*   2   s)    }}S CRCyKr   c                    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 	 t#          | d          r)t%          | j                  r|                                 } n8t#          | d          r(t%          | j                  r|                                 } n4# t*          $ r'}t,                              d|            Y d }~nd }~ww xY wt          | t(                    rt1          |           S t3          |           r$t          | t                    st5          |           S t7          |           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es     r   cleanrE   8   s   $   T{{$ 4yysw~xtDzzR   $dE*++ !4   	4&& 	8DO+D+D 	??$$DDT6"" 	x	':': 	99;;D   		AaAABBB $ !4   D &*T4"8"8 &%%%4   s   A1D5 5
E&?E!!E&c                     d | D             S )Nc                 ,    g | ]}t          |          S  )rE   ).0rC   s     r   
<listcomp>z_clean_list.<locals>.<listcomp>V   s    ***DE$KK***r   rH   )list_s    r   r:   r:   U   s    **E****r   c           
          i }t          j        |           D ]R\  }}	 t          |          ||<   # t          $ r- t                              d||t          |                     Y Ow xY w|S )NzXDictionary values must be serializeable to JSON "%s" value %s of type %s is unsupported.)r1   	iteritemsrE   r=   r>   warningr6   )dict_datakvs       r   r@   r@   Y   s    De$$ 	 	1	AhhDGG 	 	 	KKjQ	    	 Ks   04A'&A'c                 B    t          |           }t          |          }|S N)r   r@   )
dataclass_rP   s     r   rA   rA   h   s!    *DtDKr   cmplxreturnc                 T   d}	 t          | t                    r|                     dd          }nt          | t                    r| }n`# t          $ rS}d                    t          t          |j                            }t          	                    d|           Y d}~dS d}~ww xY w|S )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decoder0   	Exceptionjoinmapargsr>   rN   )rV   rC   	exceptions      r   rB   rB   n   s    $ DeU## 	<<22DDs## 	D   xxC0011($///ttttt
 Ks   AA 
B%AB  B%c                 \    	 t          j        |            dS # t           j        $ r Y dS w xY w)NTF)recompileerror)values    r   is_valid_regexrg      s@    

5t8   uus    ++c                   (     e Zd Z fdZ fdZ xZS )SizeLimitedDictc                 H     t                      j        |i | || _        d S rT   )super__init__max_size)selfrm   r`   kwargs	__class__s       r   rl   zSizeLimitedDict.__init__   s*    $)&))) r   c                     t          |           | j        k    r|                                  t                                          ||           d S rT   )lenrm   clearrk   __setitem__)rn   keyrf   rp   s      r   rt   zSizeLimitedDict.__setitem__   sC    t99%%JJLLLC'''''r   )__name__
__module____qualname__rl   rt   __classcell__)rp   s   @r   ri   ri      sQ        ! ! ! ! !( ( ( ( ( ( ( ( (r   ri   c                   $    e Zd ZddZd ZddZdS )FlagCacheEntryNc                 V    || _         || _        |pt          j                    | _        d S rT   )flag_resultflag_definition_versiontime	timestamp)rn   r}   r~   r   s       r   rl   zFlagCacheEntry.__init__   s(    &'>$"1dikkr   c                 <    || j         z
  |k     }| j        |k    }|o|S rT   )r   r~   )rn   current_timettlcurrent_flag_version
time_validversion_valids         r   is_validzFlagCacheEntry.is_valid   s,    "T^3s:
48LL+m+r   r   c                     || j         z
  |k     S rT   )r   )rn   r   max_stale_ages      r   is_stale_but_usablez"FlagCacheEntry.is_stale_but_usable   s    t~->>r   rT   r   )rv   rw   rx   rl   r   r   rH   r   r   r{   r{      sK        2 2 2 2
, , ,
? ? ? ? ? ?r   r{   c                   <    e Zd ZddZd ZddZd Zd Zd	 Zd
 Z	dS )	FlagCache'  ,  c                 >    i | _         i | _        || _        || _        d S rT   )cacheaccess_timesrm   default_ttl)rn   rm   r   s      r   rl   zFlagCache.__init__   s&    
 &r   c                     t          j                     }|| j        vrd S | j        |         }||vrd S ||         }|                    || j        |          r|| j        |<   |j        S d S rT   )r   r   r   r   r   r}   )rn   distinct_idflag_keyr   r   
user_flagsentrys          r   get_cached_flagzFlagCache.get_cached_flag   s|    y{{dj((4Z,
:%%48$>>,(8:NOO 	%-9Dk*$$tr   r   c                     t          j                     }|| j        vrd S | j        |         }||vrd S ||         }|                    ||          r|j        S d S rT   )r   r   r   r}   )rn   r   r   r   r   r   r   s          r   get_stale_cached_flagzFlagCache.get_stale_cached_flag   sk    y{{dj((4Z,
:%%48$$$\=AA 	%$$tr   c                    t          j                     }|| j        vr1t          | j                  | j        k    r|                                  || j        vr
i | j        |<   t          |||          | j        |         |<   || j        |<   d S rT   )r   r   rr   rm   
_evict_lrur{   r   )rn   r   r   r}   r~   r   s         r   set_cached_flagzFlagCache.set_cached_flag   s     y{{ dj((S__-M-MOO dj((&(DJ{# -;0,-
 -

;) *6+&&&r   c                 :   g }| j                                         D ]`\  }}g }|                                D ]%\  }}|j        |k    r|                    |           &|D ]}||= |s|                    |           a|D ]}| j         |= || j        v r| j        |= d S rT   )r   itemsr~   appendr   )rn   old_versionusers_to_remover   r   flags_to_remover   r   s           r   invalidate_versionzFlagCache.invalidate_version   s    '+z'7'7'9'9 	4 	4#K O#-#3#3#5#5 5 5%0K??#**8444 , ) )x((  4&&{333 + 	3 	3K
;'d///%k2	3 	3r   c                    | j         sd S t          | j                                         d           }t          dt	          |          dz            }|d |         D ]'\  }}|| j        v r| j        |= || j         v r| j         |= (d S )Nc                     | d         S )N   rH   )xs    r   <lambda>z&FlagCache._evict_lru.<locals>.<lambda>  s
    qt r   )ru   r   r    )r   sortedr   maxrr   r   )rn   sorted_users	to_remover   _s        r   r   zFlagCache._evict_lru  s      	F d/5577^^LLL3|,,122	*:I:6 	3 	3NKdj((J{+d///%k2		3 	3r   c                 j    | j                                          | j                                         d S rT   )r   rs   r   )rn   s    r   rs   zFlagCache.clear  s1    
!!!!!r   N)r   r   r   )
rv   rw   rx   rl   r   r   r   r   r   rs   rH   r   r   r   r      s        ' ' ' '  "    6 6 6&3 3 3.3 3 3" " " " "r   r   c                   L    e Zd Z	 ddZd ZddZd Zd	 Zdd
Zd Z	d Z
d ZdS )RedisFlagCacher   r   posthog:flags:c                 R    || _         || _        || _        || _        | d| _        d S )Nversion)redisr   	stale_ttl
key_prefixversion_key)rn   redis_clientr   r   r   s        r   rl   zRedisFlagCache.__init__  s8     "
&"$(111r   c                     | j          | d| S )NrZ   )r   )rn   r   r   s      r   _get_cache_keyzRedisFlagCache._get_cache_key   s    /;;;;;;;r   Nc                 ~    |t          j                     }t          |          }|||d}t          j        |          S )N)r}   flag_versionr   )r   rE   jsondumps)rn   r}   r~   r   serialized_resultr   s         r   _serialize_entryzRedisFlagCache._serialize_entry#  sL    	I "+.. -3"
 

 z%   r   c                     	 t          j        |          }|d         }t          ||d         |d                   S # t           j        t          t
          f$ r Y d S w xY w)Nr}   r   r   )r}   r~   r   )r   loadsr{   JSONDecodeErrorKeyError
ValueError)rn   rP   r   r}   s       r   _deserialize_entryz!RedisFlagCache._deserialize_entry1  sx    
	Jt$$E.K!'(-n(=,   
 $h
; 	 	 	44	s   9< AAc                 $   	 |                      ||          }| j                            |          }|rK|                     |          }|r4|                    t          j                    | j        |          r|j        S d S # t          $ r Y d S w xY wrT   )	r   r   getr   r   r   r   r}   r]   )rn   r   r   r   	cache_keyrP   r   s          r   r   zRedisFlagCache.get_cached_flag>  s    	++KBBI:>>),,D -//55 -U^^IKK!13G  - !,,4 	 	 	44	s   A<B 
BBc                 *   	 || j         }|                     ||          }| j                            |          }|rE|                     |          }|r.|                    t          j                    |          r|j        S d S # t          $ r Y d S w xY wrT   )	r   r   r   r   r   r   r   r}   r]   )rn   r   r   r   r   rP   r   s          r   r   z$RedisFlagCache.get_stale_cached_flagO  s    	$ $++KBBI:>>),,D -//55 -U66ty{{MRR - ,,4 	 	 	44	s   A?B 
BBc                    	 |                      ||          }|                     ||          }| j                            || j        |           | j                            | j        |           d S # t          $ r Y d S w xY wrT   )r   r   r   setexr   r7   r   r]   )rn   r   r   r}   r~   r   serialized_entrys          r   r   zRedisFlagCache.set_cached_flaga  s    	++KBBI#444   
 JY8HIII JNN4+-DEEEEE 	 	 	DD	s   A-A1 1
A?>A?c                    	 d}| j          d}	 | j                            ||d          \  }}|D ]}|                                | j        k    r 	 | j                            |          }|rGt          j        |          }|                    d          |k    r| j                            |           # t          j	        t          f$ r | j                            |           Y w xY w|dk    rd S # t          $ r Y d S w xY w)Nr   *Td   matchcountr   )r   r   scanr\   r   r   r   r   deleter   r   r]   )rn   r   cursorpatternkeysru   rP   
entry_dicts           r   r   z!RedisFlagCache.invalidate_versiont  s=   	
 F+++G#zvWCPP / /Czz||t'777 /#z~~c22 7)-D)9)9J)~~n==LL $
 1 1# 6 6 6 0(; / / /
))#...../ Q;;E%(  	 	 	DD	s=   AC5 A#B65C5 60C)&C5 (C))	C5 4C5 5
DDc                     	 d}| j          d}	 | j                            ||d          \  }}|r | j        j        |  |dk    rd S :# t          $ r Y d S w xY w)Nr   r   Tr   r   )r   r   r   r   r]   )rn   r   r   r   s       r   rs   zRedisFlagCache.clear  s    	F+++G#zvWCPP -%DJ%t,,Q;;E  	 	 	DD	s   AA	 A	 	
AA)r   r   r   rT   )rv   rw   rx   rl   r   r   r   r   r   r   r   rs   rH   r   r   r   r     s        HX2 2 2 2< < <! ! ! !    "   $  &  B    r   r   c                 T    | j          |                     t          j                  } | S )Nr!   )r   r#   r   utc)date_objs    r   convert_to_datetime_awarer     s'    ##8<#88Or   c                     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
    r0   casefold)sourcesearchs     r   str_icontainsr     s3    " v;;!!S[[%9%9%;%;;;r   c                     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   )rf   	comparands     r   str_iequalsr     s3    " u::  C	NN$;$;$=$===r   c                  ~   d} d}t           j        }|                    d          r5d} t          t          d          rt          j                    d         }|r|}n|dk    r5d} t          t          d          rt          j                    d         }|r|}n|                    d	          r&d
} t          j                    }|d         r|d         }nj|                    d          r+d} t          t          d          rt          j                    }n*|} t          t          d          rt          j                    }| |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
startswithr;   r   r   distroinfor   )os_name
os_versionplatform_namewin_versionmac_version
linux_infos         r   get_os_infor    sR   
 GJLM&& ,8[)) 	)",..q1K )(
	(	"	"8Y'' 	)"*,,Q/K )(
		!	!'	*	* ,[]]
i  	/#I.J		!	!)	,	, ,8Y'' 	,!)++J  8Y'' 	,!)++JJr   c                  ~    t                      \  } }t          j                    dt          j        d d         z  | |dS )Nz%s.%s.%s   )z$python_runtimez$python_versionz$osz$os_version)r  r   python_implementationr   version_info)r   r   s     r   system_contextr    sG    %--GZ $9;;%)9"1")=>!	  r   )3r   loggingr4   rc   r   collectionsr   dataclassesr   r   r   r   r   decimalr	   typingr
   r   uuidr   r   r   r   r1   dateutil.tzr   r   	getLoggerr>   r   r   r$   r*   rE   r:   r@   rA   r0   rB   r3   rg   ri   r{   r   r   r   r   r   r  r-   r  rH   r   r   <module>r     s      				  # # # # # # , , , , , , , , - - - - - - - - - -                             



   



 & & & & & & & &g	""@ @ @
W W W  "  ! ! !:+ + +    3 8C=    @T    	( 	( 	( 	( 	(k 	( 	( 	(? ? ? ? ? ? ? ?b" b" b" b" b" b" b" b"JM M M M M M M M`  < < <(> > >(( ( (VS#X      r   