From f3f73e30eaf2c8612e0952e0ff797f8c77c04fbb Mon Sep 17 00:00:00 2001 From: German Gomez-Herrero Date: Thu, 24 Apr 2025 15:58:04 +0200 Subject: [PATCH 1/2] Fix minor issues with test suite --- tests/test_config_manager.py | 2 +- tests/test_optimizely.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/test_config_manager.py b/tests/test_config_manager.py index 56674381..e0b4f500 100644 --- a/tests/test_config_manager.py +++ b/tests/test_config_manager.py @@ -509,7 +509,7 @@ def test_fetch_datafile__exception_polling_thread_failed(self, _): with mock.patch('requests.Session.get', return_value=test_response): project_config_manager = config_manager.PollingConfigManager(sdk_key=sdk_key, logger=mock_logger, - update_interval=12345678912345) + update_interval=300) project_config_manager.stop() diff --git a/tests/test_optimizely.py b/tests/test_optimizely.py index 1f4293cd..66126201 100644 --- a/tests/test_optimizely.py +++ b/tests/test_optimizely.py @@ -34,6 +34,11 @@ from optimizely.helpers.sdk_settings import OptimizelySdkSettings from . import base +import warnings +import urllib3 +# Suppress SystemTimeWarning from urllib3 +warnings.filterwarnings('ignore', category=urllib3.exceptions.SystemTimeWarning) + class OptimizelyTest(base.BaseTest): strTest = None @@ -3965,7 +3970,6 @@ def test_get_feature_variable__returns_default_value_if_no_variation(self): 'source_info': {}, }, ) - def test_get_feature_variable__returns_none_if_none_feature_key(self): """ Test that get_feature_variable_* returns None for None feature key. """ @@ -5557,3 +5561,4 @@ def test_send_odp_event__default_type_when_empty_string(self): mock_send_event.assert_called_with('fullstack', 'great', {'amazing': 'fantastic'}, {}) mock_logger.error.assert_not_called() + From 0b1846864e2c61f3f15211080f52db6fd136600a Mon Sep 17 00:00:00 2001 From: German Gomez-Herrero Date: Fri, 25 Apr 2025 07:42:49 +0200 Subject: [PATCH 2/2] Add no op event dispatcher --- README.md | 14 ++++++++++++++ optimizely/event_dispatcher.py | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/README.md b/README.md index e0aeafb6..c0b2d70e 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,20 @@ Each method is described below. config_manager=custom_config_manager ) + +### NoOpEventDispatcher + +If you are only interested in using Optimizely's [free feature flag](https://www.optimizely.com/products/feature-experimentation/free-feature-flagging/) feature you +should configure the SDK to not send any event to Optimizely's servers: + + from optimizely.event_dispatcher import NoOpEventDispatcher + + optimizely_client = optimizely.Optimizely( + sdk_key='your-sdk-key-here', + event_dispatcher=NoOpEventDispatcher() + ) + + ### PollingConfigManager The [PollingConfigManager](https://github.com/optimizely/python-sdk/blob/master/optimizely/config_manager.py#L150) asynchronously polls for diff --git a/optimizely/event_dispatcher.py b/optimizely/event_dispatcher.py index 767fbb7d..d1723f85 100644 --- a/optimizely/event_dispatcher.py +++ b/optimizely/event_dispatcher.py @@ -36,6 +36,18 @@ def dispatch_event(self, event: event_builder.Event) -> None: ... +class NoOpEventDispatcher: + """Event dispatcher that doesn't send any events to Optimizely's servers.""" + + def dispatch_event(self, event: event_builder.Event) -> None: + """No-op implementation that silently discards events. + + Args: + event: Event object that would normally be sent to Optimizely's servers. + """ + pass + + class EventDispatcher: @staticmethod