
    jKj              	          d dl Z 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	 d dl
mZ d dlmZ d dlmZmZ  ed      Z ej&                  d      Zd	gZ G d
 de      ZdZdZdZdZdZdZeez   Zeez   ez   ez   ez   Z G d de      Z  G d de      Z!d5de"de"de"defdZ#d Z$d Z%	 d6dZ&d Z'd6dZ(ddddddddd defd!Z)	 	 d7dd"defd#Z*de+fd$Z,	 	 	 	 d8de+fd%Z-	 	 	 	 d8de+fd&Z.d'e"dej                  fd(Z/d)ej                  d*e0de	ej                     fd+Z1d)ej                  d,e0de	ej                     fd-Z2d'e"de	ej                     fd.Z3d/e"de0fd0Z4d'e"de5fd1Z6d'e"de5fd2Z7d'e"de5fd3Z8d'e"de5fd4Z9y)9    N)Enum)Optional)utils)	FlagValue)convert_to_datetime_awareis_valid_regexl   posthogis_notc                       e Zd ZdZdZdZdZy)ConditionMatchu?  Outcome of evaluating a single condition group.

    OUT_OF_ROLLOUT_BOUND means the group's property filters matched (or there were none)
    but the rollout percentage excluded the user — the only case that triggers a flag's
    ``early_exit`` short-circuit. Mirrors the server-side (Rust) engine's match cases.
    matchno_matchout_of_rollout_boundN)__name__
__module____qualname____doc__MATCHNO_MATCHOUT_OF_ROLLOUT_BOUND     f/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/posthog/feature_flags.pyr   r      s     EH1r   r   )exactr
   is_set
is_not_set)	icontainsnot_icontainsregex	not_regexgtgteltlteis_date_beforeis_date_after)	semver_eq
semver_neq	semver_gt
semver_gte	semver_lt
semver_lte)semver_tildesemver_caretsemver_wildcardc                       e Zd Zy)InconclusiveMatchErrorN)r   r   r   r   r   r   r3   r3   ;   s    r   r3   c                       e Zd ZdZy)RequiresServerEvaluationa&  
    Raised when feature flag evaluation requires server-side data that is not
    available locally (e.g., static cohorts, experience continuity).

    This error should propagate immediately to trigger API fallback, unlike
    InconclusiveMatchError which allows trying other conditions.
    N)r   r   r   r   r   r   r   r5   r5   ?   s     	r   r5   keybucketing_valuesaltreturnc                     |  d| | }t        t        j                  |j                  d            j	                         d d d      }|t
        z  S )N.zutf-8      )inthashlibsha1encode	hexdigest__LONG_SCALE__)r6   r7   r8   hash_keyhash_vals        r   _hashrF   O   sP    a(/H7<< 89CCEcrJBOHn$$r   c                 v    t        | d   |d      }t        |       D ]  }||d   k\  s||d   k  s|d   c S  y )Nr6   variant)r8   	value_min	value_max)rF   variant_lookup_table)flagr7   
