flagsmith 5.3.0__tar.gz → 5.4.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.
Files changed (23) hide show
  1. {flagsmith-5.3.0 → flagsmith-5.4.0}/PKG-INFO +1 -1
  2. flagsmith-5.4.0/flagsmith/__init__.py +6 -0
  3. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/analytics.py +54 -56
  4. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/flagsmith.py +91 -30
  5. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/models.py +1 -37
  6. {flagsmith-5.3.0 → flagsmith-5.4.0}/pyproject.toml +1 -1
  7. flagsmith-5.3.0/flagsmith/__init__.py +0 -6
  8. {flagsmith-5.3.0 → flagsmith-5.4.0}/LICENSE +0 -0
  9. {flagsmith-5.3.0 → flagsmith-5.4.0}/README.md +0 -0
  10. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/api/__init__.py +0 -0
  11. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/api/types.py +0 -0
  12. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/exceptions.py +0 -0
  13. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/mappers.py +0 -0
  14. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/offline_handlers.py +0 -0
  15. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/polling_manager.py +0 -0
  16. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/py.typed +0 -0
  17. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/streaming_manager.py +0 -0
  18. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/types.py +0 -0
  19. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/utils/__init__.py +0 -0
  20. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/utils/datetime.py +0 -0
  21. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/utils/identities.py +0 -0
  22. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/version.py +0 -0
  23. {flagsmith-5.3.0 → flagsmith-5.4.0}/flagsmith/webhooks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flagsmith
3
- Version: 5.3.0
3
+ Version: 5.4.0
4
4
  Summary: Flagsmith Python SDK
5
5
  License: BSD3
6
6
  License-File: LICENSE
@@ -0,0 +1,6 @@
1
+ from flagsmith import webhooks
2
+ from flagsmith.analytics import EventProcessorConfig
3
+ from flagsmith.flagsmith import Flagsmith
4
+ from flagsmith.version import __version__
5
+
6
+ __all__ = ("Flagsmith", "EventProcessorConfig", "webhooks", "__version__")
@@ -2,7 +2,6 @@ import atexit
2
2
  import json
3
3
  import logging
4
4
  import threading
5
- import time
6
5
  import typing
7
6
  from dataclasses import dataclass
8
7
  from datetime import datetime
@@ -18,6 +17,10 @@ ANALYTICS_ENDPOINT: typing.Final[str] = "analytics/flags/"
18
17
  # Used to control how often we send data(in seconds)
19
18
  ANALYTICS_TIMER: typing.Final[int] = 10
20
19
 
20
+ FLAG_EXPOSURE_EVENT: typing.Final[str] = "$flag_exposure"
21
+
22
+ DEFAULT_EVENT_API_URL: typing.Final[str] = "https://events.api.flagsmith.com/"
23
+
21
24
  session = FuturesSession(max_workers=4)
22
25
 
23
26
 
@@ -72,92 +75,90 @@ class AnalyticsProcessor:
72
75
 
73
76
 
74
77
  @dataclass
75
- class PipelineAnalyticsConfig:
76
- analytics_server_url: str
78
+ class EventProcessorConfig:
79
+ events_api_url: str = DEFAULT_EVENT_API_URL
77
80
  max_buffer_items: int = 1000
78
81
  flush_interval_seconds: float = 10.0
79
82
 
80
83
 
81
- class PipelineAnalyticsProcessor:
84
+ class EventProcessor:
82
85
  """
83
- Buffered analytics processor that sends per-evaluation and custom events
84
- to the Flagsmith pipeline analytics endpoint in batches.
85
-
86
- Evaluation events are deduplicated within each flush window. Events are
87
- flushed periodically via a background timer or when the buffer is full.
86
+ Buffered event processor that batches custom events and POSTs them to the
87
+ Flagsmith event endpoint. Flushes on a background timer or when the buffer
88
+ fills.
88
89
  """
89
90
 
90
91
  def __init__(
91
92
  self,
92
- config: PipelineAnalyticsConfig,
93
+ config: EventProcessorConfig,
93
94
  environment_key: str,
94
95
  ) -> None:
95
- url = config.analytics_server_url
96
+ url = config.events_api_url
96
97
  if not url.endswith("/"):
97
98
  url = f"{url}/"
