
    Qi>                        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j6                  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"Z2y)#    N)defaultdict)asdictis_dataclass)datedatetimetimezone)Decimal)AnyOptional)UUID)tzlocaltzutcposthogc                 \    | j                   du xs | j                   j                  |       du S )z1Determines if a given datetime.datetime is naive.N)tzinfo	utcoffset)dts    I/mnt/e/genesis-system/.venv/lib/python3.12/site-packages/posthog/utils.pyis_naiver      s*    99?		 3 3B 74 ??    c                 f    | 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      s6     %--%**r/D2H"HC!OOSVVVr   c                     t        |       rYt        j                         | z
  }t        |      dk  r| j	                  t                     S | j	                  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$   !   sW    | #!# ::WY:// ::UW:--Ir   c                 2    | j                  d      r| d d S | S )N/)endswith)hosts    r   remove_trailing_slashr*   2   s    }}SCRy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| j'                         } n1t#        | d      r%t%        | j(                        r| j)                         } t        | t(              rt1        |       S t3        |       rt        | t              st5        |       S t7        |       S # t*        $ r"}t,        j/                  d|        Y d }~rd }~ww xY w)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{$4ysw~~xtDzR $dE*+4  	4&8DOO+D??$DT6"x		':99;D $4  D*T4"8%%4    		=aSABs   #A#E 	E=E88E=c                 >    | D cg c]  }t        |       c}S c c}w N)rE   )list_rC   s     r   r:   r:   U   s    $)*DE$K***s   c           
          i }t        j                  |       D ]  \  }}	 t        |      ||<    |S # t        $ r$ t        j                  d||t        |             Y Ew xY w)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   si    De$ 	1	AhDG	 K  	KKjQ		s   1*AAc                 2    t        |       }t        |      }|S rG   )r   r@   )
dataclass_rM   s     r   rA   rA   h   s    *DtDKr   cmplxreturnc                 "   d}	 t        | t              r| j                  dd      }|S t        | t              r| }|S # t        $ rI}dj                  t        t        |j                              }t        j                  d|       Y d}~yd}~ww xY 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decoder0   	Exceptionjoinmapargsr>   rK   )rR   rC   	exceptions      r   rB   rB   n   s    $ DeU#<<2D K s#D K  xxC01($/s   "< < 	B?B		Bc                 b    	 t        j                  |        y# t         j                  $ r Y yw xY w)NTF)recompileerror)values    r   is_valid_regexrc      s,    


588 s    ..c                   (     e Zd Z fdZ fdZ xZS )SizeLimitedDictc                 2    t        |   |i | || _        y rG   )super__init__max_size)selfri   r\   kwargs	__class__s       r   rh   zSizeLimitedDict.__init__   s    $)&) r   c                 v    t        |       | j                  k\  r| j                          t        |   ||       y rG   )lenri   clearrg   __setitem__)rj   keyrb   rl   s      r   rp   zSizeLimitedDict.__setitem__   s+    t9%JJLC'r   )__name__
__module____qualname__rh   rp   __classcell__)rl   s   @r   re   re      s    !( (r   re   c                   "    e Zd ZddZd ZddZy)FlagCacheEntryNc                 Z    || _         || _        |xs t        j                         | _        y rG   )flag_resultflag_definition_versiontime	timestamp)rj   ry   rz   r|   s       r   rh   zFlagCacheEntry.__init__   s$    &'>$"1diikr   c                 P    || j                   z
  |k  }| j                  |k(  }|xr |S rG   )r|   rz   )rj   current_timettlcurrent_flag_version
time_validversion_valids         r   is_validzFlagCacheEntry.is_valid   s1    "T^^3s:
448LL+m+r   c                 &    || j                   z
  |k  S rG   )r|   )rj   r~   max_stale_ages      r   is_stale_but_usablez"FlagCacheEntry.is_stale_but_usable   s    t~~->>r   rG   r   )rr   rs   rt   rh   r   r    r   r   rw   rw      s    2