hash_valuerH   s       r   get_matching_variantrN   U   sK    tE{O)DJ'---*w{?S2S5>! . r   c                     g }d}| j                  d      xs i j                  d      xs i j                  d      xs g }|D ]'  }||d   dz  z   }|j                  |||d   d       |}) |S )	Nr   filtersmultivariatevariantsrollout_percentaged   r6   )rI   rJ   r6   )getappend)feature_flaglookup_tablerI   multivariatesrH   rJ   s         r   rK   rK   ]   s    LI"&&y17R<<^LRPRWW 	  !(< = CC	#)GENS	
 	 ! r   c                    ||t        d| j                  dd       d      d| vrt        d| j                  dd       d      | d   }t        |      d	k(  rFt        j	                  d
| j                  d              t        d| j                  dd       d      |D ]  }||vr|j                  |      }	|	sd||<   t        d| d      |	j                  d      sd||<   nQ	 |	j                  d      xs i }
|
j                  d      }||}nt        |	||      }t        |	|||||||      }|||<   ||   }|t        d| d      |r y | j                  d      }| j                  d      }| j                  dd      }|rW|U|j                  |      }|t        d| d      |dk(  rt        ||      S t        d| j                  dd       d| d      y# t         $ r}d||<   t        d| d|       |d}~ww xY w)ai  
    Evaluate a flag dependency property according to the dependency chain algorithm.

    Args:
        property: Flag property with type="flag" and dependency_chain
        flags_by_key: Dictionary of all flags by their key
        evaluation_cache: Cache for storing evaluation results
        distinct_id: The distinct ID being evaluated
        properties: Person properties for evaluation
        cohort_properties: Cohort properties for evaluation
        device_id: The device ID for bucketing (optional)

    Returns:
        bool: True if all dependencies in the chain evaluate to True, False otherwise
    Nz$Cannot evaluate flag dependency on 'r6   unknownz+' without flags_by_key and evaluation_cachedependency_chainzFlag dependency property for 'z.' is missing required 'dependency_chain' fieldr   z'Circular dependency detected for flag: z'Circular dependency detected for flag ''z!Cannot evaluate flag dependency 'z!' - flag not found in local flagsactiveFrP   aggregation_group_type_index)cohort_propertiesflags_by_keyevaluation_cache	device_idr7   z': zFlag dependency 'z' was previously inconclusivevalueoperatorr   zFlag 'z5' was not evaluated despite being in dependency chainflag_evaluates_toz' has invalid operator 'T)r3   rU   lenlogdebugresolve_bucketing_valuematch_feature_flag_propertiesmatches_dependency_value)propertyra   rb   distinct_id
propertiesr`   rc   r\   dep_flag_keydep_flagdep_flag_filters dep_aggregation_group_type_indexdep_bucketing_value
dep_resultecached_resultflag_keyexpected_valuere   actual_values                       r   evaluate_flag_dependencyr{   l   s   0 /7$28<<y3Q2RR}~
 	

 )$,X\\%-K,LLz{
 	
   23 !		;HLL<O;PQR$5hll5)6T5UUVW
 	

 )//#''5H15 .,7~Efg 
  ||H-5:$\2!+3<<	+B+Hb(;K;O;O:<8 <G 3>/2I (+y3/ &C$'&.?)5-=&/,?	&
 :D(6 )6 (#L>1NO  q )x ||E"H\\'*N||J0HN.'++H5(
"WX  **+NLII )0eY1O0PPhiqhrrst 
 [ 2 !9=(64?~SQRPST !!s   (AG""	H+HHc                     t        |t              r6t        |      dkD  r(t        | t              r| S t        | t              r|| k(  S yt        |t              rt        | t              r|| k(  S y)a  
    Check if the actual flag value matches the expected dependency value.

    This follows the same logic as the C# MatchesDependencyValue function:
    - String variant case: check for exact match or boolean true
    - Boolean case: must match expected boolean value

    Args:
        expected_value: The expected value from the property
        actual_value: The actual value returned by the flag evaluation

    Returns:
        bool: True if the values match according to flag dependency rules
    r   F)
isinstancestrrg   bool)ry   rz   s     r   rl   rl      sg      ,$\):Q)>nd+!!,>11 
L$	'J~t,L~-- r   c                     | j                  d      xs i }| j                  d      xs |j                  d      }|dk(  r|st        d      |S |S )a  Resolve the bucketing value for a flag based on its bucketing_identifier setting.

    Returns:
        The appropriate identifier string to use for hashing/bucketing.

    Raises:
        InconclusiveMatchError: If the flag requires device_id but none was provided.
    rP   bucketing_identifierrc   z;Flag requires device_id for bucketing but none was provided)rU   r3   )rL   rn   rc   flag_filtersr   s        r   rj   rj     sh     88I&,"L88$:; |?O?O@ {*(M  r   )r`   ra   rb   rc   r7   group_type_mappinggroupsgroup_propertiesc                   |)t        j                  dt        d       t        | ||      }| j	                  d      xs i }|j	                  d      xs g }|j	                  d      }|j	                  d      }d}|xs i }|	xs i }	|
