kameleoon-client-python 3.20.0__tar.gz → 3.22.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.
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/PKG-INFO +13 -13
- kameleoon_client_python-3.22.0/kameleoon/client_readiness/async_readiness.py +43 -0
- kameleoon_client_python-3.22.0/kameleoon/client_readiness/threading_readiness.py +134 -0
- kameleoon_client_python-3.22.0/kameleoon/events/__init__.py +19 -0
- kameleoon_client_python-3.22.0/kameleoon/events/data_file_update_event.py +33 -0
- kameleoon_client_python-3.22.0/kameleoon/events/data_file_update_handler.py +23 -0
- kameleoon_client_python-3.22.0/kameleoon/events/event_handler.py +13 -0
- kameleoon_client_python-3.22.0/kameleoon/events/event_manager.py +62 -0
- kameleoon_client_python-3.22.0/kameleoon/events/event_type.py +70 -0
- kameleoon_client_python-3.22.0/kameleoon/events/http_request_failure.py +70 -0
- kameleoon_client_python-3.22.0/kameleoon/events/http_request_handler.py +43 -0
- kameleoon_client_python-3.22.0/kameleoon/events/request_type.py +21 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/exceptions.py +18 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/kameleoon_client.py +170 -48
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/network_manager.py +6 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/network_manager_factory.py +2 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/network_manager_factory_impl.py +3 -2
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/network_manager_impl.py +7 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/automation_service_impl.py +2 -1
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/configuration_service_impl.py +4 -1
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/data_service_impl.py +5 -3
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/service_impl.py +43 -5
- kameleoon_client_python-3.20.0/kameleoon/real_time/real_time_configuration_service.py → kameleoon_client_python-3.22.0/kameleoon/real_time/real_time_event_service.py +27 -18
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/sdk_version.py +1 -1
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/unknown_condition.py +3 -3
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon_client_python.egg-info/PKG-INFO +13 -13
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon_client_python.egg-info/SOURCES.txt +10 -1
- kameleoon_client_python-3.20.0/kameleoon/client_readiness/async_readiness.py +0 -48
- kameleoon_client_python-3.20.0/kameleoon/client_readiness/threading_readiness.py +0 -44
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/MANIFEST.in +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/README.md +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/client_readiness/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/consent_blocking_behaviour.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/custom_data_info.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/data_file.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/experiment.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/feature_flag.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/me_group.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/rule.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/rule_type.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/settings.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/variable.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/variation.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/variation_by_exposition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/application_version.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/browser.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/cbscores.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/conversion.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/cookie.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/custom_data.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/data.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/device.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/geolocation.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/kcs_heat.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/assigned_variation.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/forced_experiment_variation.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/forced_feature_variation.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/forced_variation.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/legal_consent.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/page_view_visit.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/visitor.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/visitor_manager.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/visitor_slot.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/mapping_identifier.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/operating_system.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/page_view.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/personalization.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/targeted_segment.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/unique_identifier.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/user_agent.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/data/visitor_visits.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/defaults.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/domain.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/functions.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/hasher.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/logger.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/multi_threading.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/nonce.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/repeat_timer.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/scheduler.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/sem_version.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/string_utils.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/time.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/visitor_code.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/hybrid/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/hybrid/hybrid_manager.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/hybrid/hybrid_manager_impl.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/kameleoon_client_config.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/kameleoon_client_factory.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/logging/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/logging/kameleoon_logger.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/logging/log_level.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/logging/logger.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/asyncexec/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/asyncexec/async_executor.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/data/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/data/data_manager.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/evaluation/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/evaluation/evaluated_experiment.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/remote_data/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/remote_data/remote_data_manager.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/remote_data/remote_visitor_data.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/tracking/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/tracking/tracking_builder.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/tracking/tracking_manager.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/tracking/visitor_tracking_registry.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/warehouse/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/warehouse/warehouse_manager.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/middleware.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/access_token_source.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/access_token_source_factory.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/activity_event.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/cookie/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/cookie/cookie_manager.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/net_provider.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/net_provider_impl.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/query_builder.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/query_encodable.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/sendable.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/service_initialize_context.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/service_initialize_context_impl.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/automation_service.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/configuration_service.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/data_service.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/service.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/uri_helper.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/network/url_provider.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/real_time/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/real_time/real_time_event.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/storage/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/storage/cache.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/storage/cache_factory.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/storage/cache_factory_impl.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/storage/cache_impl.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/browser_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/constants.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/conversion_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/cookie_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/custom_datum.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/device_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/exclusive_experiment_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/geolocation_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/kcs_heat_range_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/number_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/operating_system_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/page_title_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/page_url_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/page_view_number_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/previous_page_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/sdk_language_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/segment_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/string_value_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/target_experiment_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/target_feature_flag_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/target_personalization_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/targeting_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/version_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/visit_number_today_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/visit_number_total_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/visitor_new_return_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/visitor_scope_condition.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/models.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/targeting_manager.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/tree_builder.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/tree_condition_factory.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/types/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/types/data_file.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/types/feature_flag.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/types/remote_visitor_data_filter.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/types/rule.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/types/variable.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon/types/variation.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon_client_python.egg-info/requires.txt +12 -12
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/setup.cfg +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/setup.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/apps.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/migrations/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/views.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/manage.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/proj/__init__.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/proj/asgi.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/proj/settings.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/proj/urls.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/proj/wsgi.py +0 -0
- {kameleoon_client_python-3.20.0 → kameleoon_client_python-3.22.0}/tests/resources/config.yml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kameleoon-client-python
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.22.0
|
|
4
4
|
Summary: Kameleoon Client Python Software Development Kit.
|
|
5
5
|
Home-page: https://developers.kameleoon.com/python-sdk.html
|
|
6
6
|
Author: Kameleoon
|
|
@@ -20,27 +20,27 @@ Requires-Dist: requests<3.0.0,>=2.25
|
|
|
20
20
|
Requires-Dist: sseclient-py<1.9.0,>=1.7.0
|
|
21
21
|
Requires-Dist: aiohttp<4.0.0,>=3.8.0
|
|
22
22
|
Provides-Extra: test
|
|
23
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: types-requests==2.25.0; extra == "test"
|
|
24
|
+
Requires-Dist: Django==3.2.4; extra == "test"
|
|
25
|
+
Requires-Dist: sseclient-py<1.9.0,>=1.7.0; extra == "test"
|
|
24
26
|
Requires-Dist: pytest-django==4.4.0; extra == "test"
|
|
25
27
|
Requires-Dist: pytest-pythonpath==0.7.3; extra == "test"
|
|
28
|
+
Requires-Dist: pytest-ordering==0.6; extra == "test"
|
|
29
|
+
Requires-Dist: aiohttp<4.0.0,>=3.8.0; extra == "test"
|
|
26
30
|
Requires-Dist: flake8==4.0.1; extra == "test"
|
|
27
|
-
Requires-Dist: wheel==0.36.2; extra == "test"
|
|
28
31
|
Requires-Dist: pytest-asyncio==0.21.*; extra == "test"
|
|
29
|
-
Requires-Dist:
|
|
30
|
-
Requires-Dist: requests<3.0.0,>=2.25; extra == "test"
|
|
31
|
-
Requires-Dist: pyyaml<6.1.0,>=5.4.0; extra == "test"
|
|
32
|
+
Requires-Dist: pytest-cov==2.12.1; extra == "test"
|
|
32
33
|
Requires-Dist: mypy==0.991; extra == "test"
|
|
34
|
+
Requires-Dist: pylint==2.12.*; extra == "test"
|
|
33
35
|
Requires-Dist: Werkzeug==2.0.1; extra == "test"
|
|
36
|
+
Requires-Dist: pyyaml<6.1.0,>=5.4.0; extra == "test"
|
|
34
37
|
Requires-Dist: freezegun==1.1.0; extra == "test"
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
Requires-Dist: types-requests==2.25.0; extra == "test"
|
|
37
|
-
Requires-Dist: pytest-cov==2.12.1; extra == "test"
|
|
38
|
-
Requires-Dist: pylint==2.12.*; extra == "test"
|
|
38
|
+
Requires-Dist: twine==3.4.1; extra == "test"
|
|
39
39
|
Requires-Dist: types-PyYAML==5.4.3; extra == "test"
|
|
40
|
-
Requires-Dist:
|
|
41
|
-
Requires-Dist:
|
|
40
|
+
Requires-Dist: requests<3.0.0,>=2.25; extra == "test"
|
|
41
|
+
Requires-Dist: wheel==0.36.2; extra == "test"
|
|
42
42
|
Requires-Dist: types-python-dateutil==2.8.2; extra == "test"
|
|
43
|
-
Requires-Dist:
|
|
43
|
+
Requires-Dist: aioresponses==0.7.*; extra == "test"
|
|
44
44
|
Dynamic: author
|
|
45
45
|
Dynamic: author-email
|
|
46
46
|
Dynamic: classifier
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"Async Client Readiness"
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from kameleoon.exceptions import Initialization
|
|
7
|
+
from kameleoon.client_readiness.threading_readiness import ThreadingClientReadiness
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AsyncClientReadiness:
|
|
11
|
+
"""
|
|
12
|
+
A class that provides an asynchronous interface for checking client readiness.
|
|
13
|
+
|
|
14
|
+
This class wraps around a `ThreadingClientReadiness` object to provide asynchronous
|
|
15
|
+
methods for waiting for the client to be ready. Blocking waits are run in the
|
|
16
|
+
event loop's default executor so the loop is never blocked.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, inner: ThreadingClientReadiness) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Initializes an AsyncClientReadiness instance.
|
|
22
|
+
"""
|
|
23
|
+
super().__init__()
|
|
24
|
+
self._inner = inner
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def inner(self) -> ThreadingClientReadiness:
|
|
28
|
+
"""
|
|
29
|
+
Returns the inner ThreadingClientReadiness instance.
|
|
30
|
+
"""
|
|
31
|
+
return self._inner
|
|
32
|
+
|
|
33
|
+
async def wait_with_timeout(self, timeout_second: float) -> Optional[Initialization]:
|
|
34
|
+
"""
|
|
35
|
+
Asynchronously waits until the readiness state is settled, but no longer than
|
|
36
|
+
`timeout_second`. See `ThreadingClientReadiness.wait_with_timeout` for the
|
|
37
|
+
detailed contract.
|
|
38
|
+
"""
|
|
39
|
+
# Non-blocking paths (already settled or expired timeout) are served inline.
|
|
40
|
+
if timeout_second <= 0:
|
|
41
|
+
return self._inner.wait_with_timeout(timeout_second)
|
|
42
|
+
loop = asyncio.get_event_loop()
|
|
43
|
+
return await loop.run_in_executor(None, self._inner.wait_with_timeout, timeout_second)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""ThreadingClientReadiness"""
|
|
2
|
+
from threading import Event, Lock
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from kameleoon.exceptions import Initialization
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class _State:
|
|
9
|
+
"""
|
|
10
|
+
A single settlement of the readiness state: `error` is written at most once,
|
|
11
|
+
before the event is set, and never changes afterwards, so a waiter which
|
|
12
|
+
obtained the state observes exactly the outcome it was registered for.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self) -> None:
|
|
16
|
+
self._event = Event()
|
|
17
|
+
self.error: Optional[Initialization] = None
|
|
18
|
+
|
|
19
|
+
def settle(self) -> None:
|
|
20
|
+
"""Settles the state, releasing all its waiters."""
|
|
21
|
+
self._event.set()
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def settled(self) -> bool:
|
|
25
|
+
"""Returns whether the state is settled."""
|
|
26
|
+
return self._event.is_set()
|
|
27
|
+
|
|
28
|
+
def wait(self, timeout_second: float) -> bool:
|
|
29
|
+
"""Returns whether the state was settled before the timeout elapsed."""
|
|
30
|
+
return self._event.wait(timeout_second)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ThreadingClientReadiness:
|
|
34
|
+
"""
|
|
35
|
+
ThreadingClientReadiness tracks whether the SDK has successfully loaded its
|
|
36
|
+
configuration and exposes that state to `KameleoonClient.wait_init` and
|
|
37
|
+
`KameleoonClient.is_ready`:
|
|
38
|
+
- a successful fetch settles the state successfully;
|
|
39
|
+
- a failed fetch settles it with an `Initialization` error.
|
|
40
|
+
|
|
41
|
+
Readiness is monotonic: once the SDK is ready it stays ready, and a later failed
|
|
42
|
+
fetch can never revert it. A failure reported before the first success does not
|
|
43
|
+
prevent a subsequent successful retry from marking the SDK ready.
|
|
44
|
+
|
|
45
|
+
It is created on the thread that builds the client but settled from the
|
|
46
|
+
background thread(s) performing configuration fetches.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self, site_code: str, environment: Optional[str]) -> None:
|
|
50
|
+
self._lock = Lock()
|
|
51
|
+
self._state = _State()
|
|
52
|
+
self._ready = False
|
|
53
|
+
self._site_code = site_code
|
|
54
|
+
self._environment = environment
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def ready(self) -> bool:
|
|
58
|
+
"""
|
|
59
|
+
Returns `True` if the SDK has been successfully initialized, `False` otherwise
|
|
60
|
+
(including while the initialization is still pending or has failed).
|
|
61
|
+
It never blocks.
|
|
62
|
+
|
|
63
|
+
This is the per-request hot path, so it is lock-free: `_ready` is only ever
|
|
64
|
+
flipped False -> True (readiness is monotonic), making a plain attribute read
|
|
65
|
+
safe. At worst a reader briefly observes `False` while `mark_ready` is
|
|
66
|
+
completing, which is indistinguishable from calling a moment earlier.
|
|
67
|
+
"""
|
|
68
|
+
return self._ready
|
|
69
|
+
|
|
70
|
+
def mark_ready(self) -> None:
|
|
71
|
+
"""Marks the SDK ready and releases all waiters."""
|
|
72
|
+
with self._lock:
|
|
73
|
+
self._ready = True
|
|
74
|
+
if self._state.settled:
|
|
75
|
+
if self._state.error is not None:
|
|
76
|
+
# Recovery after a failure: the failed state is left settled for its
|
|
77
|
+
# waiters, and a fresh, ready state is published for the new ones.
|
|
78
|
+
state = _State()
|
|
79
|
+
state.settle()
|
|
80
|
+
self._state = state
|
|
81
|
+
else:
|
|
82
|
+
self._state.settle()
|
|
83
|
+
|
|
84
|
+
def mark_not_ready(self, cause: Exception) -> None:
|
|
85
|
+
"""
|
|
86
|
+
Reports a failed fetch with an `Initialization` error, but only while the SDK
|
|
87
|
+
is not yet ready. A failure never reverts an already-ready client and is
|
|
88
|
+
reported at most once, so the first reported cause is the one waiters observe.
|
|
89
|
+
|
|
90
|
+
:param cause: the failure which prevented the SDK from loading its configuration.
|
|
91
|
+
:type cause: Exception
|
|
92
|
+
"""
|
|
93
|
+
with self._lock:
|
|
94
|
+
if not self._state.settled:
|
|
95
|
+
self._state.error = Initialization(self._site_code, self._environment, cause)
|
|
96
|
+
self._state.settle()
|
|
97
|
+
# else: already ready, or the failure was already reported
|
|
98
|
+
|
|
99
|
+
def wait_with_timeout(self, timeout_second: float) -> Optional[Initialization]:
|
|
100
|
+
"""
|
|
101
|
+
Blocks until the readiness state is settled, but no longer than `timeout_second`.
|
|
102
|
+
Returns the result of the configuration fetch: `None` once the SDK is ready, or
|
|
103
|
+
the `Initialization` error the fetch failure was reported with (fail-fast - it
|
|
104
|
+
does not wait for background retries). If no fetch result is available within
|
|
105
|
+
the timeout, returns an `Initialization` error caused by the expired timeout.
|
|
106
|
+
A non-positive timeout expires immediately unless a result is already available.
|
|
107
|
+
An expired timeout does not settle the readiness state: once the SDK becomes
|
|
108
|
+
ready, a subsequent call returns `None`.
|
|
109
|
+
|
|
110
|
+
:param timeout_second: maximum number of seconds to wait.
|
|
111
|
+
:type timeout_second: float
|
|
112
|
+
:return: `None` if the SDK is ready, otherwise an `Initialization` error.
|
|
113
|
+
:rtype: Optional[Initialization]
|
|
114
|
+
"""
|
|
115
|
+
state = self._current_state()
|
|
116
|
+
if state.settled:
|
|
117
|
+
return state.error
|
|
118
|
+
if timeout_second <= 0:
|
|
119
|
+
return self._timeout_failure(timeout_second)
|
|
120
|
+
if state.wait(timeout_second):
|
|
121
|
+
return state.error
|
|
122
|
+
return self._timeout_failure(timeout_second)
|
|
123
|
+
|
|
124
|
+
def _timeout_failure(self, timeout_second: float) -> Initialization:
|
|
125
|
+
# The timeout failure wraps a `TimeoutError` cause (the counterpart of the
|
|
126
|
+
# timeout error types the other SDKs report), so a caller can distinguish an
|
|
127
|
+
# expired timeout from a failed fetch.
|
|
128
|
+
cause = TimeoutError(f"initialization did not complete within {round(timeout_second * 1000)} ms")
|
|
129
|
+
return Initialization(self._site_code, self._environment, cause)
|
|
130
|
+
|
|
131
|
+
def _current_state(self) -> _State:
|
|
132
|
+
# Synchronized for safe publication of the state swapped in by a recovery.
|
|
133
|
+
with self._lock:
|
|
134
|
+
return self._state
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Kameleoon SDK events"""
|
|
2
|
+
|
|
3
|
+
from kameleoon.events.data_file_update_event import DataFileUpdateEvent # noqa: F401
|
|
4
|
+
from kameleoon.events.data_file_update_handler import DataFileUpdateHandler # noqa: F401
|
|
5
|
+
from kameleoon.events.event_handler import EventHandler # noqa: F401
|
|
6
|
+
from kameleoon.events.event_type import EventType # noqa: F401
|
|
7
|
+
from kameleoon.events.http_request_failure import HttpRequestFailure # noqa: F401
|
|
8
|
+
from kameleoon.events.http_request_handler import HttpRequestHandler # noqa: F401
|
|
9
|
+
from kameleoon.events.request_type import RequestType # noqa: F401
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"DataFileUpdateEvent",
|
|
13
|
+
"DataFileUpdateHandler",
|
|
14
|
+
"EventHandler",
|
|
15
|
+
"EventType",
|
|
16
|
+
"HttpRequestFailure",
|
|
17
|
+
"HttpRequestHandler",
|
|
18
|
+
"RequestType",
|
|
19
|
+
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Events"""
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class DataFileUpdateEvent:
|
|
6
|
+
"""Describes an update of the SDK data file (configuration) reported to `DataFileUpdateHandler`."""
|
|
7
|
+
|
|
8
|
+
class Source(Enum):
|
|
9
|
+
"""Represents the source of a data file update."""
|
|
10
|
+
|
|
11
|
+
POLLING = "POLLING"
|
|
12
|
+
"""The data file was updated by periodic polling."""
|
|
13
|
+
|
|
14
|
+
STREAMING = "STREAMING"
|
|
15
|
+
"""The data file was updated by a real-time (streaming) notification."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, source: "DataFileUpdateEvent.Source", date_modified: int) -> None:
|
|
18
|
+
"""For internal use only."""
|
|
19
|
+
self.__source = source
|
|
20
|
+
self.__date_modified = date_modified
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def source(self) -> "DataFileUpdateEvent.Source":
|
|
24
|
+
"""Returns the source of the data file update."""
|
|
25
|
+
return self.__source
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def date_modified(self) -> int:
|
|
29
|
+
"""Returns the date of the last modification of the data file, in Unix time milliseconds."""
|
|
30
|
+
return self.__date_modified
|
|
31
|
+
|
|
32
|
+
def __str__(self) -> str:
|
|
33
|
+
return f"DataFileUpdateEvent{{Source:{self.__source.value},DateModified:{self.__date_modified}}}"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Events"""
|
|
2
|
+
from typing import Protocol
|
|
3
|
+
|
|
4
|
+
from kameleoon.events.data_file_update_event import DataFileUpdateEvent
|
|
5
|
+
from kameleoon.events.event_handler import EventHandler
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DataFileUpdateHandler(EventHandler, Protocol):
|
|
9
|
+
"""
|
|
10
|
+
Handles `EventType.DATAFILE_UPDATE` SDK events.
|
|
11
|
+
|
|
12
|
+
Subclassing this protocol is optional: any object which provides the `on_update` method
|
|
13
|
+
is accepted by `KameleoonClient.set_event_handler`.
|
|
14
|
+
Static type checkers (e.g. mypy) verify such handlers structurally.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def on_update(self, update_event: DataFileUpdateEvent) -> None:
|
|
18
|
+
"""
|
|
19
|
+
Called when the SDK data file (configuration) is updated.
|
|
20
|
+
:param update_event: The data file update details.
|
|
21
|
+
:type update_event: DataFileUpdateEvent
|
|
22
|
+
"""
|
|
23
|
+
raise NotImplementedError()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Events"""
|
|
2
|
+
from typing import Protocol
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class EventHandler(Protocol): # pylint: disable=R0903
|
|
6
|
+
"""
|
|
7
|
+
Base protocol for all SDK event handlers. See `EventType` for the supported
|
|
8
|
+
event types and their corresponding handler protocols.
|
|
9
|
+
|
|
10
|
+
Subclassing the handler protocols is optional: any object which provides the methods
|
|
11
|
+
required by the selected event type is accepted by `KameleoonClient.set_event_handler`.
|
|
12
|
+
Static type checkers (e.g. mypy) verify such handlers structurally.
|
|
13
|
+
"""
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Events"""
|
|
2
|
+
from typing import Any, Dict, Optional
|
|
3
|
+
|
|
4
|
+
from kameleoon.events.data_file_update_event import DataFileUpdateEvent
|
|
5
|
+
from kameleoon.events.event_type import EventType, T
|
|
6
|
+
from kameleoon.events.http_request_failure import HttpRequestFailure
|
|
7
|
+
from kameleoon.events.request_type import RequestType
|
|
8
|
+
from kameleoon.logging.kameleoon_logger import KameleoonLogger
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EventManager:
|
|
12
|
+
"""For internal use only. Stores SDK event handlers and fires SDK events."""
|
|
13
|
+
|
|
14
|
+
def __init__(self) -> None:
|
|
15
|
+
self.__event_handlers: Dict[EventType[Any], Any] = {}
|
|
16
|
+
|
|
17
|
+
def set_event_handler(self, event_type: EventType[T], handler: Optional[T]) -> None:
|
|
18
|
+
"""Sets the SDK event handler for the specified event type. `None` clears the handler."""
|
|
19
|
+
if not isinstance(event_type, EventType): # runtime guard for untyped callers
|
|
20
|
+
KameleoonLogger.error("Unknown event type '%s'", event_type) # type: ignore[unreachable]
|
|
21
|
+
return
|
|
22
|
+
if (handler is not None) and (
|
|
23
|
+
not all(callable(getattr(handler, method, None)) for method in event_type.required_methods)
|
|
24
|
+
):
|
|
25
|
+
KameleoonLogger.error(
|
|
26
|
+
"Handler for event type '%s' must provide the following methods: %s",
|
|
27
|
+
event_type, ", ".join(event_type.required_methods),
|
|
28
|
+
)
|
|
29
|
+
return
|
|
30
|
+
if handler is None:
|
|
31
|
+
self.__event_handlers.pop(event_type, None)
|
|
32
|
+
else:
|
|
33
|
+
self.__event_handlers[event_type] = handler
|
|
34
|
+
|
|
35
|
+
def fire_http_request_succeeded(self, request_type: RequestType, http_status: int, duration_millis: int) -> None:
|
|
36
|
+
"""Fires the HTTP request event for a succeeded HTTP request attempt."""
|
|
37
|
+
handler = self.__event_handlers.get(EventType.HTTP_REQUEST)
|
|
38
|
+
if handler is not None:
|
|
39
|
+
try:
|
|
40
|
+
handler.on_request_succeeded(request_type, http_status, duration_millis)
|
|
41
|
+
except Exception as ex: # pylint: disable=W0703
|
|
42
|
+
KameleoonLogger.warning("HTTP request event handler failed: %s", ex)
|
|
43
|
+
|
|
44
|
+
def fire_http_request_failed(
|
|
45
|
+
self, request_type: RequestType, failure: HttpRequestFailure, duration_millis: int
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Fires the HTTP request event for a failed HTTP request attempt."""
|
|
48
|
+
handler = self.__event_handlers.get(EventType.HTTP_REQUEST)
|
|
49
|
+
if handler is not None:
|
|
50
|
+
try:
|
|
51
|
+
handler.on_request_failed(request_type, failure, duration_millis)
|
|
52
|
+
except Exception as ex: # pylint: disable=W0703
|
|
53
|
+
KameleoonLogger.warning("HTTP request event handler failed: %s", ex)
|
|
54
|
+
|
|
55
|
+
def fire_data_file_update(self, update_event: DataFileUpdateEvent) -> None:
|
|
56
|
+
"""Fires the data file update event."""
|
|
57
|
+
handler = self.__event_handlers.get(EventType.DATAFILE_UPDATE)
|
|
58
|
+
if handler is not None:
|
|
59
|
+
try:
|
|
60
|
+
handler.on_update(update_event)
|
|
61
|
+
except Exception as ex: # pylint: disable=W0703
|
|
62
|
+
KameleoonLogger.warning("Data file update event handler failed: %s", ex)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Events"""
|
|
2
|
+
from typing import cast, Generic, Tuple, Type, TypeVar
|
|
3
|
+
|
|
4
|
+
from kameleoon.events.data_file_update_handler import DataFileUpdateHandler
|
|
5
|
+
from kameleoon.events.event_handler import EventHandler
|
|
6
|
+
from kameleoon.events.http_request_handler import HttpRequestHandler
|
|
7
|
+
|
|
8
|
+
T = TypeVar("T", bound=EventHandler)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _handler_methods(handler_type: type) -> Tuple[str, ...]:
|
|
12
|
+
"""Collects the public methods of the handler type."""
|
|
13
|
+
return tuple(
|
|
14
|
+
name for name, member in vars(handler_type).items()
|
|
15
|
+
if not name.startswith("_") and callable(member)
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class EventType(Generic[T]):
|
|
20
|
+
"""
|
|
21
|
+
Represents an SDK event type available for `KameleoonClient.set_event_handler`.
|
|
22
|
+
The type parameter defines the handler protocol accepted by the event type.
|
|
23
|
+
|
|
24
|
+
Subclassing the handler protocols is optional: any object which provides the methods
|
|
25
|
+
required by the selected event type is accepted by `KameleoonClient.set_event_handler`.
|
|
26
|
+
Static type checkers (e.g. mypy) verify such handlers structurally.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
HTTP_REQUEST: "EventType[HttpRequestHandler]"
|
|
30
|
+
"""
|
|
31
|
+
Notifies when an SDK HTTP request completes successfully or fails.
|
|
32
|
+
Handled by `HttpRequestHandler`.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
DATAFILE_UPDATE: "EventType[DataFileUpdateHandler]"
|
|
36
|
+
"""
|
|
37
|
+
Notifies when the SDK data file (configuration) is updated.
|
|
38
|
+
Handled by `DataFileUpdateHandler`.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __init__(self, name: str, handler_type: type) -> None:
|
|
42
|
+
"""For internal use only. Use the predefined event type constants instead."""
|
|
43
|
+
self.__name = name
|
|
44
|
+
self.__handler_type = handler_type
|
|
45
|
+
self.__required_methods = _handler_methods(handler_type)
|
|
46
|
+
if not self.__required_methods:
|
|
47
|
+
# Guards against an event type accepting any object: `all(())` is `True`.
|
|
48
|
+
raise ValueError(f"Event handler type '{handler_type.__name__}' declares no handler methods")
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def name(self) -> str:
|
|
52
|
+
"""Returns the name of the event type."""
|
|
53
|
+
return self.__name
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def handler_type(self) -> Type[T]:
|
|
57
|
+
"""Returns the event handler protocol accepted by the event type."""
|
|
58
|
+
return cast(Type[T], self.__handler_type)
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def required_methods(self) -> Tuple[str, ...]:
|
|
62
|
+
"""Returns the names of the methods a handler of the event type must provide."""
|
|
63
|
+
return self.__required_methods
|
|
64
|
+
|
|
65
|
+
def __str__(self) -> str:
|
|
66
|
+
return self.__name
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
EventType.HTTP_REQUEST = EventType("HTTP_REQUEST", HttpRequestHandler)
|
|
70
|
+
EventType.DATAFILE_UPDATE = EventType("DATAFILE_UPDATE", DataFileUpdateHandler)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Events"""
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class HttpRequestFailure:
|
|
7
|
+
"""Describes the failure of an SDK HTTP request reported to `HttpRequestHandler`."""
|
|
8
|
+
|
|
9
|
+
class Reason(Enum):
|
|
10
|
+
"""Represents the reason of an SDK HTTP request failure."""
|
|
11
|
+
|
|
12
|
+
HTTP_STATUS = "HTTP_STATUS"
|
|
13
|
+
"""The request completed with an unexpected HTTP status code."""
|
|
14
|
+
|
|
15
|
+
EXCEPTION = "EXCEPTION"
|
|
16
|
+
"""The request failed with an exception."""
|
|
17
|
+
|
|
18
|
+
CANCELLED = "CANCELLED"
|
|
19
|
+
"""The request was cancelled (for example, due to a timeout)."""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self, reason: "HttpRequestFailure.Reason", http_status: Optional[int], cause: Optional[Exception]
|
|
23
|
+
) -> None:
|
|
24
|
+
"""
|
|
25
|
+
For internal use only. Use the `from_http_status`, `from_exception`,
|
|
26
|
+
`of_cancellation` factory methods instead.
|
|
27
|
+
"""
|
|
28
|
+
self.__reason = reason
|
|
29
|
+
self.__http_status = http_status
|
|
30
|
+
self.__cause = cause
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def from_http_status(http_status: int) -> "HttpRequestFailure":
|
|
34
|
+
"""For internal use only. Creates a failure with the `HTTP_STATUS` reason."""
|
|
35
|
+
return HttpRequestFailure(HttpRequestFailure.Reason.HTTP_STATUS, http_status, None)
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def from_exception(cause: Exception) -> "HttpRequestFailure":
|
|
39
|
+
"""For internal use only. Creates a failure with the `EXCEPTION` reason."""
|
|
40
|
+
return HttpRequestFailure(HttpRequestFailure.Reason.EXCEPTION, None, cause)
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def of_cancellation() -> "HttpRequestFailure":
|
|
44
|
+
"""For internal use only. Creates a failure with the `CANCELLED` reason."""
|
|
45
|
+
return HttpRequestFailure(HttpRequestFailure.Reason.CANCELLED, None, None)
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def reason(self) -> "HttpRequestFailure.Reason":
|
|
49
|
+
"""Returns the reason of the failure."""
|
|
50
|
+
return self.__reason
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def http_status(self) -> Optional[int]:
|
|
54
|
+
"""
|
|
55
|
+
Returns the HTTP status code of the response. Has a value only if `reason` is
|
|
56
|
+
`Reason.HTTP_STATUS`.
|
|
57
|
+
"""
|
|
58
|
+
return self.__http_status
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def cause(self) -> Optional[Exception]:
|
|
62
|
+
"""
|
|
63
|
+
Returns the exception caused the failure. Not `None` only if `reason` is
|
|
64
|
+
`Reason.EXCEPTION`.
|
|
65
|
+
"""
|
|
66
|
+
return self.__cause
|
|
67
|
+
|
|
68
|
+
def __str__(self) -> str:
|
|
69
|
+
cause = type(self.__cause).__name__ if self.__cause is not None else None
|
|
70
|
+
return f"HttpRequestFailure{{Reason:{self.__reason.value},HttpStatus:{self.__http_status},Cause:{cause}}}"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Events"""
|
|
2
|
+
from typing import Protocol
|
|
3
|
+
|
|
4
|
+
from kameleoon.events.event_handler import EventHandler
|
|
5
|
+
from kameleoon.events.http_request_failure import HttpRequestFailure
|
|
6
|
+
from kameleoon.events.request_type import RequestType
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class HttpRequestHandler(EventHandler, Protocol):
|
|
10
|
+
"""
|
|
11
|
+
Handles `EventType.HTTP_REQUEST` SDK events. The handler is called once per each
|
|
12
|
+
actual HTTP request attempt, including retries.
|
|
13
|
+
|
|
14
|
+
Subclassing this protocol is optional: any object which provides the `on_request_succeeded`
|
|
15
|
+
and `on_request_failed` methods is accepted by `KameleoonClient.set_event_handler`.
|
|
16
|
+
Static type checkers (e.g. mypy) verify such handlers structurally.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def on_request_succeeded(self, request_type: RequestType, http_status: int, duration_millis: int) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Called when an SDK HTTP request completes successfully.
|
|
22
|
+
:param request_type: The type of the request.
|
|
23
|
+
:type request_type: RequestType
|
|
24
|
+
:param http_status: The HTTP status code of the response.
|
|
25
|
+
:type http_status: int
|
|
26
|
+
:param duration_millis: The duration of the request in milliseconds.
|
|
27
|
+
:type duration_millis: int
|
|
28
|
+
"""
|
|
29
|
+
raise NotImplementedError()
|
|
30
|
+
|
|
31
|
+
def on_request_failed(
|
|
32
|
+
self, request_type: RequestType, failure: HttpRequestFailure, duration_millis: int
|
|
33
|
+
) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Called when an SDK HTTP request fails.
|
|
36
|
+
:param request_type: The type of the request.
|
|
37
|
+
:type request_type: RequestType
|
|
38
|
+
:param failure: The failure details.
|
|
39
|
+
:type failure: HttpRequestFailure
|
|
40
|
+
:param duration_millis: The duration of the request in milliseconds.
|
|
41
|
+
:type duration_millis: int
|
|
42
|
+
"""
|
|
43
|
+
raise NotImplementedError()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Events"""
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class RequestType(Enum):
|
|
6
|
+
"""Represents the type of an SDK HTTP request reported to `HttpRequestHandler`."""
|
|
7
|
+
|
|
8
|
+
DATAFILE = "DATAFILE"
|
|
9
|
+
"""Fetching of the SDK data file (configuration)."""
|
|
10
|
+
|
|
11
|
+
TRACKING = "TRACKING"
|
|
12
|
+
"""Sending of tracking data."""
|
|
13
|
+
|
|
14
|
+
REMOTE_VISITOR_DATA = "REMOTE_VISITOR_DATA"
|
|
15
|
+
"""Fetching of remote visitor data."""
|
|
16
|
+
|
|
17
|
+
REMOTE_DATA = "REMOTE_DATA"
|
|
18
|
+
"""Fetching of remote data."""
|
|
19
|
+
|
|
20
|
+
ACCESS_TOKEN = "ACCESS_TOKEN"
|
|
21
|
+
"""Fetching of the Kameleoon API access token."""
|
|
@@ -25,6 +25,24 @@ class SiteCodeIsEmpty(KameleoonError):
|
|
|
25
25
|
"""Site Code is Empty"""
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
class Initialization(KameleoonError):
|
|
29
|
+
"""
|
|
30
|
+
SDK could not be initialized: its configuration failed to load or no
|
|
31
|
+
initialization result was available within the requested timeout.
|
|
32
|
+
The failure which prevented the initialization is available via `cause`;
|
|
33
|
+
it is also reported in the message so a caller which only logs the
|
|
34
|
+
message still learns why the SDK is not initialized.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, site_code: str, environment, cause: Exception) -> None:
|
|
38
|
+
# The failure which prevented the SDK from loading its configuration.
|
|
39
|
+
self.cause = cause
|
|
40
|
+
reason = "unknown" if cause is None else str(cause)
|
|
41
|
+
super().__init__(
|
|
42
|
+
f"SDK is not initialized for siteCode: '{site_code}', environment: '{environment}'. Reason: {reason}"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
28
46
|
class NotFoundError(KameleoonError):
|
|
29
47
|
"""Base not found error"""
|
|
30
48
|
|