,
?r   rw   c                   :    e Zd Zd	dZd Zd
dZd Zd Zd Zd Z	y)	FlagCachec                 <    i | _         i | _        || _        || _        y rG   )cacheaccess_timesri   default_ttl)rj   ri   r   s      r   rh   zFlagCache.__init__   s     
 &r   c                     t        j                          }|| j                  vry | j                  |   }||vry ||   }|j                  || j                  |      r|| j                  |<   |j
                  S y rG   )r{   r   r   r   r   ry   )rj   distinct_idflag_keyr   r~   
user_flagsentrys          r   get_cached_flagzFlagCache.get_cached_flag   su    yy{djj(ZZ,
:%8$>>,(8(8:NO-9Dk*$$$r   c                     t        j                          }|| j                  vry | j                  |   }||vry ||   }|j                  ||      r|j                  S y rG   )r{   r   r   ry   )rj   r   r   r   r~   r   r   s          r   get_stale_cached_flagzFlagCache.get_stale_cached_flag   s^    yy{djj(ZZ,
:%8$$$\=A$$$r   c                 >   t        j                          }|| j                  vr2t        | j                        | j                  k\  r| j	                          || j                  vri | j                  |<   t        |||      | j                  |   |<   || j                  |<   y rG   )r{   r   rn   ri   
_evict_lrurw   r   )rj   r   r   ry   rz   r~   s         r   set_cached_flagzFlagCache.set_cached_flag   s     yy{ djj(S_-MOO djj(&(DJJ{# -;0,-


;) *6+&r   c                 ^   g }| j                   j                         D ]^  \  }}g }|j                         D ]&  \  }}|j                  |k(  s|j                  |       ( |D ]  }||=  |rN|j                  |       ` |D ]+  }| j                   |= || j                  v s| j                  |= - y rG   )r   itemsrz   appendr   )rj   old_versionusers_to_remover   r   flags_to_remover   r   s           r   invalidate_versionzFlagCache.invalidate_version   s    '+zz'7'7'9 	4#K O#-#3#3#5 5%00K?#**845
 , )x() &&{3	4 + 	3K

;'d///%%k2	3r   c                 "   | j                   sy t        | j                   j                         d       }t        dt	        |      dz        }|d | D ]<  \  }}|| j
                  v r| j
                  |= || j                   v s0| j                   |= > y )Nc                     | d   S )N   r   )xs    r   <lambda>z&FlagCache._evict_lru.<locals>.<lambda>  s
    qt r   )rq   r   r    )r   sortedr   maxrn   r   )rj   sorted_users	to_remover   _s        r   r   zFlagCache._evict_lru  s       d//557^L3|,12	*:I6 	3NKdjj(JJ{+d///%%k2		3r   c                 l    | j                   j                          | j                  j                          y rG   )r   ro   r   )rj   s    r   ro   zFlagCache.clear  s$    

!r   N)i'  ,  r   )
rr   rs   rt   rh   r   r   r   r   r   ro   r   r   r   r   r      s%    '" 6&3.3"r   r   c                   J    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y)RedisFlagCachec                 P    || _         || _        || _        || _        | d| _        y )Nversion)redisr   	stale_ttl
key_prefixversion_key)rj   redis_clientr   r   r   s        r   rh   zRedisFlagCache.__init__  s0     "
&"$(\1r   c                 (    | j                    | d| S )NrV   )r   )rj   r   r   s      r   _get_cache_keyzRedisFlagCache._get_cache_key   s    //";-q
;;r   Nc                 z    |t        j                          }t        |      }|||d}t        j                  |      S )N)ry   flag_versionr|   )r{   rE   jsondumps)rj   ry   rz   r|   serialized_resultr   s         r   _serialize_entryzRedisFlagCache._serialize_entry#  sC    		I "+. -3"

 zz%  r   c                     	 t        j                  |      }|d   }t        ||d   |d         S # t         j                  t        t
        f$ r Y y w xY w)Nry   r   r|   )ry   rz   r|   )r   loadsrw   JSONDecodeErrorKeyError
ValueError)rj   rM   r   ry   s       r   _deserialize_entryz!RedisFlagCache._deserialize_entry1  s`    
	JJt$E.K!'(-n(=, 
 $$h