xs i }
|xs i }|j	                  d	      xs i j	                  d
      xs g }|D cg c]  }|d   	 }}|D ]  }	 |j	                  d|      }||k7  ra|Z|j	                  t        |            }|r||	vr(t        j                  d| j	                  dd      |       e||
vrd}l|
|   }|	|   }n	|}|}n|}|}t        | ||||||||	      }|t        j                  k(  r.|j	                  d      }|r||v r|}nt        | |      }|xs dc S |r|t        j                  k(  r y |rt        d      yc c}w # t        $ r  t        $ r d}Y w xY w)NzCalling match_feature_flag_properties() without bucketing_value is deprecated. Pass bucketing_value explicitly. This fallback will be removed in a future major release.   )
stacklevelrP   r   r_   
early_exitFrQ   rR   r6   zISkipping group condition for flag '%s': group type index %s not available T)r7   rc   rH   zGCan't determine if feature flag is enabled or not with given properties)warningswarnDeprecationWarningrj   rU   r~   rh   ri   is_condition_matchr   r   rN   r   r5   r3   )rL   rn   ro   r`   ra   rb   rc   r7   r   r   r   r   flag_conditionsflag_aggregationearly_exit_enabledis_inconclusiveflag_variantsrH   valid_variant_keys	conditioncondition_aggregation
group_nameeffective_propertieseffective_bucketingmatch_resultvariant_overrides                             r   rk   rk   +  sq    h		
 2$YO88I&,"L"&&x06BO#''(FG%)),7O)/R\rF'-2+1r!%%n5;@@LRPRM8EFW'%.F$	@	# %.MM.0@%! %(88(4!3!7!7<Q8R!SJ%6)A		g HHUB/1
 !!)99*. +;J+G(*0*<'+5(*9''1$&5#-$!  3#
L ~333#,==#; #(8<N(N.G249LMG$&" N$G$GG
 u %F $U
 	
 Y Gz ( 	% 	# #O	#s,   >G
A G3G:A&G#GG'&G'rc   c          
         |j                  d      }	t        |j                  d      xs g       dkD  r|j                  d      D ]c  }
|
j                  d      }|dk(  rt        |
||||||      }n$|dk(  rt        |
||||||      }nt	        |
|      }|rSt
        j                  c S  |	t
        j                  S |	%t        | d   |      |	d	z  kD  rt
        j                  S t
        j                  S )
