Skip to content

Commit f74fd37

Browse files
authored
Merge pull request #116 from Flagsmith/release/3.0.0
Release 3.0.0
2 parents 1670282 + a25f0a6 commit f74fd37

File tree

7 files changed

+47
-9
lines changed

7 files changed

+47
-9
lines changed

flag_engine/environments/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class EnvironmentModel:
3838
project: ProjectModel
3939
feature_states: typing.List[FeatureStateModel] = field(default_factory=list)
4040
allow_client_traits: bool = True
41+
updated_at: datetime = field(default_factory=utcnow_with_tz)
4142

4243
amplitude_config: IntegrationModel = None
4344
segment_config: IntegrationModel = None

flag_engine/environments/schemas.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class BaseEnvironmentSchema(Schema):
3939
id = fields.Int()
4040
api_key = fields.Str()
4141
allow_client_traits = fields.Bool(required=False, default=True)
42+
updated_at = fields.DateTime()
4243

4344
segment_config = fields.Nested(IntegrationSchema, required=False, allow_none=True)
4445
heap_config = fields.Nested(IntegrationSchema, required=False, allow_none=True)

flag_engine/identities/models.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,25 @@ def composite_key(self) -> str:
2828
def generate_composite_key(env_key: str, identifier: str) -> str:
2929
return f"{env_key}_{identifier}"
3030

31-
def update_traits(self, traits: typing.List[TraitModel]) -> typing.List[TraitModel]:
31+
def update_traits(
32+
self, traits: typing.List[TraitModel]
33+
) -> typing.Tuple[typing.List[TraitModel], bool]:
3234
existing_traits = {trait.trait_key: trait for trait in self.identity_traits}
35+
traits_changed = False
3336

3437
for trait in traits:
35-
if trait.trait_value is None:
36-
existing_traits.pop(trait.trait_key, None)
37-
else:
38+
existing_trait = existing_traits.get(trait.trait_key)
39+
40+
if trait.trait_value is None and existing_trait:
41+
existing_traits.pop(trait.trait_key)
42+
traits_changed = True
43+
44+
elif getattr(existing_trait, "trait_value", None) != trait.trait_value:
3845
existing_traits[trait.trait_key] = trait
46+
traits_changed = True
3947

4048
self.identity_traits = list(existing_traits.values())
41-
return self.identity_traits
49+
return self.identity_traits, traits_changed
4250

4351
def prune_features(self, valid_feature_names: typing.List[str]) -> None:
4452
self.identity_features = IdentityFeaturesList(

flag_engine/projects/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ class ProjectModel:
1212
organisation: OrganisationModel
1313
hide_disabled_flags: bool
1414
segments: typing.List[SegmentModel] = field(default_factory=list)
15+
enable_realtime_updates: bool = False

flag_engine/projects/schemas.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class BaseProjectSchema(Schema):
1111
name = fields.Str()
1212
organisation = fields.Nested(OrganisationSchema)
1313
hide_disabled_flags = fields.Bool()
14+
enable_realtime_updates = fields.Bool()
1415

1516

1617
class ProjectSchema(LoadToModelMixin, BaseProjectSchema):

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name="flagsmith-flag-engine",
5-
version="2.3.0",
5+
version="3.0.0",
66
author="Flagsmith",
77
author_email="[email protected]",
88
packages=find_packages(include=["flag_engine", "flag_engine.*"]),

tests/unit/identities/test_identities_models.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,13 @@ def test_update_traits_remove_traits_with_none_value(identity_in_segment):
4444
trait_to_remove = TraitModel(trait_key=trait_key, trait_value=None)
4545

4646
# When
47-
updated_traits = identity_in_segment.update_traits([trait_to_remove])
47+
updated_traits, traits_updated = identity_in_segment.update_traits(
48+
[trait_to_remove]
49+
)
4850

4951
# Then
5052
assert identity_in_segment.identity_traits == updated_traits == []
53+
assert traits_updated is True
5154

5255

5356
def test_update_identity_traits_updates_trait_value(identity_in_segment):
@@ -57,25 +60,48 @@ def test_update_identity_traits_updates_trait_value(identity_in_segment):
5760
trait_to_update = TraitModel(trait_key=trait_key, trait_value=trait_value)
5861

5962
# When
60-
updated_traits = identity_in_segment.update_traits([trait_to_update])
63+
updated_traits, traits_updated = identity_in_segment.update_traits(
64+
[trait_to_update]
65+
)
6166

6267
# Then
6368
assert updated_traits == identity_in_segment.identity_traits
6469
assert len(identity_in_segment.identity_traits) == 1
6570
assert identity_in_segment.identity_traits[0] == trait_to_update
71+
assert traits_updated is True
6672

6773

6874
def test_update_traits_adds_new_traits(identity_in_segment):
6975
# Given
7076
new_trait = TraitModel(trait_key="new_key", trait_value="foobar")
7177

7278
# When
73-
updated_traits = identity_in_segment.update_traits([new_trait])
79+
updated_traits, traits_updated = identity_in_segment.update_traits([new_trait])
7480

7581
# Then
7682
assert updated_traits == identity_in_segment.identity_traits
7783
assert len(identity_in_segment.identity_traits) == 2
7884
assert new_trait in identity_in_segment.identity_traits
85+
assert traits_updated is True
86+
87+
88+
def test_update_traits_returns_false_if_traits_are_not_updated(identity_in_segment):
89+
# Given
90+
trait_key = identity_in_segment.identity_traits[0].trait_key
91+
trait_value = identity_in_segment.identity_traits[0].trait_value
92+
93+
trait_to_update = TraitModel(trait_key=trait_key, trait_value=trait_value)
94+
95+
# When
96+
updated_traits, traits_updated = identity_in_segment.update_traits(
97+
[trait_to_update]
98+
)
99+
100+
# Then
101+
assert updated_traits == identity_in_segment.identity_traits
102+
assert len(identity_in_segment.identity_traits) == 1
103+
assert identity_in_segment.identity_traits[0] == trait_to_update
104+
assert traits_updated is False
79105

80106

81107
def test_appending_feature_states_raises_duplicate_feature_state_if_fs_for_the_feature_already_exists(

0 commit comments

Comments
 (0)