2424# ended up having to do for the context.
2525class EvalResult :
2626 __slots__ = ['detail' , 'events' , 'big_segments_status' , 'big_segments_membership' ,
27- 'original_flag_key' , 'prereq_stack' , 'segment_stack' ]
27+ 'original_flag_key' , 'prereq_stack' , 'segment_stack' , 'depth' , 'prerequisites' ]
2828
2929 def __init__ (self ):
3030 self .detail = None
@@ -34,6 +34,12 @@ def __init__(self):
3434 self .original_flag_key = None # type: Optional[str]
3535 self .prereq_stack = None # type: Optional[List[str]]
3636 self .segment_stack = None # type: Optional[List[str]]
37+ self .depth = 0
38+ self .prerequisites = [] # type: List[str]
39+
40+ def record_prerequisite (self , key : str ):
41+ if self .depth == 0 :
42+ self .prerequisites .append (key )
3743
3844 def add_event (self , event : EventInputEvaluation ):
3945 if self .events is None :
@@ -48,7 +54,7 @@ class EvaluationException(Exception):
4854 def __init__ (self , message : str , error_kind : str = 'MALFORMED_FLAG' ):
4955 self ._message = message
5056 self ._error_kind = error_kind
51-
57+
5258 @property
5359 def message (self ) -> str :
5460 return self ._message
@@ -125,7 +131,7 @@ def _check_prerequisites(self, flag: FeatureFlag, context: Context, state: EvalR
125131 prereq_res = None
126132 if flag .prerequisites .count == 0 :
127133 return None
128-
134+
129135 try :
130136 # We use the state object to guard against circular references in prerequisites. To avoid
131137 # the overhead of creating the state.prereq_stack list in the most common case where
@@ -136,7 +142,7 @@ def _check_prerequisites(self, flag: FeatureFlag, context: Context, state: EvalR
136142 if state .prereq_stack is None :
137143 state .prereq_stack = []
138144 state .prereq_stack .append (flag_key )
139-
145+
140146 for prereq in flag .prerequisites :
141147 prereq_key = prereq .key
142148 if (prereq_key == state .original_flag_key or
@@ -145,11 +151,15 @@ def _check_prerequisites(self, flag: FeatureFlag, context: Context, state: EvalR
145151 ' this is probably a temporary condition due to an incomplete update' ) % prereq_key )
146152
147153 prereq_flag = self .__get_flag (prereq_key )
154+ state .record_prerequisite (prereq_key )
155+
148156 if prereq_flag is None :
149157 log .warning ("Missing prereq flag: " + prereq_key )
150158 failed_prereq = prereq
151159 else :
160+ state .depth += 1
152161 prereq_res = self ._evaluate (prereq_flag , context , state , event_factory )
162+ state .depth -= 1
153163 # Note that if the prerequisite flag is off, we don't consider it a match no matter what its
154164 # off variation was. But we still need to evaluate it in order to generate an event.
155165 if (not prereq_flag .on ) or prereq_res .variation_index != prereq .variation :
@@ -208,7 +218,7 @@ def _clause_matches_context(self, clause: Clause, context: Context, state: EvalR
208218 if segment is not None and self ._segment_matches_context (segment , context , state ):
209219 return _maybe_negate (clause , True )
210220 return _maybe_negate (clause , False )
211-
221+
212222 attr = clause .attribute
213223 if attr is None :
214224 return False
@@ -220,7 +230,7 @@ def _clause_matches_context(self, clause: Clause, context: Context, state: EvalR
220230 context_value = _get_context_value_by_attr_ref (actual_context , attr )
221231 if context_value is None :
222232 return False
223-
233+
224234 # is the attr an array?
225235 if isinstance (context_value , (list , tuple )):
226236 for v in context_value :
@@ -287,7 +297,7 @@ def _big_segment_match_context(self, segment: Segment, context: Context, state:
287297 # that as a "not configured" condition.
288298 state .big_segments_status = BigSegmentsStatus .NOT_CONFIGURED
289299 return False
290-
300+
291301 # A big segment can only apply to one context kind, so if we don't have a key for that kind,
292302 # we don't need to bother querying the data.
293303 match_context = context .get_individual_context (segment .unbounded_context_kind or Context .DEFAULT_KIND )
@@ -357,7 +367,7 @@ def _variation_index_for_context(flag: FeatureFlag, vr: VariationOrRollout, cont
357367 variations = rollout .variations
358368 if len (variations ) == 0 :
359369 return (None , False )
360-
370+
361371 bucket_by = None if rollout .is_experiment else rollout .bucket_by
362372 bucket = _bucket_context (
363373 rollout .seed ,
0 commit comments