; 		s   -0 AAc                    	 | j                  ||      }| j                  j                  |      }|rN| j                  |      }|r;|j	                  t        j
                         | j                  |      r|j                  S y # t        $ r Y y w xY wrG   )	r   r   getr   r   r{   r   ry   rY   )rj   r   r   r   	cache_keyrM   r   s          r   r   zRedisFlagCache.get_cached_flag>  s    	++KBI::>>),D//5U^^IIK!1!13G !,,, 		s   A<B   	BBc                 $   	 || j                   }| j                  ||      }| j                  j                  |      }|rC| j	                  |      }|r0|j                  t        j                         |      r|j                  S y # t        $ r Y y w xY wrG   )	r   r   r   r   r   r   r{   ry   rY   )rj   r   r   r   r   rM   r   s          r   r   z$RedisFlagCache.get_stale_cached_flagO  s    	$ $++KBI::>>),D//5U66tyy{MR ,,, 		s   A?B 	BBc                    	 | j                  ||      }| j                  ||      }| j                  j                  || j                  |       | j                  j                  | j                  |       y # t        $ r Y y w xY wrG   )r   r   r   setexr   r7   r   rY   )rj   r   r   ry   rz   r   serialized_entrys          r   r   zRedisFlagCache.set_cached_flaga  sz    	++KBI#444 
 JJY8HI JJNN4++-DE 		s   A1A4 4	B ?B c                    	 d}| j                    d}	 | j                  j                  ||d      \  }}|D ]  }|j                         | j                  k(  r!	 | j                  j                  |      }|rDt        j                  |      }|j                  d      |k(  r| j                  j                  |        |dk(  ry # t        j                  t        f$ r | j                  j                  |       Y w xY w# t        $ r Y y w xY w)Nr   *d   matchcountr   )r   r   scanrX   r   r   r   r   deleter   r   rY   )rj   r   cursorpatternkeysrq   rM   
entry_dicts           r   r   z!RedisFlagCache.invalidate_versiont  s   	
 F)+G#zzvWCP /Czz|t'7'77 /#zz~~c2)-D)9J)~~n=L $

 1 1# 6/ Q;%  !00(; /

))#./  		s=   AC= A!C:C= C= 4C:7C= 9C::C= =	D	D	c                     	 d}| j                    d}	 | j                  j                  ||d      \  }}|r | j                  j                  |  |dk(  ry C# t        $ r Y y w xY w)Nr   r   r   r   )r   r   r   r   rY   )rj   r   r   r   s       r   ro   zRedisFlagCache.clear  sv    	F)+G#zzvWCP%DJJ%%t,Q;   		s   AA A 	A#"A#)r   r   zposthog:flags:rG   )rr   rs   rt   rh   r   r   r   r   r   r   r   ro   r   r   r   r   r     s3    HX2<!"$&Br   r   c                 ^    | j                    | j                  t        j                        } | S )Nr!   )r   r#   r   utc)date_objs    r   convert_to_datetime_awarer     s(    ##8<<#8Or   c                 f    t        |      j                         t        |       j                         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     s)    " v;!S[%9%9%;;;r   c                 h    t        |       j                         t        |      j                         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   )rb   	comparands     r   str_iequalsr     s)    " u: C	N$;$;$===r   c                  N   d} d}t         j                  }|j                  d      r1d} t        t        d      rt        j                         d   }|r|}| |fS |dk(  r1d} t        t        d      rt        j
                         d   }|r|}| |fS |j                  d	      r$d
} t        j                         }|d   r|d   }| |fS |j                  d      r*d} t        t        d      rt        j                         }| |fS |} 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     s@   
 GJLLM&8[)",,.q1K(
2 J/ 
(	"8Y'"**,Q/K(
$ J! 
	!	!'	*[[]
i #I.J J 
	!	!)	,8Y'!))+J J	  8Y'!))+JJr   c                  v    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    sA    %-GZ $99;%)9)9"1)=>!	 r   )3r   loggingr4   r_   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   rc   re   rw   r   r   r   r   r   r   r-   r  r   r   r   <module>r
     s       	  # , - -     
   
 &g	"@
W"!:+3 8C= @T 	(k 	(? ?b" b"JM M`<(>((VS#X r   