o
    3iw                  	   @   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 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d	Zd
gZdZdZdZdZdZdZee Zee e e e ZG dd deZ G dd deZ!d=de"de"de"defddZ#dd Z$dd Z%	d>d d!Z&d"d# Z'd>d$d%Z(dddddd&defd'd(Z)		d?dd)de*fd*d+Z+de*fd,d-Z,				d@de*fd.d/Z-				d@de*fd0d1Z.d2e"dee j  fd3d4Z/d2e"de0fd5d6Z1d2e"de0fd7d8Z2d2e"de0fd9d:Z3d2e"de0fd;d<Z4dS )A    N)Optional)parser)relativedelta)utils)	FlagValue)convert_to_datetime_awareis_valid_regexl   posthogis_not)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                   @   s   e Zd ZdS )InconclusiveMatchErrorN)__name__
__module____qualname__ r'   r'   c/lsinfo/ai/hellotax_ai/llm_service/venv_embed/lib/python3.10/site-packages/posthog/feature_flags.pyr#   .   s    r#   c                   @   s   e Zd ZdZdS )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&   __doc__r'   r'   r'   r(   r)   2   s    r)    keybucketing_valuesaltreturnc                 C   s<   |  d| | }t t|d d d d}|t S )N.zutf-8      )inthashlibsha1encode	hexdigest__LONG_SCALE__)r,   r-   r.   hash_keyhash_valr'   r'   r(   _hashB   s   "r;   c                 C   sH   t | d |dd}t| D ]}||d kr!||d k r!|d   S qd S )Nr,   variant)r.   	value_min	value_max)r;   variant_lookup_table)flagr-   
hash_valuer<   r'   r'   r(   get_matching_variantH   s   rB   c                 C   sb   g }d}|  dp
i  dpi  dpg }|D ]}||d d  }||||d d |}q|S )	Nr   filtersmultivariatevariantsrollout_percentaged   r,   )r=   r>   r,   )getappend)feature_flaglookup_tabler=   multivariatesr<   r>   r'   r'   r(   r?   P   s   r?   c                 C   s  |du s|du rt d| dd dd| vr$t d| dd d| d }t|d	krEtd
| d  t d| dd d|D ]}||vr||}	|	s`d||< t d| d|	dsjd||< nGz+|	dpqi }
|
d}|dur~|}nt|	||}t|	|||||||d}|||< W n t y } zd||< t d| d| |d}~ww || }|du rt d| d|s dS qG| d}| d}| dd}|r|dur||}|du rt d| d|dkrt||S t d| dd d| ddS )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 'r,   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activeFrC   aggregation_group_type_indexcohort_propertiesflags_by_keyevaluation_cache	device_idr-   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)r#   rH   lenlogdebugresolve_bucketing_valuematch_feature_flag_propertiesmatches_dependency_value)propertyrT   rU   distinct_id
propertiesrS   rV   rN   dep_flag_keydep_flagdep_flag_filters dep_aggregation_group_type_indexdep_bucketing_value
dep_resultecached_resultflag_keyexpected_valuerX   actual_valuer'   r'   r(   evaluate_flag_dependency_   s   










rn   c                 C   sZ   t |trt|dkrt | tr| S t | tr|| kS dS t |tr+t | tr+|| kS dS )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strrZ   bool)rl   rm   r'   r'   r(   r_      s   

r_   c                 C   s>   |  dpi }|  dp| 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.
    rC   bucketing_identifierrV   z;Flag requires device_id for bucketing but none was provided)rH   r#   )r@   ra   rV   flag_filtersrr   r'   r'   r(   r]     s   	r]   rR   c                C   s  |d u rt jdtdd t| ||}| dpi }|dpg }	d}
|p%i }|dp,i dp1g }d	d
 |D }|	D ]=}z)t| ||||||||d	re|d}|rY||v rY|}nt| |}|padW   S W q; tyn     tyx   d}
Y q;w |
rtddS )NzCalling match_feature_flag_properties() without bucketing_value is deprecated. Pass bucketing_value explicitly. This fallback will be removed in a future major release.   )
stacklevelrC   groupsFrD   rE   c                 S   s   g | ]}|d  qS )r,   r'   ).0r<   r'   r'   r(   
<listcomp>8      z1match_feature_flag_properties.<locals>.<listcomp>)r-   rV   r<   TzGCan't determine if feature flag is enabled or not with given properties)	warningswarnDeprecationWarningr]   rH   is_condition_matchrB   r)   r#   )r@   ra   rb   rS   rT   rU   rV   r-   rs   flag_conditionsis_inconclusiveflag_variantsvalid_variant_keys	conditionvariant_overrider<   r'   r'   r(   r^     sT   

r^   rV   c             
   C   s   | d}	t| dpg dkrM| dD ]1}
|
 d}|dkr,t|
||||||d}n|dkr<t|
||||||d}nt|
|}|sF dS q|	d u rMd	S |	d ur^t| d
 ||	d kr^dS d	S )NrF   rb   r   typecohortr   r@   FTr,   rG   )rH   rZ   match_cohortrn   match_propertyr;   )rJ   ra   r   rb   rS   rT   rU   r-   rV   rF   propproperty_typematchesr'   r'   r(   r}   a  sJ   

	


r}   c              
   C   s  |  d}|  dpd}|  d}|tvrtd| ||vr$td|dkr,td|| }|tvr:|d u r:d	S |d
v rQdd }|dkrK|||S ||| S |dkrY||v S |dkrct||S |dkrnt|| S |dkrtt|ot	t|
t|d uS |dkrtt|ot	t|
t|d u S |dv rdd }d }zt|}W n	 ty   Y nw |d ur|d urt|tr||t||S ||||S |t|t||S |dv rpztt|}	|	stt|}	t|	}	W n ty	 }
 ztd|
d }
~
ww |	stdt|tjr)t|}|dkr%||	k S ||	kS t|tjrA|dkr;||	 k S ||	 kS t|trlzt|}t|}|dkr[||	k W S ||	kW S  tyk   tdw td|tv rpzt|}W n ttfy   td| dw |tv rzt|}W n ttfy   td| dw |dkr||kS |dkr||kS |dkr||kS |d kr||kS |d!kr||k S |d"kr||kS n|d#krz
tt|\}}W n ttfy   td| d$w ||  ko|k S   S |d%krAz
tt|\}}W n ttfy3   td| d&w ||  ko>|k S   S |d'krpz
tt|\}}W n ttfyb   td| d(w ||  kom|k S   S td| ))Nr,   rX   r   rW   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                 S   s0   t | trt| dd | D v S t| |S )Nc                 S   s   g | ]}t | qS r'   )rp   casefold)rw   valr'   r'   r(   rx     s    z?match_property.<locals>.compute_exact_match.<locals>.<listcomp>)ro   listrp   r   r   str_iequals)rW   override_valuer'   r'   r(   compute_exact_match  s
   
z+match_property.<locals>.compute_exact_matchr   r   r   r   r   r   c                 S   sN   |dkr| |k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rhsrX   r'   r'   r(   compare  s   zmatch_property.<locals>.comparer   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 operatorr!   z!' is not valid for caret operatorr"   z$' is not valid for wildcard operator)rH   PROPERTY_OPERATORSr#   NONE_VALUES_ALLOWED_OPERATORSr   str_icontainsr   rp   recompilesearchfloat	Exceptionro   -relative_date_parse_for_feature_flag_matchingr   parser   datetimedateSEMVER_OPERATORSparse_semverr   	TypeErrorSEMVER_COMPARISON_OPERATORS_tilde_bounds_caret_bounds_wildcard_bounds)r`   property_valuesr,   rX   rW   r   r   r   parsed_valueparsed_dateri   override_dateoverride_parsedflag_parsedlowerupperr'   r'   r(   r     s   


























r   c           	   	   C   sD   t | d}||vrtd| d|| }t|||||||dS )NrW   zcohort zT not found in local cohorts - likely a static cohort that requires server evaluationr   )rp   rH   r)   match_property_group)	r`   r   rS   rT   rU   ra   rV   	cohort_idproperty_groupr'   r'   r(   r   T  s   
r   c                 C   s   | sdS |  d}|  d}|rt|dkrdS d}	d|d v rs|D ]F}
zt|
||||||d}|dkr;|s:W  dS n|rAW  dS W q" tyJ     tyh } ztd|
 d	|  d}	W Y d }~q"d }~ww |	rotd
|dkS |D ]}
zX|
 ddkrt|
||||||d}n|
 ddkrt|
||||||d}nt	|
|}|
 dd}|dkr|s|sW  dS |r|rW  dS n|r|sW  dS |s|rW  dS W qu ty     ty } ztd|
 d	|  d}	W Y d }~qud }~ww |	rtd|dkS )NTr   valuesr   Fr   ANDzFailed to compute property z
 locally: z8Can't match cohort without a given cohort property valuer   r@   negationz8can't match cohort without a given cohort property value)
rH   rZ   r   r)   r#   r[   r\   r   rn   r   )r   r   rS   rT   rU   ra   rV   property_group_typerb   error_matching_locallyr   r   ri   r   r'   r'   r(   r   x  s   	

		

r   rW   c                 C   s   d}t || }tjtjj}|rgt|d}|dkrd S |d}|dkr1|t|d }|S |dkr>|t|d }|S |d	krK|t|d
 }|S |dkrX|t|d }|S |dkre|t|d }|S d S d S )Nz)^-?(?P<number>[0-9]+)(?P<interval>[a-z])$numberi'  intervalh)hoursd)daysw)weeksm)monthsy)years)	r   r   r   nowtimezoneutcr3   groupr   )rW   r   match	parsed_dtr   r   r'   r'   r(   r     s2   

r   c                 C   s   t |  d}|dd dd }|d}|r |d s$tdt|d }t|dkr:|d r:t|d nd}t|dkrL|d rLt|d nd}|||fS )	a.  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)
    Raises ValueError if parsing fails.
    vV-r   +r0   zInvalid semver format   rt   )rp   striplstripsplitr   r3   rZ   )rW   textpartsmajorminorpatchr'   r'   r(   r     s   
$$
r   c                 C   s&   t | \}}}|||f||d dffS )z9~1.2.3 means >=1.2.3 <1.3.0 (allows patch-level changes).r   r   r   )rW   r   r   r   r'   r'   r(   r     s   r   c                 C   sj   t | \}}}|||f}|dkr|d ddf}||fS |dkr*d|d df}||fS dd|d 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   )rW   r   r   r   r   r   r'   r'   r(   r   $  s   
r   c                 C   s   t |  dddd}|stddd |dD }|s&tdt|dkr>t|d	 }|d	d	f|d d	d	ffS t|d
kr]t|d	 t|d }}||d	f||d d	ffS t|d	 t|d t|d
 }}}|||f|||d ffS )zSWildcard matching:
    1.* means >=1.0.0 <2.0.0
    1.2.* means >=1.2.0 <1.3.0
    r   *r+   r0   zInvalid wildcard patternc                 S   s   g | ]}|r|qS r'   r'   )rw   pr'   r'   r(   rx   @  ry   z$_wildcard_bounds.<locals>.<listcomp>r   r   rt   )	rp   r   r   replacerstripr   r   rZ   r3   )rW   cleanedr   r   r   r   r'   r'   r(   r   7  s    (r   )r+   )N)NN)NNNN)5r   r4   loggingr   rz   typingr   dateutilr   dateutil.relativedeltar   r	   r   posthog.typesr   posthog.utilsr   r   r   r8   	getLoggerr[   r   EQUALITY_OPERATORSSTRING_OPERATORSNUMERIC_OPERATORSDATE_OPERATORSr   SEMVER_RANGE_OPERATORSr   r   r   r#   r)   rp   r;   rB   r?   rn   r_   r]   r^   rq   r}   r   r   r   r   tupler   r   r   r   r'   r'   r'   r(   <module>   s    
	
 
"

I

4 D
(
o
 