22import typing
33import uuid
44
5- from annotated_types import Ge , Le
5+ from annotated_types import Ge , Le , SupportsLt
66from pydantic import UUID4 , BaseModel , Field , model_validator
77from pydantic_collections import BaseCollectionModel
88from typing_extensions import Annotated
@@ -16,16 +16,16 @@ class FeatureModel(BaseModel):
1616 name : str
1717 type : str
1818
19- def __eq__ (self , other ) :
20- return self .id == other .id
19+ def __eq__ (self , other : object ) -> bool :
20+ return isinstance ( other , FeatureModel ) and self .id == other .id
2121
22- def __hash__ (self ):
22+ def __hash__ (self ) -> int :
2323 return hash (self .id )
2424
2525
2626class MultivariateFeatureOptionModel (BaseModel ):
2727 value : typing .Any
28- id : int = None
28+ id : typing . Optional [ int ] = None
2929
3030
3131class MultivariateFeatureStateValueModel (BaseModel ):
@@ -40,7 +40,7 @@ class FeatureSegmentModel(BaseModel):
4040
4141
4242class MultivariateFeatureStateValueList (
43- BaseCollectionModel [MultivariateFeatureStateValueModel ]
43+ BaseCollectionModel [MultivariateFeatureStateValueModel ] # type: ignore[misc,no-any-unimported]
4444):
4545 @staticmethod
4646 def _ensure_correct_percentage_allocations (
@@ -75,15 +75,15 @@ def append(
7575class FeatureStateModel (BaseModel , validate_assignment = True ):
7676 feature : FeatureModel
7777 enabled : bool
78- django_id : int = None
79- feature_segment : FeatureSegmentModel = None
78+ django_id : typing . Optional [ int ] = None
79+ feature_segment : typing . Optional [ FeatureSegmentModel ] = None
8080 featurestate_uuid : UUID4 = Field (default_factory = uuid .uuid4 )
8181 feature_state_value : typing .Any = None
8282 multivariate_feature_state_values : MultivariateFeatureStateValueList = Field (
8383 default_factory = MultivariateFeatureStateValueList
8484 )
8585
86- def set_value (self , value : typing .Any ):
86+ def set_value (self , value : typing .Any ) -> None :
8787 self .feature_state_value = value
8888
8989 def get_value (self , identity_id : typing .Union [None , int , str ] = None ) -> typing .Any :
@@ -113,18 +113,19 @@ def is_higher_segment_priority(self, other: "FeatureStateModel") -> bool:
113113
114114 """
115115
116- try :
117- return (
118- getattr (
119- self .feature_segment ,
120- "priority" ,
121- math .inf ,
116+ if other_feature_segment := other .feature_segment :
117+ if (
118+ other_feature_segment_priority := other_feature_segment .priority
119+ ) is not None :
120+ return (
121+ getattr (
122+ self .feature_segment ,
123+ "priority" ,
124+ math .inf ,
125+ )
126+ < other_feature_segment_priority
122127 )
123- < other .feature_segment .priority
124- )
125-
126- except (TypeError , AttributeError ):
127- return False
128+ return False
128129
129130 def _get_multivariate_value (
130131 self , identity_id : typing .Union [int , str ]
@@ -138,10 +139,14 @@ def _get_multivariate_value(
138139 # the percentage allocations of the multivariate options. This gives us a
139140 # way to ensure that the same value is returned every time we use the same
140141 # percentage value.
141- start_percentage = 0
142+ start_percentage = 0.0
143+
144+ def _mv_fs_sort_key (mv_value : MultivariateFeatureStateValueModel ) -> SupportsLt :
145+ return mv_value .id or mv_value .mv_fs_value_uuid
146+
142147 for mv_value in sorted (
143148 self .multivariate_feature_state_values ,
144- key = lambda v : v . id or v . mv_fs_value_uuid ,
149+ key = _mv_fs_sort_key ,
145150 ):
146151 limit = mv_value .percentage_allocation + start_percentage
147152 if start_percentage <= percentage_value < limit :
0 commit comments