NrS   ro   r   typecohortr   rL   r6   rT   )
rU   rg   match_cohortr{   match_propertyr   r   r   rF   r   )rW   rn   r   ro   r`   ra   rb   r7   rc   rS   propproperty_typematchess                r   r   r     s    #';<
9==&,"-1MM,/D HHV,M(&% $' &(2 $%' )z:%...3 06 %!''' %%U_+	c	!+# 222r   c                 	   | j                  d      }| j                  d      xs d}| j                  d      }|t        vrt        d|       ||vrt        d      |dk(  rt        d      ||   }|t        vr|y	|d
v rd }|dk(  r	 |||      S  |||       S |dk(  r||v S |dk(  rt	        j
                  ||      S |dk(  rt	        j
                  ||       S |dk(  rNt        t        |            xr8 t        j                  t        |            j                  t        |            d uS |dk(  rNt        t        |            xr8 t        j                  t        |            j                  t        |            d u S |dv r^d }d }	 t        |      }|/|-t        |t              r ||t        |      |      S  ||||      S  |t        |      t        |      |      S |dv r	 t        t        |            }	|	st        t        |            }	t!        |	      }	|	st        d      t        |t"        j"                        rt!        |      }|dk(  r||	k  S ||	kD  S t        |t"        j$                        r+|dk(  r||	j%                         k  S ||	j%                         kD  S t        |t              r&	 t        |      }t!        |      }|dk(  r||	k  S ||	kD  S t        d      |t&        v r	 t)        |      }|t.        v rH	 t)        |      }|dk(  r||k(  S |dk(  r||k7  S |dk(  r||kD  S |dk(  r||k\  S |dk(  r||k  S |d k(  r||k  S |d!k(  r(	 t1        t        |            \  }}||cxk  xr |k  S c S |d#k(  r(	 t3        t        |            \  }}||cxk  xr |k  S c S |d%k(  r(	 t5        t        |            \  }}||cxk  xr |k  S c S t        d|       # t        $ r Y Sw xY w# t        $ r}
t        d      |
d }
~
ww xY w# t        $ r t        d      w xY w# t*        t,        f$ r t        d| d      w xY w# t*        t,        f$ r t        d| d      w xY w# t*        t,        f$ r t        d| d"      w xY w# t*        t,        f$ r t        d| d$      w xY w# t*        t,        f$ r t        d| d&      w xY w)'Nr6   re   r   rd   zUnknown operator z5can't match properties without a given property valuer   z/can't match properties with operator is_not_setF)r   r
   c                     t        | t              r@t        |      j                         | D cg c]  }t        |      j                          c}v S t	        j
                  | |      S c c}w N)r}   listr~   casefoldr   str_iequals)rd   override_valuevals      r   compute_exact_matchz+match_property.<locals>.compute_exact_match  se    %&>*33538:38CCH%%'5:   $$UN;;:s    A'r   r   r   r   r    r!   c                 n    |dk(  r| |kD  S |dk(  r| |k\  S |dk(  r| |k  S |dk(  r| |k  S t        d|       )Nr"   r#   r$   r%   zInvalid operator: )
ValueError)lhsrhsre   s      r   comparezmatch_property.<locals>.compare  s]    4Sy U"cz!T!Sy U"cz! #5hZ!@AAr   r&   z.The date set on the flag is not a valid formatr'   z'The date provided is not a valid formatz1The date provided must be a string or date objectzPerson property value 'z' is not a valid semverzFlag semver value 'r)   r*   r+   r,   r-   r.   r/   z!' is not valid for tilde operatorr0   z!' is not valid for caret operatorr1   z$' is not valid for wildcard operator)rU   PROPERTY_OPERATORSr3   NONE_VALUES_ALLOWED_OPERATORSr   str_icontainsr   r~   recompilesearchfloat	Exceptionr}   -relative_date_parse_for_feature_flag_matchingparse_datetimer   datetimedateSEMVER_OPERATORSparse_semverr   	TypeErrorSEMVER_COMPARISON_OPERATORS_tilde_bounds_caret_bounds_wildcard_bounds)rm   property_valuesr6   re   rd   r   r   r   parsed_valueparsed_daterv   override_dateoverride_parsedflag_parsedloweruppers                   r   r   r     s    ,,u
C||J'27HLL!E))$'8
%CDD
/!$C
 	
 <$%VWW$S)N55>;Q&&	< w&un==*5.AAA8o%%;"">599?"&&~u===73u:& O

3u:&--c..AB$N	

 ;3u:& K

3u:&--c..ABdJ	

 --
	B 	 <L #(B.#.~s5z8DD~|XFF3~.E
HEE66		GE
SK,SZ87D (@  nh&7&785nEM++${22${226++%(8(8(:::%(8(8(:::,X .~ > 9- H//(;66(;66 )C  ##	*>:O 22*51 ;&&+55\)&+55[(&44\)&+55[(&44\)&+55',SZ8u
 O3e3333',SZ8u
 O3e3333**/E
;u
 O3e3333 !#4XJ!?
@@a  		$  	(@	:  X,-VWWX I& 	().)99PQ 	 	* ,)%0GH * 	* ,)%0QR  	* ,)%0QR  	* ,)%0TU sx   O )5O. 5P P .P# Q Q' <R	 )R+ 	O+*O+.	P7PPP #QQ$'R	R(+S
c           	          t        | j                  d            }||vrt        d| d      ||   }t        |||||||      S )Nrd   zcohort zT not found in local cohorts - likely a static cohort that requires server evaluationr   )r~   rU   r5   match_property_group)	rm   r   r`   ra   rb   rn   rc   	cohort_idproperty_groups	            r   r   r     sh    $ HLL)*I))&i[ tu
 	
 'y1N r   c           
      ,   | sy| j                  d      }| j                  d      }|rt        |      dk(  ryd}	d|d   v r9|D ]"  }
	 t        |
