44# license information.
55# -------------------------------------------------------------------------
66import logging
7- from typing import overload
7+ from typing import cast , overload , Any , Optional , Dict , Mapping , List
88from ._defaultfilters import TimeWindowFilter , TargetingFilter
99from ._featurefilters import FeatureFilter
10- from ._models import EvaluationEvent
10+ from ._models import EvaluationEvent , Variant , TargetingContext
1111from ._featuremanagerbase import (
1212 _get_feature_flag ,
1313 FeatureManagerBase ,
@@ -28,17 +28,17 @@ class FeatureManager(FeatureManagerBase):
2828 evaluated.
2929 """
3030
31- def __init__ (self , configuration , ** kwargs ):
31+ def __init__ (self , configuration : Mapping , ** kwargs : Dict [ str , Any ] ):
3232 super ().__init__ (configuration , ** kwargs )
33- filters = [TimeWindowFilter (), TargetingFilter ()] + kwargs .pop (PROVIDED_FEATURE_FILTERS , [])
33+ filters = [TimeWindowFilter (), TargetingFilter ()] + cast ( List , kwargs .pop (PROVIDED_FEATURE_FILTERS , []) )
3434
3535 for feature_filter in filters :
3636 if not isinstance (feature_filter , FeatureFilter ):
3737 raise ValueError ("Custom filter must be a subclass of FeatureFilter" )
3838 self ._filters [feature_filter .name ] = feature_filter
3939
40- @overload
41- def is_enabled (self , feature_flag_id , user_id , ** kwargs ) :
40+ @overload # type: ignore
41+ def is_enabled (self , feature_flag_id : str , user_id : str , ** kwargs : Dict [ str , Any ]) -> bool :
4242 """
4343 Determine if the feature flag is enabled for the given context.
4444
@@ -48,7 +48,7 @@ def is_enabled(self, feature_flag_id, user_id, **kwargs):
4848 :rtype: bool
4949 """
5050
51- def is_enabled (self , feature_flag_id , * args , ** kwargs ):
51+ def is_enabled (self , feature_flag_id : str , * args : Any , ** kwargs : Dict [ str , Any ]) -> bool : # type: ignore
5252 """
5353 Determine if the feature flag is enabled for the given context.
5454
@@ -59,13 +59,18 @@ def is_enabled(self, feature_flag_id, *args, **kwargs):
5959 targeting_context = self ._build_targeting_context (args )
6060
6161 result = self ._check_feature (feature_flag_id , targeting_context , ** kwargs )
62- if self ._on_feature_evaluated and result .feature .telemetry .enabled :
62+ if (
63+ self ._on_feature_evaluated
64+ and result .feature
65+ and result .feature .telemetry .enabled
66+ and callable (self ._on_feature_evaluated )
67+ ):
6368 result .user = targeting_context .user_id
6469 self ._on_feature_evaluated (result )
6570 return result .enabled
6671
67- @overload
68- def get_variant (self , feature_flag_id , user_id , ** kwargs ) :
72+ @overload # type: ignore
73+ def get_variant (self , feature_flag_id : str , user_id : str , ** kwargs : Dict [ str , Any ]) -> Optional [ Variant ] :
6974 """
7075 Determine the variant for the given context.
7176
@@ -75,7 +80,9 @@ def get_variant(self, feature_flag_id, user_id, **kwargs):
7580 :rtype: Variant
7681 """
7782
78- def get_variant (self , feature_flag_id , * args , ** kwargs ):
83+ def get_variant ( # type: ignore
84+ self , feature_flag_id : str , * args : Any , ** kwargs : Dict [str , Any ]
85+ ) -> Optional [Variant ]:
7986 """
8087 Determine the variant for the given context.
8188
@@ -87,13 +94,22 @@ def get_variant(self, feature_flag_id, *args, **kwargs):
8794 targeting_context = self ._build_targeting_context (args )
8895
8996 result = self ._check_feature (feature_flag_id , targeting_context , ** kwargs )
90- if self ._on_feature_evaluated and result .feature .telemetry .enabled :
97+ if (
98+ self ._on_feature_evaluated
99+ and result .feature
100+ and result .feature .telemetry .enabled
101+ and callable (self ._on_feature_evaluated )
102+ ):
91103 result .user = targeting_context .user_id
92104 self ._on_feature_evaluated (result )
93105 return result .variant
94106
95- def _check_feature_filters (self , evaluation_event , targeting_context , ** kwargs ):
107+ def _check_feature_filters (
108+ self , evaluation_event : EvaluationEvent , targeting_context : TargetingContext , ** kwargs : Dict
109+ ) -> None :
96110 feature_flag = evaluation_event .feature
111+ if not feature_flag :
112+ return
97113 feature_conditions = feature_flag .conditions
98114 feature_filters = feature_conditions .client_filters
99115
@@ -107,8 +123,8 @@ def _check_feature_filters(self, evaluation_event, targeting_context, **kwargs):
107123
108124 for feature_filter in feature_filters :
109125 filter_name = feature_filter [FEATURE_FILTER_NAME ]
110- kwargs ["user" ] = targeting_context .user_id
111- kwargs ["groups" ] = targeting_context .groups
126+ kwargs ["user" ] = targeting_context .user_id # type: ignore
127+ kwargs ["groups" ] = targeting_context .groups # type: ignore
112128 if filter_name not in self ._filters :
113129 raise ValueError (f"Feature flag { feature_flag .name } has unknown filter { filter_name } " )
114130 if feature_conditions .requirement_type == REQUIREMENT_TYPE_ALL :
@@ -119,7 +135,9 @@ def _check_feature_filters(self, evaluation_event, targeting_context, **kwargs):
119135 evaluation_event .enabled = True
120136 break
121137
122- def _check_feature (self , feature_flag_id , targeting_context , ** kwargs ):
138+ def _check_feature (
139+ self , feature_flag_id : str , targeting_context : TargetingContext , ** kwargs : Dict [str , Any ]
140+ ) -> EvaluationEvent :
123141 """
124142 Determine if the feature flag is enabled for the given context.
125143
0 commit comments