flagsmith 3.9.1__tar.gz → 3.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flagsmith
3
- Version: 3.9.1
3
+ Version: 3.10.0
4
4
  Summary: Flagsmith Python SDK
5
5
  License: BSD3
6
6
  Keywords: feature,flag,flagsmith,remote,config
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.10
14
14
  Classifier: Programming Language :: Python :: 3.11
15
15
  Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Programming Language :: Python :: 3.13
17
- Requires-Dist: flagsmith-flag-engine (>=5.1.0,<6.0.0)
17
+ Requires-Dist: flagsmith-flag-engine (>=6.0.2,<7.0.0)
18
18
  Requires-Dist: pydantic (>=2,<3)
19
19
  Requires-Dist: requests (>=2.32.3,<3.0.0)
20
20
  Requires-Dist: requests-futures (>=1.0.1,<2.0.0)
@@ -22,8 +22,6 @@ Requires-Dist: sseclient-py (>=1.8.0,<2.0.0)
22
22
  Project-URL: Documentation, https://docs.flagsmith.com
23
23
  Description-Content-Type: text/markdown
24
24
 
25
- <img width="100%" src="https://github.com/Flagsmith/flagsmith/raw/main/static-files/hero.png"/>
26
-
27
25
  # Flagsmith Python SDK
28
26
 
29
27
  > Flagsmith allows you to manage feature flags and remote config across multiple projects, environments and
@@ -1,5 +1,3 @@
1
- <img width="100%" src="https://github.com/Flagsmith/flagsmith/raw/main/static-files/hero.png"/>
2
-
3
1
  # Flagsmith Python SDK
4
2
 
5
3
  > Flagsmith allows you to manage feature flags and remote config across multiple projects, environments and
@@ -0,0 +1,5 @@
1
+ from flagsmith import webhooks
2
+ from flagsmith.flagsmith import Flagsmith
3
+ from flagsmith.version import __version__
4
+
5
+ __all__ = ("Flagsmith", "webhooks", "__version__")
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ import sys
2
3
  import typing
3
4
  from datetime import timezone
4
5
 
@@ -11,6 +12,7 @@ from flag_engine.identities.traits.models import TraitModel
11
12
  from flag_engine.identities.traits.types import TraitValue
12
13
  from flag_engine.segments.evaluator import get_identity_segments
13
14
  from requests.adapters import HTTPAdapter
15
+ from requests.utils import default_user_agent
14
16
  from urllib3 import Retry
15
17
 
16
18
  from flagsmith.analytics import AnalyticsProcessor
@@ -19,13 +21,24 @@ from flagsmith.models import DefaultFlag, Flags, Segment
19
21
  from flagsmith.offline_handlers import BaseOfflineHandler
20
22
  from flagsmith.polling_manager import EnvironmentDataPollingManager
21
23
  from flagsmith.streaming_manager import EventStreamManager, StreamEvent
22
- from flagsmith.types import JsonType, TraitConfig, TraitMapping
24
+ from flagsmith.types import (
25
+ ApplicationMetadata,
26
+ JsonType,
27
+ TraitConfig,
28
+ TraitMapping,
29
+ )
23
30
  from flagsmith.utils.identities import generate_identity_data
31
+ from flagsmith.version import __version__
24
32
 
25
33
  logger = logging.getLogger(__name__)
26
34
 
27
35
  DEFAULT_API_URL = "https://edge.api.flagsmith.com/api/v1/"
28
36
  DEFAULT_REALTIME_API_URL = "https://realtime.flagsmith.com/"
37
+ DEFAULT_USER_AGENT = (
38
+ f"flagsmith-python-client/{__version__} "
39
+ + default_user_agent()
40
+ + f" python/{sys.version_info.major}.{sys.version_info.minor}"
41
+ )
29
42
 
30
43
 
31
44
  class Flagsmith:
@@ -61,6 +74,7 @@ class Flagsmith:
61
74
  offline_mode: bool = False,
62
75
  offline_handler: typing.Optional[BaseOfflineHandler] = None,
63
76
  enable_realtime_updates: bool = False,
77
+ application_metadata: typing.Optional[ApplicationMetadata] = None,
64
78
  ):
65
79
  """
66
80
  :param environment_key: The environment key obtained from Flagsmith interface.
@@ -88,6 +102,7 @@ class Flagsmith:
88
102
  document from another source when in offline_mode. Works in place of
89
103
  default_flag_handler if offline_mode is not set and using remote evaluation.
90
104
  :param enable_realtime_updates: Use real-time functionality via SSE as opposed to polling the API
105
+ :param application_metadata: Optional metadata about the client application.
91
106
  """
92
107
 