||||||      }|dk(  r|s y|r y$ |	rt	        d
      |dk(  S |D ]  }
	 |
j                  d      dk(  rt        |
||||||      }n3|
j                  d      dk(  rt        |
||||||      }nt        |
|      }|
j                  dd      }|dk(  r|s|s y|r|r y|r|s y|s|r y |	rt	        d      |dk(  S # t        $ r  t        $ r(}t
        j                  d|
 d	|        d}	Y d }~d }~ww xY w# t        $ r  t        $ r(}t
        j                  d|
 d	|        d}	Y d }~d }~ww xY w)NTr   valuesr   Fr   ANDzFailed to compute property z
 locally: z8Can't match cohort without a given cohort property valuer   rL   negationz8can't match cohort without a given cohort property value)
rU   rg   r   r5   r3   rh   ri   r   r{   r   )r   r   r`   ra   rb   rn   rc   property_group_typero   error_matching_locallyr   r   rv   r   s                 r   r   r     s    (,,V4##H-JZA-":a= D..#% $' '%/"$ ## 2 "(J  #e++ D+.88F#x/*')$(#"+G XXf%/6$(#')"+G -T?CG88J6&%/"8$8$ x#"x#M \ "(J 
 #e++G , ) .		7vZsKL)-&.f , ) .		7vZsKL)-&.sI   D!D?A5E6E<EEE.EEF+FFrd   c                    | j                         }|j                  d      r	|d d dz   }n|j                         j                  d      r	|d d dz   }nht        j                  d|      rRt
        j
                  j                         }t        j
                  t        |      |j                  |j                        S t        j                  dd|      }t
        j
                  j                  |      S )	NZz+00:00z UTCz\d{4}z ([+-]\d{2}:\d{2})$z\1)stripendswithr   r   	fullmatchr   nowr>   monthdaysubfromisoformat)rd   textr   s      r   r   r   $  s    ;;=D}}SCRy8#			v	&CRy8#	h	%##%  TCIIsww??66(%6D**400r   dtmonthsc                     | j                   dz  | j                  z   dz
  |z
  }|dz  }|dz  dz   }d|cxk  rdk  sy  y t        | j                  t	        j
                  ||      d         }| j                  |||      S )N      '  )yearr   r   )r   r   minr   calendar
monthrangereplace)r   r   month_indexr   r   r   s         r   _subtract_monthsr   4  s    ''B,)A-6K"D"q E 
bffh))$6q9
:C::4u#:66r   yearsc                     | j                   |z
  }d|cxk  rdk  sy  y t        | j                  t        j                  || j
                        d         }| j                  ||      S )Nr   r   )r   r   )r   r   r   r   r   r   r   )r   r   r   r   s       r   _subtract_yearsr   >  s`    77U?D 
bffh))$9!<
=C::4S:))r   c                    d}t        j                  ||       }t        j                  j                  t        j                  j
                        }|rt        |j                  d            }|dk\  ry |j                  d      }|dk(  r|t        j                  |      z
  }|S |dk(  r|t        j                  |      z
  }|S |d	k(  r|t        j                  |
      z
  }|S |dk(  rt        ||      S |dk(  rt        ||      S y y )Nz)^-?(?P<number>[0-9]+)(?P<interval>[a-z])$numberi'  intervalh)hoursd)daysw)weeksmy)r   r   r   r   timezoneutcr>   group	timedeltar   r   )rd   r   r   	parsed_dtr   r   s         r   r   r   F  s    9EIIeU#E!!%%h&7&7&;&;<IU[[*+V;;z*s?!H$6$6V$DDI  _!H$6$6F$CCI  _!H$6$6V$DDI  _#Iv66_"9f55 r   partc                     | r| j                         st        d|  d      t        |       dkD  r| d   dk(  rt        d|  d      t        |       S )Nz$Invalid semver numeric identifier: 'r]   r   r   0z-Semver numeric identifier has leading zero: ')isdigitr   rg   r>   )r  s    r   _semver_numeric_identifierr	  f  sV    t||~?vQGHH
