kameleoon-client-python 3.19.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.19.0 → kameleoon_client_python-3.22.0}/PKG-INFO +14 -14
- 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.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/conversion.py +25 -1
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/assigned_variation.py +7 -4
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/page_view_visit.py +3 -3
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/visitor.py +46 -44
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/visitor_manager.py +10 -7
- kameleoon_client_python-3.22.0/kameleoon/data/personalization.py +44 -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.19.0 → kameleoon_client_python-3.22.0}/kameleoon/exceptions.py +18 -0
- kameleoon_client_python-3.22.0/kameleoon/helpers/time.py +24 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/hybrid/hybrid_manager_impl.py +22 -13
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/kameleoon_client.py +171 -49
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/kameleoon_client_config.py +12 -11
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/remote_data/remote_visitor_data.py +13 -6
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/network_manager.py +6 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/network_manager_factory.py +2 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/network_manager_factory_impl.py +3 -2
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/network_manager_impl.py +7 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/automation_service_impl.py +2 -1
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/configuration_service_impl.py +4 -1
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/data_service_impl.py +5 -3
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/service_impl.py +43 -5
- kameleoon_client_python-3.19.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.19.0 → kameleoon_client_python-3.22.0}/kameleoon/sdk_version.py +1 -1
- kameleoon_client_python-3.22.0/kameleoon/targeting/conditions/conversion_condition.py +37 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/exclusive_experiment_condition.py +23 -12
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/target_experiment_condition.py +11 -5
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/target_feature_flag_condition.py +30 -20
- kameleoon_client_python-3.22.0/kameleoon/targeting/conditions/target_personalization_condition.py +30 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.py +2 -2
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/unknown_condition.py +3 -3
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/visit_number_today_condition.py +2 -3
- kameleoon_client_python-3.22.0/kameleoon/targeting/conditions/visitor_scope_condition.py +56 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/targeting_manager.py +31 -9
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon_client_python.egg-info/PKG-INFO +14 -14
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon_client_python.egg-info/SOURCES.txt +12 -1
- kameleoon_client_python-3.19.0/kameleoon/client_readiness/async_readiness.py +0 -48
- kameleoon_client_python-3.19.0/kameleoon/client_readiness/threading_readiness.py +0 -44
- kameleoon_client_python-3.19.0/kameleoon/data/personalization.py +0 -30
- kameleoon_client_python-3.19.0/kameleoon/targeting/conditions/conversion_condition.py +0 -24
- kameleoon_client_python-3.19.0/kameleoon/targeting/conditions/target_personalization_condition.py +0 -23
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/MANIFEST.in +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/README.md +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/client_readiness/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/consent_blocking_behaviour.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/custom_data_info.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/data_file.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/experiment.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/feature_flag.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/me_group.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/rule.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/rule_type.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/settings.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/variable.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/variation.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/configuration/variation_by_exposition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/application_version.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/browser.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/cbscores.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/cookie.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/custom_data.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/data.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/device.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/geolocation.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/kcs_heat.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/forced_experiment_variation.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/forced_feature_variation.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/forced_variation.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/legal_consent.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/visitor_slot.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/mapping_identifier.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/operating_system.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/page_view.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/targeted_segment.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/unique_identifier.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/user_agent.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/visitor_visits.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/defaults.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/domain.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/functions.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/hasher.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/logger.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/multi_threading.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/nonce.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/repeat_timer.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/scheduler.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/sem_version.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/string_utils.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/helpers/visitor_code.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/hybrid/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/hybrid/hybrid_manager.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/kameleoon_client_factory.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/logging/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/logging/kameleoon_logger.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/logging/log_level.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/logging/logger.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/asyncexec/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/asyncexec/async_executor.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/data/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/data/data_manager.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/evaluation/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/evaluation/evaluated_experiment.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/remote_data/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/remote_data/remote_data_manager.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/tracking/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/tracking/tracking_builder.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/tracking/tracking_manager.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/tracking/visitor_tracking_registry.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/warehouse/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/managers/warehouse/warehouse_manager.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/middleware.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/access_token_source.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/access_token_source_factory.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/activity_event.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/cookie/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/cookie/cookie_manager.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/net_provider.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/net_provider_impl.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/query_builder.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/query_encodable.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/sendable.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/service_initialize_context.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/service_initialize_context_impl.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/automation_service.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/configuration_service.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/data_service.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/services/service.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/uri_helper.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/network/url_provider.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/real_time/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/real_time/real_time_event.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/storage/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/storage/cache.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/storage/cache_factory.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/storage/cache_factory_impl.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/storage/cache_impl.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/browser_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/constants.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/cookie_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/custom_datum.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/device_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/geolocation_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/kcs_heat_range_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/number_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/operating_system_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/page_title_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/page_url_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/page_view_number_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/previous_page_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/sdk_language_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/segment_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/string_value_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/targeting_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/version_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/visit_number_total_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/conditions/visitor_new_return_condition.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/models.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/tree_builder.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/targeting/tree_condition_factory.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/types/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/types/data_file.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/types/feature_flag.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/types/remote_visitor_data_filter.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/types/rule.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/types/variable.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/types/variation.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon_client_python.egg-info/requires.txt +13 -13
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/setup.cfg +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/setup.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/apps.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/migrations/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/kameleoon_app/views.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/manage.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/proj/__init__.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/proj/asgi.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/proj/settings.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/proj/urls.py +0 -0
- {kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/tests/integration/proj/proj/wsgi.py +0 -0
- {kameleoon_client_python-3.19.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,26 +20,26 @@ 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: wheel==0.36.2; extra == "test"
|
|
24
|
-
Requires-Dist: Werkzeug==2.0.1; extra == "test"
|
|
25
|
-
Requires-Dist: aiohttp<4.0.0,>=3.8.0; extra == "test"
|
|
26
|
-
Requires-Dist: pylint==2.12.*; extra == "test"
|
|
27
23
|
Requires-Dist: types-requests==2.25.0; extra == "test"
|
|
28
|
-
Requires-Dist:
|
|
24
|
+
Requires-Dist: Django==3.2.4; extra == "test"
|
|
29
25
|
Requires-Dist: sseclient-py<1.9.0,>=1.7.0; extra == "test"
|
|
30
|
-
Requires-Dist: pytest-cov==2.12.1; extra == "test"
|
|
31
|
-
Requires-Dist: types-python-dateutil==2.8.2; extra == "test"
|
|
32
|
-
Requires-Dist: freezegun==1.1.0; extra == "test"
|
|
33
|
-
Requires-Dist: pyyaml<6.1.0,>=5.4.0; extra == "test"
|
|
34
26
|
Requires-Dist: pytest-django==4.4.0; extra == "test"
|
|
27
|
+
Requires-Dist: pytest-pythonpath==0.7.3; extra == "test"
|
|
35
28
|
Requires-Dist: pytest-ordering==0.6; extra == "test"
|
|
36
|
-
Requires-Dist:
|
|
37
|
-
Requires-Dist: types-PyYAML==5.4.3; extra == "test"
|
|
29
|
+
Requires-Dist: aiohttp<4.0.0,>=3.8.0; extra == "test"
|
|
38
30
|
Requires-Dist: flake8==4.0.1; extra == "test"
|
|
39
|
-
Requires-Dist: pytest-
|
|
31
|
+
Requires-Dist: pytest-asyncio==0.21.*; extra == "test"
|
|
32
|
+
Requires-Dist: pytest-cov==2.12.1; extra == "test"
|
|
40
33
|
Requires-Dist: mypy==0.991; extra == "test"
|
|
41
|
-
Requires-Dist:
|
|
34
|
+
Requires-Dist: pylint==2.12.*; extra == "test"
|
|
35
|
+
Requires-Dist: Werkzeug==2.0.1; extra == "test"
|
|
36
|
+
Requires-Dist: pyyaml<6.1.0,>=5.4.0; extra == "test"
|
|
37
|
+
Requires-Dist: freezegun==1.1.0; extra == "test"
|
|
42
38
|
Requires-Dist: twine==3.4.1; extra == "test"
|
|
39
|
+
Requires-Dist: types-PyYAML==5.4.3; extra == "test"
|
|
40
|
+
Requires-Dist: requests<3.0.0,>=2.25; extra == "test"
|
|
41
|
+
Requires-Dist: wheel==0.36.2; extra == "test"
|
|
42
|
+
Requires-Dist: types-python-dateutil==2.8.2; extra == "test"
|
|
43
43
|
Requires-Dist: aioresponses==0.7.*; extra == "test"
|
|
44
44
|
Dynamic: author
|
|
45
45
|
Dynamic: author-email
|
|
@@ -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
|
{kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/conversion.py
RENAMED
|
@@ -6,6 +6,7 @@ from typing import Optional, Iterable
|
|
|
6
6
|
from kameleoon.data.custom_data import CustomData
|
|
7
7
|
from kameleoon.data.data import Data, DataType
|
|
8
8
|
from kameleoon.helpers.string_utils import StringUtils
|
|
9
|
+
from kameleoon.helpers.time import time_ms
|
|
9
10
|
from kameleoon.network.sendable import DuplicationSafeSendableBase
|
|
10
11
|
from kameleoon.network.query_builder import QueryBuilder, QueryParam, QueryParams
|
|
11
12
|
|
|
@@ -45,6 +46,23 @@ class Conversion(Data, DuplicationSafeSendableBase):
|
|
|
45
46
|
self.__revenue = revenue
|
|
46
47
|
self.__negative = negative
|
|
47
48
|
self._metadata = metadata
|
|
49
|
+
self._assignment_time_ms = time_ms()
|
|
50
|
+
|
|
51
|
+
# pylint: disable=too-many-arguments
|
|
52
|
+
@classmethod
|
|
53
|
+
def _build_internal(
|
|
54
|
+
cls,
|
|
55
|
+
goal_id: int,
|
|
56
|
+
revenue: float = 0.0,
|
|
57
|
+
negative: bool = False,
|
|
58
|
+
metadata: Optional[Iterable[CustomData]] = None,
|
|
59
|
+
assignment_time: Optional[int] = None,
|
|
60
|
+
) -> "Conversion":
|
|
61
|
+
"""Create a conversion with SDK-managed internal state."""
|
|
62
|
+
conversion = cls(goal_id, revenue, negative, metadata)
|
|
63
|
+
if assignment_time:
|
|
64
|
+
conversion._assignment_time_ms = assignment_time
|
|
65
|
+
return conversion
|
|
48
66
|
|
|
49
67
|
@property
|
|
50
68
|
def goal_id(self) -> int:
|
|
@@ -66,6 +84,11 @@ class Conversion(Data, DuplicationSafeSendableBase):
|
|
|
66
84
|
"""Returns metadata"""
|
|
67
85
|
return self._metadata
|
|
68
86
|
|
|
87
|
+
@property
|
|
88
|
+
def _assignment_time(self) -> float:
|
|
89
|
+
"""Returns the internal time when the conversion was added."""
|
|
90
|
+
return self._assignment_time_ms
|
|
91
|
+
|
|
69
92
|
@property
|
|
70
93
|
def data_type(self) -> DataType:
|
|
71
94
|
return DataType.CONVERSION
|
|
@@ -97,5 +120,6 @@ class Conversion(Data, DuplicationSafeSendableBase):
|
|
|
97
120
|
f"Conversion{{goal_id:{self.__goal_id},"
|
|
98
121
|
f"revenue:{self.__revenue},"
|
|
99
122
|
f"negative:{self.__negative},"
|
|
100
|
-
f"metadata:{StringUtils.object_to_string(self._metadata)}
|
|
123
|
+
f"metadata:{StringUtils.object_to_string(self._metadata)},"
|
|
124
|
+
f"assignment_time:{self._assignment_time_ms}}}"
|
|
101
125
|
)
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
# pylint: disable=duplicate-code
|
|
1
2
|
"""Assigned Variation"""
|
|
2
|
-
|
|
3
|
+
|
|
3
4
|
from typing import Optional
|
|
4
5
|
from kameleoon.configuration.rule_type import RuleType
|
|
5
6
|
from kameleoon.data.data import BaseData, DataType
|
|
7
|
+
from kameleoon.helpers.time import time_ms
|
|
6
8
|
from kameleoon.network.sendable import DuplicationUnsafeSendableBase
|
|
7
9
|
from kameleoon.network.query_builder import QueryBuilder, QueryParam, QueryParams
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
class AssignedVariation(BaseData, DuplicationUnsafeSendableBase):
|
|
11
13
|
"""Assigned variation"""
|
|
14
|
+
|
|
12
15
|
EVENT_TYPE = "experiment"
|
|
13
16
|
|
|
14
17
|
def __init__(
|
|
@@ -22,7 +25,7 @@ class AssignedVariation(BaseData, DuplicationUnsafeSendableBase):
|
|
|
22
25
|
self.__experiment_id = experiment_id
|
|
23
26
|
self.__variation_id = variation_id
|
|
24
27
|
self.__rule_type = rule_type
|
|
25
|
-
self.
|
|
28
|
+
self.__assignment_time_ms = assignment_time or time_ms()
|
|
26
29
|
|
|
27
30
|
@property
|
|
28
31
|
def experiment_id(self) -> int:
|
|
@@ -42,7 +45,7 @@ class AssignedVariation(BaseData, DuplicationUnsafeSendableBase):
|
|
|
42
45
|
@property
|
|
43
46
|
def assignment_time(self) -> float:
|
|
44
47
|
"""Returns the time when the assignment occurred."""
|
|
45
|
-
return self.
|
|
48
|
+
return self.__assignment_time_ms
|
|
46
49
|
|
|
47
50
|
@property
|
|
48
51
|
def data_type(self) -> DataType:
|
|
@@ -66,6 +69,6 @@ class AssignedVariation(BaseData, DuplicationUnsafeSendableBase):
|
|
|
66
69
|
return (
|
|
67
70
|
f"AssignedVariation{{experiment_id:{self.__experiment_id},"
|
|
68
71
|
f"variation_id:{self.__variation_id},"
|
|
69
|
-
f"assignment_time:{self.
|
|
72
|
+
f"assignment_time:{self.__assignment_time_ms},"
|
|
70
73
|
f"rule_type:{self.__rule_type}}}"
|
|
71
74
|
)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""Page view visit"""
|
|
2
2
|
|
|
3
|
-
import time
|
|
4
3
|
from typing import Optional
|
|
5
4
|
from kameleoon.data import DataType
|
|
6
5
|
from kameleoon.data.data import BaseData
|
|
7
6
|
from kameleoon.data.page_view import PageView
|
|
7
|
+
from kameleoon.helpers.time import time_ms
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class PageViewVisit(BaseData):
|
|
@@ -14,13 +14,13 @@ class PageViewVisit(BaseData):
|
|
|
14
14
|
super().__init__()
|
|
15
15
|
self.page_view = page_view
|
|
16
16
|
self.count = count
|
|
17
|
-
self.last_timestamp = last_timestamp or
|
|
17
|
+
self.last_timestamp = last_timestamp or time_ms()
|
|
18
18
|
|
|
19
19
|
def overwrite(self, new_page_view: PageView) -> None:
|
|
20
20
|
"""Overwrites the current PageView with a new PageView and increments the visit count."""
|
|
21
21
|
self.page_view = new_page_view
|
|
22
22
|
self.count += 1
|
|
23
|
-
self.last_timestamp =
|
|
23
|
+
self.last_timestamp = time_ms()
|
|
24
24
|
|
|
25
25
|
def merge(self, page_view_visit) -> None:
|
|
26
26
|
"""Merges the visit data from another PageViewVisit instance into this one."""
|
{kameleoon_client_python-3.19.0 → kameleoon_client_python-3.22.0}/kameleoon/data/manager/visitor.py
RENAMED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"""Visitor"""
|
|
2
|
-
import time
|
|
3
2
|
|
|
4
3
|
from threading import Lock
|
|
5
4
|
from typing import Any, Callable, Optional, Dict, List, Iterator, Iterable, cast
|
|
@@ -27,6 +26,7 @@ from kameleoon.data.manager.forced_experiment_variation import ForcedExperimentV
|
|
|
27
26
|
from kameleoon.data.manager.forced_feature_variation import ForcedFeatureVariation
|
|
28
27
|
from kameleoon.data.manager.legal_consent import LegalConsent
|
|
29
28
|
from kameleoon.data.manager.page_view_visit import PageViewVisit
|
|
29
|
+
from kameleoon.helpers.time import time_ms
|
|
30
30
|
from kameleoon.logging.kameleoon_logger import KameleoonLogger
|
|
31
31
|
from kameleoon.network.sendable import Sendable
|
|
32
32
|
|
|
@@ -37,6 +37,7 @@ EMPTY_LIST: List[Any] = []
|
|
|
37
37
|
|
|
38
38
|
class Visitor: # pylint: disable=R0904
|
|
39
39
|
"""Visitor"""
|
|
40
|
+
|
|
40
41
|
def __init__(self, source: Optional["Visitor"] = None) -> None:
|
|
41
42
|
if source is None:
|
|
42
43
|
self._data = Visitor.VisitorData()
|
|
@@ -56,108 +57,109 @@ class Visitor: # pylint: disable=R0904
|
|
|
56
57
|
|
|
57
58
|
def enumerate_sendable_data(self) -> Iterator[Sendable]:
|
|
58
59
|
"""Enumerates all sendable data associated with this Visitor."""
|
|
59
|
-
KameleoonLogger.debug(
|
|
60
|
+
KameleoonLogger.debug("CALL: Visitor.enumerate_sendable_data()")
|
|
60
61
|
sendable_data = self._data.enumerate_sendable_data()
|
|
61
|
-
KameleoonLogger.debug(
|
|
62
|
+
KameleoonLogger.debug("RETURN: Visitor.enumerate_sendable_data() -> (sendable_data)")
|
|
62
63
|
return sendable_data
|
|
63
64
|
|
|
64
65
|
def count_sendable_data(self) -> int:
|
|
65
66
|
"""Counts the number of sendable data items associated with this Visitor."""
|
|
66
|
-
KameleoonLogger.debug(
|
|
67
|
+
KameleoonLogger.debug("CALL: Visitor.count_sendable_data()")
|
|
67
68
|
count_sendable_data = self._data.count_sendable_data()
|
|
68
|
-
KameleoonLogger.debug(
|
|
69
|
+
KameleoonLogger.debug("RETURN: Visitor.count_sendable_data() -> (count: %s)", count_sendable_data)
|
|
69
70
|
return count_sendable_data
|
|
70
71
|
|
|
71
72
|
@property
|
|
72
73
|
def user_agent(self) -> Optional[str]:
|
|
73
74
|
"""Returns the user agent string associated with this Visitor."""
|
|
74
75
|
user_agent = self._data.user_agent
|
|
75
|
-
KameleoonLogger.debug(
|
|
76
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.user_agent -> (user_agent: %s)", user_agent)
|
|
76
77
|
return user_agent
|
|
77
78
|
|
|
78
79
|
@property
|
|
79
80
|
def device(self) -> Optional[Device]:
|
|
80
81
|
"""Returns the device information associated with this Visitor."""
|
|
81
82
|
device = self._data.device
|
|
82
|
-
KameleoonLogger.debug(
|
|
83
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.device -> (device: %s)", device)
|
|
83
84
|
return device
|
|
84
85
|
|
|
85
86
|
@property
|
|
86
87
|
def browser(self) -> Optional[Browser]:
|
|
87
88
|
"""Returns the browser information associated with this Visitor."""
|
|
88
89
|
browser = self._data.browser
|
|
89
|
-
KameleoonLogger.debug(
|
|
90
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.browser -> (browser: %s)", browser)
|
|
90
91
|
return browser
|
|
91
92
|
|
|
92
93
|
@property
|
|
93
94
|
def geolocation(self) -> Optional[Geolocation]:
|
|
94
95
|
"""Returns the geolocation information associated with this Visitor."""
|
|
95
96
|
geolocation = self._data.geolocation
|
|
96
|
-
KameleoonLogger.debug(
|
|
97
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.geolocation -> (geolocation: %s)", geolocation)
|
|
97
98
|
return geolocation
|
|
98
99
|
|
|
99
100
|
@property
|
|
100
101
|
def operating_system(self) -> Optional[OperatingSystem]:
|
|
101
102
|
"""Returns the operating system information associated with this Visitor."""
|
|
102
103
|
operating_system = self._data.operating_system
|
|
103
|
-
KameleoonLogger.debug(
|
|
104
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.operating_system -> (operating_system: %s)", operating_system)
|
|
104
105
|
return operating_system
|
|
105
106
|
|
|
106
107
|
@property
|
|
107
108
|
def application_version(self) -> Optional[ApplicationVersion]:
|
|
108
109
|
"""Returns the application version information associated with this Visitor."""
|
|
109
110
|
application_version = self._data.application_version
|
|
110
|
-
KameleoonLogger.debug(
|
|
111
|
-
|
|
111
|
+
KameleoonLogger.debug(
|
|
112
|
+
"CALL/RETURN: Visitor.application_version -> (application_version: %s)", application_version
|
|
113
|
+
)
|
|
112
114
|
return application_version
|
|
113
115
|
|
|
114
116
|
@property
|
|
115
117
|
def cookie(self) -> Optional[Cookie]:
|
|
116
118
|
"""Returns the cookie information associated with this Visitor."""
|
|
117
119
|
cookie = self._data.cookie
|
|
118
|
-
KameleoonLogger.debug(
|
|
120
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.cookie -> (cookie: %s)", cookie)
|
|
119
121
|
return cookie
|
|
120
122
|
|
|
121
123
|
@property
|
|
122
124
|
def custom_data(self) -> Dict[int, CustomData]:
|
|
123
125
|
"""Returns the custom data associated with this Visitor."""
|
|
124
126
|
custom_data = EMPTY_DICT if self._data.custom_data_dict is None else self._data.custom_data_dict.copy()
|
|
125
|
-
KameleoonLogger.debug(
|
|
127
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.custom_data -> (custom_data: %s)", custom_data)
|
|
126
128
|
return custom_data
|
|
127
129
|
|
|
128
130
|
@property
|
|
129
131
|
def page_view_visits(self) -> Dict[str, PageViewVisit]:
|
|
130
132
|
"""Returns the page view visits associated with this Visitor."""
|
|
131
133
|
page_view_visits = EMPTY_DICT if self._data.page_view_visits is None else self._data.page_view_visits.copy()
|
|
132
|
-
KameleoonLogger.debug(
|
|
134
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.page_view_visits -> (page_view_visits: %s)", page_view_visits)
|
|
133
135
|
return page_view_visits
|
|
134
136
|
|
|
135
137
|
@property
|
|
136
138
|
def conversions(self) -> List[Conversion]:
|
|
137
139
|
"""Returns the conversions associated with this Visitor."""
|
|
138
140
|
conversions = EMPTY_LIST if self._data.conversions is None else self._data.conversions.copy()
|
|
139
|
-
KameleoonLogger.debug(
|
|
141
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.conversions -> (conversions: %s)", conversions)
|
|
140
142
|
return conversions
|
|
141
143
|
|
|
142
144
|
@property
|
|
143
145
|
def variations(self) -> Dict[int, AssignedVariation]:
|
|
144
146
|
"""Returns the variations associated with this Visitor."""
|
|
145
147
|
variations = EMPTY_DICT if self._data.variations is None else self._data.variations.copy()
|
|
146
|
-
KameleoonLogger.debug(
|
|
148
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.variations -> (variations: %s)", variations)
|
|
147
149
|
return variations
|
|
148
150
|
|
|
149
151
|
@property
|
|
150
152
|
def personalizations(self) -> Dict[int, Personalization]:
|
|
151
153
|
"""Returns the personalizations associated with this Visitor."""
|
|
152
154
|
personalizations = EMPTY_DICT if self._data.personalizations is None else self._data.personalizations.copy()
|
|
153
|
-
KameleoonLogger.debug(
|
|
155
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.personalizations -> (personalizations: %s)", personalizations)
|
|
154
156
|
return personalizations
|
|
155
157
|
|
|
156
158
|
@property
|
|
157
159
|
def targeted_segments(self) -> Dict[int, TargetedSegment]:
|
|
158
160
|
"""Returns the personalizations associated with this Visitor."""
|
|
159
161
|
targeted_segments = EMPTY_DICT if self._data.targeted_segments is None else self._data.targeted_segments.copy()
|
|
160
|
-
KameleoonLogger.debug(
|
|
162
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.targeted_segments -> (targeted_segments: %s)", targeted_segments)
|
|
161
163
|
return targeted_segments
|
|
162
164
|
|
|
163
165
|
def get_forced_feature_variation(self, feature_key: str) -> Optional[ForcedFeatureVariation]:
|
|
@@ -165,10 +167,10 @@ class Visitor: # pylint: disable=R0904
|
|
|
165
167
|
Returns an associated forced feature variation by its feature key if it is present.
|
|
166
168
|
Otherwise returns `None`.
|
|
167
169
|
"""
|
|
168
|
-
KameleoonLogger.debug(
|
|
170
|
+
KameleoonLogger.debug("CALL: Visitor.get_forced_feature_variation(feature_key: %s)", feature_key)
|
|
169
171
|
ffv = self._data.simulated_variations.get(feature_key) if self._data.simulated_variations else None
|
|
170
172
|
KameleoonLogger.debug(
|
|
171
|
-
|
|
173
|
+
"RETURN: Visitor.get_forced_feature_variation(feature_key: %s) -> (variation: %s)", feature_key, ffv
|
|
172
174
|
)
|
|
173
175
|
return ffv
|
|
174
176
|
|
|
@@ -177,64 +179,64 @@ class Visitor: # pylint: disable=R0904
|
|
|
177
179
|
Returns an associated forced experiment variation by its experiment id if it is present.
|
|
178
180
|
Otherwise returns `None`.
|
|
179
181
|
"""
|
|
180
|
-
KameleoonLogger.debug(
|
|
182
|
+
KameleoonLogger.debug("CALL: Visitor.get_forced_experiment_variation(experiment_id: %s)", experiment_id)
|
|
181
183
|
fev = self._data.forced_variations.get(experiment_id) if self._data.forced_variations else None
|
|
182
184
|
KameleoonLogger.debug(
|
|
183
|
-
|
|
185
|
+
"RETURN: Visitor.get_forced_experiment_variation(experiment_id: %s) -> (variation: %s)", experiment_id, fev
|
|
184
186
|
)
|
|
185
187
|
return fev
|
|
186
188
|
|
|
187
189
|
def reset_forced_experiment_variation(self, experiment_id: int) -> None:
|
|
188
190
|
"""Resets an associated forced experiment variation for some experiment id"""
|
|
189
|
-
KameleoonLogger.debug(
|
|
191
|
+
KameleoonLogger.debug("CALL: Visitor.reset_forced_experiment_variation(experiment_id: %s)", experiment_id)
|
|
190
192
|
if self._data.forced_variations:
|
|
191
193
|
self._data.forced_variations.pop(experiment_id, None)
|
|
192
|
-
KameleoonLogger.debug(
|
|
194
|
+
KameleoonLogger.debug("RETURN: Visitor.reset_forced_experiment_variation(experiment_id: %s)", experiment_id)
|
|
193
195
|
|
|
194
196
|
def update_simulated_variations(self, variations: Iterable[ForcedFeatureVariation]) -> None:
|
|
195
197
|
"""Updates the associated simulated variations"""
|
|
196
198
|
if not (self._data.simulated_variations or variations):
|
|
197
199
|
return
|
|
198
|
-
KameleoonLogger.debug(
|
|
200
|
+
KameleoonLogger.debug("CALL: Visitor.update_simulated_variations(variations: %s)", variations)
|
|
199
201
|
self._data.simulated_variations = {sv.feature_key: sv for sv in variations}
|
|
200
|
-
KameleoonLogger.debug(
|
|
202
|
+
KameleoonLogger.debug("RETURN: Visitor.update_simulated_variations(variations: %s)", variations)
|
|
201
203
|
|
|
202
204
|
@property
|
|
203
205
|
def kcs_heat(self) -> Optional[KcsHeat]:
|
|
204
206
|
"""Returns the KCS heat data associated with this Visitor."""
|
|
205
207
|
kcs_heat = self._data.kcs_heat
|
|
206
|
-
KameleoonLogger.debug(
|
|
208
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.kcs_heat -> (kcs_heat: %s)", kcs_heat)
|
|
207
209
|
return kcs_heat
|
|
208
210
|
|
|
209
211
|
@property
|
|
210
212
|
def cbscores(self) -> Optional[CBScores]:
|
|
211
213
|
"""Returns the CBS data associated with this Visitor."""
|
|
212
214
|
cbs = self._data.cbscores
|
|
213
|
-
KameleoonLogger.debug(
|
|
215
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.cbscores -> (cbs: %s)", cbs)
|
|
214
216
|
return cbs
|
|
215
217
|
|
|
216
218
|
@property
|
|
217
219
|
def visitor_visits(self) -> Optional[VisitorVisits]:
|
|
218
220
|
"""Returns the visitor visits data associated with this Visitor."""
|
|
219
221
|
visitor_visits = self._data.visitor_visits
|
|
220
|
-
KameleoonLogger.debug(
|
|
222
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.visitor_visits -> (visitor_visits: %s)", visitor_visits)
|
|
221
223
|
return visitor_visits
|
|
222
224
|
|
|
223
225
|
def assign_variation(self, variation: AssignedVariation) -> None:
|
|
224
226
|
"""Assigns a variation to the Visitor."""
|
|
225
|
-
KameleoonLogger.debug(
|
|
227
|
+
KameleoonLogger.debug("CALL: Visitor.assign_variation(variation: %s)", variation)
|
|
226
228
|
if self._data.variations is None:
|
|
227
229
|
with self._data.lock:
|
|
228
230
|
if self._data.variations is None:
|
|
229
231
|
self._data.variations = {variation.experiment_id: variation}
|
|
230
|
-
KameleoonLogger.debug(
|
|
232
|
+
KameleoonLogger.debug("RETURN: Visitor.assign_variation(variation: %s)", variation)
|
|
231
233
|
return
|
|
232
234
|
self._data.variations[variation.experiment_id] = variation
|
|
233
|
-
KameleoonLogger.debug(
|
|
235
|
+
KameleoonLogger.debug("RETURN: Visitor.assign_variation(variation: %s)", variation)
|
|
234
236
|
|
|
235
237
|
def add_data(self, *args, overwrite: bool = True, track: bool = True) -> None:
|
|
236
238
|
"""Adds data to the Visitor."""
|
|
237
|
-
KameleoonLogger.debug(
|
|
239
|
+
KameleoonLogger.debug("CALL: Visitor.add_data(args: %s, overwrite: %s, track: %s)", args, overwrite, track)
|
|
238
240
|
with self._data.lock:
|
|
239
241
|
for data in args:
|
|
240
242
|
if data is None:
|
|
@@ -247,14 +249,13 @@ class Visitor: # pylint: disable=R0904
|
|
|
247
249
|
data_adder(self, self.DataAddingContext(data, overwrite))
|
|
248
250
|
else:
|
|
249
251
|
KameleoonLogger.warning("Data has unsupported type %s", data_type)
|
|
250
|
-
KameleoonLogger.debug(
|
|
252
|
+
KameleoonLogger.debug("RETURN: Visitor.add_data(args: %s, overwrite: %s, track: %s)", args, overwrite, track)
|
|
251
253
|
|
|
252
254
|
@property
|
|
253
255
|
def mapping_identifier(self) -> Optional[str]:
|
|
254
256
|
"""Returns the mapping identifier associated with this Visitor."""
|
|
255
257
|
mapping_identifier = self._data.mapping_identifier
|
|
256
|
-
KameleoonLogger.debug(
|
|
257
|
-
mapping_identifier)
|
|
258
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.mapping_identifier -> (mapping_identifier: %s)", mapping_identifier)
|
|
258
259
|
return mapping_identifier
|
|
259
260
|
|
|
260
261
|
@mapping_identifier.setter
|
|
@@ -272,7 +273,7 @@ class Visitor: # pylint: disable=R0904
|
|
|
272
273
|
def legal_consent(self) -> LegalConsent:
|
|
273
274
|
"""Returns the legal consent status for this Visitor."""
|
|
274
275
|
legal_consent = self._data.legal_consent
|
|
275
|
-
KameleoonLogger.debug(
|
|
276
|
+
KameleoonLogger.debug("CALL/RETURN: Visitor.legal_consent -> (legal_consent: %s)", legal_consent)
|
|
276
277
|
return legal_consent
|
|
277
278
|
|
|
278
279
|
@legal_consent.setter
|
|
@@ -285,14 +286,16 @@ class Visitor: # pylint: disable=R0904
|
|
|
285
286
|
def is_unique_identifier(self) -> bool:
|
|
286
287
|
"""Returns the unique identifier status for this Visitor."""
|
|
287
288
|
is_unique_identifier = self._is_unique_identifier
|
|
288
|
-
KameleoonLogger.debug(
|
|
289
|
-
|
|
289
|
+
KameleoonLogger.debug(
|
|
290
|
+
"CALL/RETURN: Visitor.is_unique_identifier -> (is_unique_identifier: %s)", is_unique_identifier
|
|
291
|
+
)
|
|
290
292
|
return is_unique_identifier
|
|
291
293
|
|
|
292
294
|
class VisitorData:
|
|
293
295
|
"""Visitor Data"""
|
|
296
|
+
|
|
294
297
|
def __init__(self) -> None:
|
|
295
|
-
self.time_started =
|
|
298
|
+
self.time_started = time_ms()
|
|
296
299
|
self.lock = Lock()
|
|
297
300
|
self.user_agent: Optional[str] = None
|
|
298
301
|
self.device: Optional[Device] = None
|
|
@@ -365,9 +368,8 @@ class Visitor: # pylint: disable=R0904
|
|
|
365
368
|
|
|
366
369
|
class DataAddingContext:
|
|
367
370
|
"""Data adding context"""
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
) -> None:
|
|
371
|
+
|
|
372
|
+
def __init__(self, data: Data, overwrite: bool = True) -> None:
|
|
371
373
|
self._data = data
|
|
372
374
|
self._overwrite = overwrite
|
|
373
375
|
|