93
108
  self.offline_mode = offline_mode
@@ -122,7 +137,11 @@ class Flagsmith:
122
137
 
123
138
  self.session = requests.Session()
124
139
  self.session.headers.update(
125
- **{"X-Environment-Key": environment_key}, **(custom_headers or {})
140
+ self._get_headers(
141
+ environment_key=environment_key,
142
+ application_metadata=application_metadata,
143
+ custom_headers=custom_headers,
144
+ )
126
145
  )
127
146
  self.session.proxies.update(proxies or {})
128
147
  retries = retries or Retry(total=3, backoff_factor=0.1)
@@ -261,7 +280,9 @@ class Flagsmith:
261
280
 
262
281
  traits = traits or {}
263
282
  identity_model = self._get_identity_model(identifier, **traits)
264
- segment_models = get_identity_segments(self._environment, identity_model)
283
+ segment_models = get_identity_segments(
284
+ environment=self._environment, identity=identity_model
285
+ )
265
286
  return [Segment(id=sm.id, name=sm.name) for sm in segment_models]
266
287
 
267
288
  def update_environment(self) -> None:
@@ -275,6 +296,24 @@ class Flagsmith:
275
296
  identity.identifier: identity for identity in overrides
276
297
  }
277
298
 
299
+ def _get_headers(
300
+ self,
301
+ environment_key: str,
302
+ application_metadata: typing.Optional[ApplicationMetadata],
303
+ custom_headers: typing.Optional[typing.Dict[str, typing.Any]],
304
+ ) -> typing.Dict[str, str]:
305
+ headers = {
306
+ "X-Environment-Key": environment_key,
307
+ "User-Agent": DEFAULT_USER_AGENT,
308
+ }
309
+ if application_metadata:
310
+ if name := application_metadata.get("name"):
311
+ headers["Flagsmith-Application-Name"] = name
312
+ if version := application_metadata.get("version"):
313
+ headers["Flagsmith-Application-Version"] = version
314
+ headers.update(custom_headers or {})
315
+ return headers
316
+
278
317
  def _get_environment_from_api(self) -> EnvironmentModel:
279
318
  environment_data = self._get_json_response(self.environment_url, method="GET")
280
319
  return EnvironmentModel.model_validate(environment_data)
@@ -1,7 +1,7 @@
1
1
  import typing
2
2
 
3
3
  from flag_engine.identities.traits.types import TraitValue
4
- from typing_extensions import TypeAlias
4
+ from typing_extensions import NotRequired, TypeAlias
5
5
 
6
6
  _JsonScalarType: TypeAlias = typing.Union[
7
7
  int,
@@ -23,3 +23,8 @@ class TraitConfig(typing.TypedDict):
23
23
 
24
24
 
25
25
  TraitMapping: TypeAlias = typing.Mapping[str, typing.Union[TraitValue, TraitConfig]]
26
+
27
+
28
+ class ApplicationMetadata(typing.TypedDict):
29
+ name: NotRequired[str]
30
+ version: NotRequired[str]
@@ -0,0 +1,3 @@
1
+ from importlib.metadata import version
2
+
3
+ __version__ = version("flagsmith")
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "flagsmith"
3
- version = "3.9.1"
3
+ version = "3.10.0"
4
4
  description = "Flagsmith Python SDK"
5
5
  authors = ["Flagsmith <support@flagsmith.com>"]
6
6
  license = "BSD3"
@@ -13,7 +13,7 @@ packages = [{ include = "flagsmith" }]
13
13
  python = ">=3.8.1,<4"
14
14
  requests = "^2.32.3"
15
15
  requests-futures = "^1.0.1"
16
- flagsmith-flag-engine = "^5.1.0"
16
+ flagsmith-flag-engine = "^6.0.2"
17
17
  sseclient-py = "^1.8.0"
18
18
  pydantic = "^2"
19
19
 
@@ -21,10 +21,11 @@ pydantic = "^2"
21
21
  optional = true
22
22
 
23
23
  [tool.poetry.group.dev.dependencies]
24
+ mypy = { version = "^1.16.1", python = ">=3.9,<4" }
24
25
  pytest = "^7.4.0"
25
26
  pytest-cov = "^4.1.0"
26
27
  pytest-mock = "^3.6.1"
27
- pre-commit = "^2.17.0"
28
+ pre-commit = { version = "^4.2.0", python = ">=3.9,<4" }
28
29
  responses = "^0.24.1"
29
30
  types-requests = "^2.32"
30
31
 
@@ -1,4 +0,0 @@
1
- from . import webhooks
2
- from .flagsmith import Flagsmith
3
-
4
- __all__ = ("Flagsmith", "webhooks")
File without changes
File without changes