4y1}aCHaPQQt9r   c                    t        |       j                         j                  d      }|j                  d      d   j                  d      d   }|j                  d      }|r|d   st	        d      t        |d         }t        |      dkD  r|d   rt        |d         nd}t        |      dkD  r|d   rt        |d         nd}|||fS )	ux  Parse a semver string into a comparable (major, minor, patch) integer tuple.

    Matches the behavior of the sortableSemver HogQL function:
    - Handles v-prefix, whitespace, pre-release suffixes
    - Defaults missing components to 0 (e.g., 1.2 -> 1.2.0)
    - Rejects numeric identifiers with leading zeros per semver 2.0.0 §2
    Raises ValueError if parsing fails.
    vV-r   +r;   zInvalid semver formatr   r   )r~   r   lstripsplitr   r	  rg   )rd   r   partsmajorminorpatchs         r   r   r   o  s     u:$$T*D::c?1##C(+DJJsOEa011&uQx0E47JNuQx&uQx0UVE47JNuQx&uQx0UVE5%  r   c                 :    t        |       \  }}}|||f||dz   dffS )z9~1.2.3 means >=1.2.3 <1.3.0 (allows patch-level changes).r   r   r   )rd   r  r  r  s       r   r   r     s0    &u-E5%5% 5%!)Q"777r   c                     t        |       \  }}}|||f}|dkD  r|dz   ddf}||fS |dkD  rd|dz   df}||fS dd|dz   f}||fS )zCaret follows semver spec:
    ^1.2.3 means >=1.2.3 <2.0.0
    ^0.2.3 means >=0.2.3 <0.3.0
    ^0.0.3 means >=0.0.3 <0.0.4
    r   r   r  )rd   r  r  r  r   r   s         r   r   r     s     'u-E5%E5!EqyAq! %< 
EAIq! %< Auqy!%<r   c                 >   t        |       j                         j                  d      j                  dd      j	                  d      }|st        d      |j                  d      D cg c]  }|s|	 }}|st        d      t        |      dk(  rt        |d         }|ddf|dz   ddffS t        |      dk(  r)t        |d         t        |d         }}||df||dz   dffS t        |d         }t        |d         }t        |d         }|||f|||dz   ffS c c}w )	zSWildcard matching:
    1.* means >=1.0.0 <2.0.0
    1.2.* means >=1.2.0 <1.3.0
    r  *r   r;   zInvalid wildcard patternr   r   r   )	r~   r   r  r   rstripr   r  rg   r	  )rd   cleanedpr  r  r  r  s          r   r   r     sB   
 %j ''-55c2>EEcJG344c*0*1aQ*E0344
5zQ*584q!}uqy!Q///	Uq&uQx0&uQx0  ua 5%!)Q"777*584*584*584ue$ueUQY&???# 1s   (D0D)r   r   )NN)NNNN):r   r   r?   loggingr   r   enumr   typingr   r	   r   posthog.typesr   posthog.utilsr   r   r   rC   	getLoggerrh   r   r   EQUALITY_OPERATORSSTRING_OPERATORSNUMERIC_OPERATORSDATE_OPERATORSr   SEMVER_RANGE_OPERATORSr   r   r   r3   r5   r~   rF   rN   rK   r{   rl   rj   rk   r   r   r   r   r   r   r>   r   r   r   r	  tupler   r   r   r   r   r   r   <module>r(     s       	     # C()g	"!)
 
2T 
2 A G . 4  M .1GG    	 	Y 			y 		 %s %S % %U %, DND6 n nn 3  3  3 l|A |AF ! 
!P l, 
l,^1# 1("3"3 1 7** 7C 7HXEVEV<W 7*)) *# *(8CTCT:U *h @S S ! ! !08 8 8  &@C @E @r   