98
- self._batch_endpoint = f"{url}v1/analytics/batch"
99
+ self._batch_endpoint = f"{url}v1/events"
99
100
  self._environment_key = environment_key
100
101
  self._max_buffer = config.max_buffer_items
101
102
  self._flush_interval_seconds = config.flush_interval_seconds
102
103
 
103
104
  self._buffer: typing.List[typing.Dict[str, typing.Any]] = []
104
- self._dedup_keys: typing.Dict[str, str] = {}
105
105
  self._lock = threading.Lock()
106
106
  self._timer: typing.Optional[threading.Timer] = None
107
107
 
108
- def record_evaluation_event(
108
+ def track_event(
109
109
  self,
110
- flag_key: str,
111
- enabled: bool,
112
- value: typing.Any,
113
- identity_identifier: typing.Optional[str] = None,
110
+ event: str,
111
+ identifier: typing.Optional[str] = None,
112
+ value: typing.Optional[typing.Union[str, int, float, bool]] = None,
114
113
  traits: typing.Optional[typing.Dict[str, typing.Any]] = None,
114
+ metadata: typing.Optional[typing.Dict[str, typing.Any]] = None,
115
115
  ) -> None:
116
- fingerprint = f"{identity_identifier or 'none'}|{enabled}|{value}"
117
- should_flush = False
118
-
119
- with self._lock:
120
- if self._dedup_keys.get(flag_key) == fingerprint:
121
- return
122
- self._dedup_keys[flag_key] = fingerprint
123
- self._buffer.append(
124
- {
125
- "event_id": flag_key,
126
- "event_type": "flag_evaluation",
127
- "evaluated_at": int(time.time() * 1000),
128
- "identity_identifier": identity_identifier,
129
- "enabled": enabled,
130
- "value": value,
131
- "traits": dict(traits) if traits else None,
132
- "metadata": {"sdk_version": __version__},
133
- }
134
- )
135
- if len(self._buffer) >= self._max_buffer:
136
- should_flush = True
137
-
138
- if should_flush:
139
- self.flush()
116
+ self._buffer_event(
117
+ event=event,
118
+ feature_name=None,
119
+ identifier=identifier,
120
+ value=value,
121
+ traits=traits,
122
+ metadata=metadata,
123
+ )
140
124
 
141
- def record_custom_event(
125
+ def track_exposure_event(
142
126
  self,
143
- event_name: str,
144
- identity_identifier: typing.Optional[str] = None,
127
+ feature_name: str,
128
+ identifier: typing.Optional[str] = None,
129
+ value: typing.Optional[typing.Union[str, int, float, bool]] = None,
145
130
  traits: typing.Optional[typing.Dict[str, typing.Any]] = None,
146
131
  metadata: typing.Optional[typing.Dict[str, typing.Any]] = None,
147
132
  ) -> None:
148
- should_flush = False
133
+ self._buffer_event(
134
+ event=FLAG_EXPOSURE_EVENT,
135
+ feature_name=feature_name,
136
+ identifier=identifier,
137
+ value=value,
138
+ traits=traits,
139
+ metadata=metadata,
140
+ )
149
141
 
142
+ def _buffer_event(
143
+ self,
144
+ event: str,
145
+ feature_name: typing.Optional[str],
146
+ identifier: typing.Optional[str],
147
+ value: typing.Optional[typing.Union[str, int, float, bool]],
148
+ traits: typing.Optional[typing.Dict[str, typing.Any]],
149
+ metadata: typing.Optional[typing.Dict[str, typing.Any]],
150
+ ) -> None:
151
+ should_flush = False
150
152
  with self._lock:
151
153
  self._buffer.append(
152
154
  {
153
- "event_id": event_name,
154
- "event_type": "custom_event",
155
- "evaluated_at": int(time.time() * 1000),
156
- "identity_identifier": identity_identifier,
157
- "enabled": None,
158
- "value": None,
155
+ "event": event,
156
+ "feature_name": feature_name,
157
+ "identifier": identifier,
158
+ "value": str(value) if value is not None else None,
159
159
  "traits": dict(traits) if traits else None,
160
160
  "metadata": {**(metadata or {}), "sdk_version": __version__},
161
+ "timestamp": int(datetime.now().timestamp() * 1000),
161
162
  }
162
163
  )
163
164
  if len(self._buffer) >= self._max_buffer:
@@ -172,11 +173,8 @@ class PipelineAnalyticsProcessor:
172
173
  return
173
174
  events = self._buffer
174
175
  self._buffer = []
175
- self._dedup_keys.clear()
176
176
 
177
- payload = json.dumps(
178
- {"events": events, "environment_key": self._environment_key}
179
- )
177
+ payload = json.dumps({"events": events})
180
178
  try:
181
179
  future = session.post(
182
180
  self._batch_endpoint,
@@ -9,9 +9,10 @@ from requests.adapters import HTTPAdapter
9
9
  from urllib3 import Retry
10
10
 
11
11
  from flagsmith.analytics import (
12
+ FLAG_EXPOSURE_EVENT,
12
13
  AnalyticsProcessor,
13
- PipelineAnalyticsConfig,
14
- PipelineAnalyticsProcessor,
14
+ EventProcessor,
15
+ EventProcessorConfig,
15
16
  )
16
17
  from flagsmith.exceptions import FlagsmithAPIError, FlagsmithClientError
17
18
  from flagsmith.mappers import (
@@ -23,6 +24,7 @@ from flagsmith.mappers import (
23
24
  )
24
25
  from flagsmith.models import (
25
26
  DefaultFlag,
27
+ Flag,
26
28
  Flags,
27
29
  Segment,
28
30
  SegmentOverridesIndex,
@@ -74,7 +76,8 @@ class Flagsmith:
74
76
  environment_refresh_interval_seconds: typing.Union[int, float] = 60,
75
77
  retries: typing.Optional[Retry] = None,
76
78
  enable_analytics: bool = False,
77
- pipeline_analytics_config: typing.Optional[PipelineAnalyticsConfig] = None,
79
+ enable_events: bool = False,
80
+ event_processor_config: typing.Optional[EventProcessorConfig] = None,
78
81
  default_flag_handler: typing.Optional[
79
82
  typing.Callable[[str], DefaultFlag]
80
83
  ] = None,
@@ -100,6 +103,12 @@ class Flagsmith:
100
103
  Flagsmith API
101
104
  :param enable_analytics: if enabled, sends additional requests to the Flagsmith
102
105
  API to power flag analytics charts
106
+ :param enable_events: if enabled, starts an event processor that buffers
107
+ and sends events (custom and flag-exposure) to the Flagsmith events
108
+ API, powering experimentation analytics.
109
+ :param event_processor_config: optional configuration for the event
110
+ processor (URL override for self-hosted, buffer/flush tuning). Only
111
+ valid when ``enable_events=True``.
103
112
  :param default_flag_handler: callable which will be used in the case where
104
113
  flags cannot be retrieved from the API or a non-existent feature is
105
114
  requested
@@ -120,9 +129,7 @@ class Flagsmith:
120
129
  self.default_flag_handler = default_flag_handler
121
130
  self.enable_realtime_updates = enable_realtime_updates
122
131
  self._analytics_processor: typing.Optional[AnalyticsProcessor] = None
123
- self._pipeline_analytics_processor: typing.Optional[
124
- PipelineAnalyticsProcessor
125
- ] = None
132
+ self._event_processor: typing.Optional[EventProcessor] = None
126
133
  self.__evaluation_context: typing.Optional[SDKEvaluationContext] = None
127
134
  self._segment_overrides_index: SegmentOverridesIndex = {}
128
135
  self._environment_updated_at: typing.Optional[datetime] = None
@@ -140,6 +147,11 @@ class Flagsmith:
140
147
  "Can only use realtime updates when running in local evaluation mode."
141
148
  )
142
149
 
150
+ if event_processor_config is not None and not enable_events:
151
+ raise ValueError(
152
+ "event_processor_config can only be set when enable_events=True."
153
+ )
154
+
143
155
  if self.offline_handler:
144
156
  self._evaluation_context = map_environment_document_to_context(
145
157
  self.offline_handler.get_environment()
@@ -189,25 +201,35 @@ class Flagsmith:
189
201
  self._initialise_analytics(
190
202
  environment_key=environment_key,
191
203
  enable_analytics=enable_analytics,
192
- pipeline_analytics_config=pipeline_analytics_config,
204
+ )
205
+ self._initialise_events(
206
+ environment_key=environment_key,
207
+ enable_events=enable_events,
208
+ event_processor_config=event_processor_config,
193
209
  )
194
210
 
195
211
  def _initialise_analytics(
196
212
  self,
197
213
  environment_key: str,
198
214
  enable_analytics: bool,
199
- pipeline_analytics_config: typing.Optional[PipelineAnalyticsConfig],
200
215
  ) -> None:
201
216
  if enable_analytics:
202
217
  self._analytics_processor = AnalyticsProcessor(
203
218
  environment_key, self.api_url, timeout=self.request_timeout_seconds
204
219
  )
205
- if pipeline_analytics_config:
206
- self._pipeline_analytics_processor = PipelineAnalyticsProcessor(
207
- config=pipeline_analytics_config,
220
+
221
+ def _initialise_events(
222
+ self,
223
+ environment_key: str,
224
+ enable_events: bool,
225
+ event_processor_config: typing.Optional[EventProcessorConfig],
226
+ ) -> None:
227
+ if enable_events:
228
+ self._event_processor = EventProcessor(
229
+ config=event_processor_config or EventProcessorConfig(),
208
230
  environment_key=environment_key,
209
231
  )
210
- self._pipeline_analytics_processor.start()
232
+ self._event_processor.start()
211
233
 
212
234
  def _initialise_local_evaluation(self) -> None:
213
235
  # To ensure that the environment is set before allowing subsequent
@@ -324,21 +346,68 @@ class Flagsmith:
324
346
 
325
347
  return map_segment_results_to_identity_segments(evaluation_result["segments"])
326
348
 
349
+ def get_experiment_flag(
350
+ self,
351
+ feature_name: str,
352
+ identifier: str,
353
+ traits: typing.Optional[TraitMapping] = None,
354
+ ) -> typing.Union[DefaultFlag, Flag]:
355
+ """
356
+ Resolve a flag for an identity and record an exposure event.
357
+
358
+ Skips the exposure event when the resolved flag is a `DefaultFlag`
359
+ (i.e. the feature was not present and was served via the
360
+ `default_flag_handler`), to keep experimentation data clean.
361
+ """
362
+ if not self._event_processor:
363
+ raise ValueError("Events must be enabled to use experiment flags.")
364
+ flag = self.get_identity_flags(identifier, traits).get_flag(feature_name)
365
+ if not flag.is_default:
366
+ self.track_exposure_event(
367
+ feature_name=feature_name,
368
+ identifier=identifier,
369
+ value=flag.value,
370
+ traits=traits,
371
+ )
372
+ return flag
373
+
327
374
  def track_event(
328
375
  self,
329
- event_name: str,
330
- identity_identifier: typing.Optional[str] = None,
376
+ event: str,
377
+ identifier: typing.Optional[str] = None,
378
+ value: typing.Optional[typing.Union[str, int, float, bool]] = None,
331
379
  traits: typing.Optional[TraitMapping] = None,
332
380
  metadata: typing.Optional[typing.Dict[str, typing.Any]] = None,
333
381
  ) -> None:
334
- if not self._pipeline_analytics_processor:
382
+ if not self._event_processor:
383
+ raise ValueError("Events must be enabled to track events.")
384
+ if event.startswith("$") and event != FLAG_EXPOSURE_EVENT:
335
385
  raise ValueError(
336
- "Pipeline analytics is not configured. "
337
- "Provide pipeline_analytics_config to use track_event."
386
+ f'Event name "{event}" uses the reserved "$" prefix '
387
+ "but is not a known system event."
338
388
  )
339
- self._pipeline_analytics_processor.record_custom_event(
340
- event_name=event_name,
341
- identity_identifier=identity_identifier,
389
+ self._event_processor.track_event(
390
+ event=event,
391
+ identifier=identifier,
392
+ value=value,
393
+ traits=resolve_trait_values(traits),
394
+ metadata=metadata,
395
+ )
396
+
397
+ def track_exposure_event(
398
+ self,
399
+ feature_name: str,
400
+ identifier: typing.Optional[str] = None,
401
+ value: typing.Optional[typing.Union[str, int, float, bool]] = None,
402
+ traits: typing.Optional[TraitMapping] = None,
403
+ metadata: typing.Optional[typing.Dict[str, typing.Any]] = None,
404
+ ) -> None:
405
+ if not self._event_processor:
406
+ raise ValueError("Events must be enabled to track exposure events.")
407
+ self._event_processor.track_exposure_event(
408
+ feature_name=feature_name,
409
+ identifier=identifier,
410
+ value=value,
342
411
  traits=resolve_trait_values(traits),
343
412
  metadata=metadata,
344
413
  )
@@ -418,7 +487,6 @@ class Flagsmith:
418
487
  evaluation_result=evaluation_result,
419
488
  analytics_processor=self._analytics_processor,
420
489
  default_flag_handler=self.default_flag_handler,
421
- pipeline_analytics_processor=self._pipeline_analytics_processor,
422
490
  )
423
491
 
424
492
  def _get_identity_flags_from_document(
@@ -442,9 +510,6 @@ class Flagsmith:
442
510
  overrides_index=self._segment_overrides_index,
443
511
  analytics_processor=self._analytics_processor,
444
512
  default_flag_handler=self.default_flag_handler,
445
- pipeline_analytics_processor=self._pipeline_analytics_processor,
446
- identity_identifier=identifier,
447
- traits=resolve_trait_values(traits),
448
513
  )
449
514
 
450
515
  def _get_environment_flags_from_api(self) -> Flags:
@@ -456,7 +521,6 @@ class Flagsmith:
456
521
  api_flags=json_response,
457
522
  analytics_processor=self._analytics_processor,
458
523
  default_flag_handler=self.default_flag_handler,
459
- pipeline_analytics_processor=self._pipeline_analytics_processor,
460
524
  )
461
525
  except FlagsmithAPIError:
462
526
  if self.offline_handler:
@@ -489,9 +553,6 @@ class Flagsmith:
489
553
  api_flags=json_response["flags"],
490
554
  analytics_processor=self._analytics_processor,
491
555
  default_flag_handler=self.default_flag_handler,
492
- pipeline_analytics_processor=self._pipeline_analytics_processor,
493
- identity_identifier=identifier,
494
- traits=resolve_trait_values(traits),
495
556
  )
496
557
  except FlagsmithAPIError:
497
558
  if self.offline_handler:
@@ -525,5 +586,5 @@ class Flagsmith:
525
586
  if hasattr(self, "event_stream_thread"):
526
587
  self.event_stream_thread.stop()
527
588
 
528
- if self._pipeline_analytics_processor:
529
- self._pipeline_analytics_processor.stop()
589
+ if self._event_processor:
590
+ self._event_processor.stop()
@@ -6,7 +6,7 @@ from dataclasses import dataclass, field
6
6
  from flag_engine import engine
7
7
  from flag_engine.context.types import SegmentContext
8
8
 
9
- from flagsmith.analytics import AnalyticsProcessor, PipelineAnalyticsProcessor
9
+ from flagsmith.analytics import AnalyticsProcessor
10
10
  from flagsmith.exceptions import FlagsmithFeatureDoesNotExistError
11
11
  from flagsmith.types import (
12
12
  FeatureMetadata,
@@ -85,9 +85,6 @@ class Flags:
85
85
  flags: typing.Dict[str, Flag] = field(default_factory=dict)
86
86
  default_flag_handler: typing.Optional[typing.Callable[[str], DefaultFlag]] = None
87
87
  _analytics_processor: typing.Optional[AnalyticsProcessor] = None
88
- _pipeline_analytics_processor: typing.Optional[PipelineAnalyticsProcessor] = None
89
- _identity_identifier: typing.Optional[str] = None
90
- _traits: typing.Optional[typing.Dict[str, typing.Any]] = None
91
88
  # Lazy-evaluation state. When `_context` is set, `flags` is a
92
89
  # per-feature memo rather than a fully-materialised snapshot; unseen
93
90
  # features are resolved on demand via the engine primitives and
@@ -103,11 +100,6 @@ class Flags:
103
100
  evaluation_result: SDKEvaluationResult,
104
101
  analytics_processor: typing.Optional[AnalyticsProcessor],
105
102
  default_flag_handler: typing.Optional[typing.Callable[[str], DefaultFlag]],
106
- pipeline_analytics_processor: typing.Optional[
107
- PipelineAnalyticsProcessor
108
- ] = None,
109
- identity_identifier: typing.Optional[str] = None,
110
- traits: typing.Optional[typing.Dict[str, typing.Any]] = None,
111
103
  ) -> Flags:
112
104
  return cls(
113
105
  flags={
@@ -117,9 +109,6 @@ class Flags:
117
109
  },
118
110
  default_flag_handler=default_flag_handler,
119
111
  _analytics_processor=analytics_processor,
120
- _pipeline_analytics_processor=pipeline_analytics_processor,
121
- _identity_identifier=identity_identifier,
122
- _traits=traits,
123
112
  )
124
113
 
125
114
  @classmethod
@@ -129,11 +118,6 @@ class Flags:
129
118
  overrides_index: SegmentOverridesIndex,
130
119
  analytics_processor: typing.Optional[AnalyticsProcessor],
131
120
  default_flag_handler: typing.Optional[typing.Callable[[str], DefaultFlag]],
132
- pipeline_analytics_processor: typing.Optional[
133
- PipelineAnalyticsProcessor
134
- ] = None,
135
- identity_identifier: typing.Optional[str] = None,
136
- traits: typing.Optional[typing.Dict[str, typing.Any]] = None,
137
121
  ) -> Flags:
138
122
  """Build a lazy `Flags` backed by an evaluation context.
139
123
 
@@ -146,9 +130,6 @@ class Flags:
146
130
  flags={},
147
131
  default_flag_handler=default_flag_handler,
148
132
  _analytics_processor=analytics_processor,
149
- _pipeline_analytics_processor=pipeline_analytics_processor,
150
- _identity_identifier=identity_identifier,
151
- _traits=traits,
152
133
  _context=context,
153
134
  _overrides_index=overrides_index,
154
135
  )
@@ -159,11 +140,6 @@ class Flags:
159
140
  api_flags: typing.Sequence[typing.Mapping[str, typing.Any]],
160
141
  analytics_processor: typing.Optional[AnalyticsProcessor],
161
142
  default_flag_handler: typing.Optional[typing.Callable[[str], DefaultFlag]],
162
- pipeline_analytics_processor: typing.Optional[
163
- PipelineAnalyticsProcessor
164
- ] = None,
165
- identity_identifier: typing.Optional[str] = None,
166
- traits: typing.Optional[typing.Dict[str, typing.Any]] = None,
167
143
  ) -> Flags:
168
144
  flags = {
169
145
  flag_data["feature"]["name"]: Flag.from_api_flag(flag_data)
@@ -174,9 +150,6 @@ class Flags:
174
150
  flags=flags,
175
151
  default_flag_handler=default_flag_handler,
176
152
  _analytics_processor=analytics_processor,
177
- _pipeline_analytics_processor=pipeline_analytics_processor,
178
- _identity_identifier=identity_identifier,
179
- _traits=traits,
180
153
  )
181
154
 
182
155
  def all_flags(self) -> typing.List[Flag]:
@@ -252,15 +225,6 @@ class Flags:
252
225
  if self._analytics_processor and hasattr(flag, "feature_name"):
253
226
  self._analytics_processor.track_feature(flag.feature_name)
254
227
 
255
- if self._pipeline_analytics_processor and hasattr(flag, "feature_name"):
256
- self._pipeline_analytics_processor.record_evaluation_event(
257
- flag_key=flag.feature_name,
258
- enabled=flag.enabled,
259
- value=flag.value,
260
- identity_identifier=self._identity_identifier,
261
- traits=self._traits,
262
- )
263
-
264
228
  return flag
265
229
 
266
230
  def _resolve_flag(self, feature_name: str) -> Flag:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "flagsmith"
3
- version = "5.3.0"
3
+ version = "5.4.0"
4
4
  description = "Flagsmith Python SDK"
5
5
  authors = ["Flagsmith <support@flagsmith.com>"]
6
6
  license = "BSD3"
@@ -1,6 +0,0 @@
1
- from flagsmith import webhooks
2
- from flagsmith.analytics import PipelineAnalyticsConfig
3
- from flagsmith.flagsmith import Flagsmith
4
- from flagsmith.version import __version__
5
-
6
- __all__ = ("Flagsmith", "PipelineAnalyticsConfig", "webhooks", "__version__")
File without changes
File without changes
File without changes
File without changes