kameleoon-client-python 3.6.1__tar.gz → 3.8.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.6.1 → kameleoon-client-python-3.8.0}/PKG-INFO +1 -1
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/data_file.py +44 -9
- kameleoon-client-python-3.8.0/kameleoon/configuration/experiment.py +46 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/rule.py +2 -16
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/data.py +2 -0
- kameleoon-client-python-3.8.0/kameleoon/data/manager/forced_experiment_variation.py +49 -0
- kameleoon-client-python-3.8.0/kameleoon/data/manager/forced_feature_variation.py +46 -0
- kameleoon-client-python-3.8.0/kameleoon/data/manager/forced_variation.py +33 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/visitor.py +59 -2
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/exceptions.py +9 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/functions.py +1 -39
- kameleoon-client-python-3.8.0/kameleoon/helpers/hasher.py +24 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/kameleoon_client.py +196 -94
- kameleoon-client-python-3.8.0/kameleoon/managers/evaluation/evaluated_experiment.py +50 -0
- kameleoon-client-python-3.8.0/kameleoon/network/cookie/cookie_manager.py +200 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/uri_helper.py +6 -1
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/sdk_version.py +1 -1
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/target_feature_flag_condition.py +2 -2
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon_client_python.egg-info/PKG-INFO +1 -1
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon_client_python.egg-info/SOURCES.txt +7 -0
- kameleoon-client-python-3.8.0/tests/integration/proj/proj/__init__.py +0 -0
- kameleoon-client-python-3.6.1/kameleoon/network/cookie/cookie_manager.py +0 -107
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/MANIFEST.in +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/README.md +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/client_readiness/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/client_readiness/async_readiness.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/client_readiness/threading_readiness.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/custom_data_info.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/feature_flag.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/rule_type.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/settings.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/variable.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/variation.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/variation_by_exposition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/browser.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/conversion.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/cookie.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/custom_data.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/device.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/geolocation.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/kcs_heat.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/assigned_variation.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/page_view_visit.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/visitor_manager.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/visitor_slot.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/mapping_identifier.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/operating_system.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/page_view.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/unique_identifier.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/user_agent.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/visitor_visits.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/defaults.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/domain.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/logger.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/multi_threading.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/nonce.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/repeat_timer.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/scheduler.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/string_utils.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/visitor_code.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/hybrid/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/hybrid/hybrid_manager.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/hybrid/hybrid_manager_impl.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/kameleoon_client_config.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/kameleoon_client_factory.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/logging/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/logging/kameleoon_logger.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/logging/log_level.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/logging/logger.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/asyncexec/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/asyncexec/async_executor.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/data/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/data/data_manager.py +0 -0
- {kameleoon-client-python-3.6.1/kameleoon/managers/remote_data → kameleoon-client-python-3.8.0/kameleoon/managers/evaluation}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1/kameleoon/managers/tracking → kameleoon-client-python-3.8.0/kameleoon/managers/remote_data}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/remote_data/remote_data_manager.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/remote_data/remote_visitor_data.py +0 -0
- {kameleoon-client-python-3.6.1/kameleoon/managers/warehouse → kameleoon-client-python-3.8.0/kameleoon/managers/tracking}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/tracking/tracking_builder.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/tracking/tracking_manager.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/tracking/visitor_tracking_registry.py +0 -0
- {kameleoon-client-python-3.6.1/kameleoon/network → kameleoon-client-python-3.8.0/kameleoon/managers/warehouse}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/warehouse/warehouse_manager.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/middleware.py +0 -0
- {kameleoon-client-python-3.6.1/kameleoon/network/cookie → kameleoon-client-python-3.8.0/kameleoon/network}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/access_token_source.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/access_token_source_factory.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/activity_event.py +0 -0
- {kameleoon-client-python-3.6.1/kameleoon/network/services → kameleoon-client-python-3.8.0/kameleoon/network/cookie}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/net_provider.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/net_provider_impl.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/network_manager.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/network_manager_factory.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/network_manager_factory_impl.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/network_manager_impl.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/query_builder.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/query_encodable.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/sendable.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/service_initialize_context.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/service_initialize_context_impl.py +0 -0
- {kameleoon-client-python-3.6.1/kameleoon/real_time → kameleoon-client-python-3.8.0/kameleoon/network/services}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/automation_service.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/automation_service_impl.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/configuration_service.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/configuration_service_impl.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/data_service.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/data_service_impl.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/service.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/service_impl.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/url_provider.py +0 -0
- {kameleoon-client-python-3.6.1/kameleoon/storage → kameleoon-client-python-3.8.0/kameleoon/real_time}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/real_time/real_time_configuration_service.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/real_time/real_time_event.py +0 -0
- {kameleoon-client-python-3.6.1/kameleoon/targeting → kameleoon-client-python-3.8.0/kameleoon/storage}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/storage/cache.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/storage/cache_factory.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/storage/cache_factory_impl.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/storage/cache_impl.py +0 -0
- {kameleoon-client-python-3.6.1/kameleoon/targeting/conditions → kameleoon-client-python-3.8.0/kameleoon/targeting}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1/kameleoon/types → kameleoon-client-python-3.8.0/kameleoon/targeting/conditions}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/browser_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/constants.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/conversion_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/cookie_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/custom_datum.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/device_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/exclusive_feature_flag_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/geolocation_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/kcs_heat_range_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/number_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/operating_system_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/page_title_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/page_url_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/page_view_number_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/previous_page_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/sdk_language_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/segment_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/string_value_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/targeting_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/unknown_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/visit_number_today_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/visit_number_total_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/visitor_new_return_condition.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/models.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/targeting_manager.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/tree_builder.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/tree_condition_factory.py +0 -0
- {kameleoon-client-python-3.6.1/tests/integration/proj → kameleoon-client-python-3.8.0/kameleoon/types}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/types/remote_visitor_data_filter.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/types/variable.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/types/variation.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon_client_python.egg-info/requires.txt +15 -15
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/setup.cfg +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/setup.py +0 -0
- {kameleoon-client-python-3.6.1/tests/integration/proj/kameleoon_app → kameleoon-client-python-3.8.0/tests/integration/proj}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1/tests/integration/proj/kameleoon_app/migrations → kameleoon-client-python-3.8.0/tests/integration/proj/kameleoon_app}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/kameleoon_app/apps.py +0 -0
- {kameleoon-client-python-3.6.1/tests/integration/proj/proj → kameleoon-client-python-3.8.0/tests/integration/proj/kameleoon_app/migrations}/__init__.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/kameleoon_app/views.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/manage.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/proj/asgi.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/proj/settings.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/proj/urls.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/proj/wsgi.py +0 -0
- {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/resources/config.yml +0 -0
{kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/data_file.py
RENAMED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
from typing import Any, Dict, Optional, Set
|
|
4
4
|
from kameleoon.configuration import Variable
|
|
5
5
|
from kameleoon.configuration.custom_data_info import CustomDataInfo
|
|
6
|
-
from kameleoon.configuration.
|
|
6
|
+
from kameleoon.configuration.experiment import Experiment
|
|
7
7
|
from kameleoon.configuration.feature_flag import FeatureFlag
|
|
8
8
|
from kameleoon.configuration.rule import Rule
|
|
9
9
|
from kameleoon.configuration.settings import Settings
|
|
10
|
+
from kameleoon.configuration.variation_by_exposition import VariationByExposition
|
|
10
11
|
from kameleoon.exceptions import FeatureNotFound, FeatureEnvironmentDisabled
|
|
11
12
|
from kameleoon.logging.kameleoon_logger import KameleoonLogger
|
|
12
13
|
|
|
@@ -31,7 +32,8 @@ class DataFile:
|
|
|
31
32
|
for jobj in configuration.get("featureFlags") or []
|
|
32
33
|
}
|
|
33
34
|
custom_data_info = CustomDataInfo(configuration.get("customData"))
|
|
34
|
-
|
|
35
|
+
holdout = Experiment.from_json(configuration["holdout"]) if "holdout" in configuration else None
|
|
36
|
+
data_file = DataFile(environment, settings, feature_flags, custom_data_info, holdout)
|
|
35
37
|
return data_file
|
|
36
38
|
|
|
37
39
|
# pylint: disable=R0913
|
|
@@ -41,10 +43,12 @@ class DataFile:
|
|
|
41
43
|
settings: Settings,
|
|
42
44
|
feature_flags: Dict[str, FeatureFlag],
|
|
43
45
|
custom_data_info: CustomDataInfo,
|
|
46
|
+
holdout: Optional[Experiment] = None,
|
|
44
47
|
) -> None:
|
|
45
48
|
KameleoonLogger.debug(
|
|
46
|
-
'CALL: DataFile(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s)',
|
|
47
|
-
environment, settings, feature_flags, custom_data_info
|
|
49
|
+
'CALL: DataFile(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s, holdout: %s)',
|
|
50
|
+
environment, settings, feature_flags, custom_data_info, holdout
|
|
51
|
+
)
|
|
48
52
|
self.__environment = environment # pylint: disable=W0238
|
|
49
53
|
self.__settings = settings
|
|
50
54
|
self.__feature_flags: Dict[str, FeatureFlag] = feature_flags
|
|
@@ -56,13 +60,16 @@ class DataFile:
|
|
|
56
60
|
)
|
|
57
61
|
self.__variation_by_id: Dict[int, VariationByExposition] = {}
|
|
58
62
|
self.__rule_by_segment_id: Dict[int, Rule] = {}
|
|
63
|
+
self.__rule_info_by_exp_id: Dict[int, DataFile.RuleInfo] = {}
|
|
59
64
|
self.__feature_flag_by_id: Dict[int, FeatureFlag] = {}
|
|
60
65
|
self.__experiment_ids_with_js_css_variable: Set[int] = set()
|
|
61
66
|
self.__collect_indices()
|
|
62
67
|
self.__custom_data_info = custom_data_info
|
|
68
|
+
self.__holdout = holdout
|
|
63
69
|
KameleoonLogger.debug(
|
|
64
|
-
'RETURN: DataFile.new(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s)',
|
|
65
|
-
environment, settings, feature_flags, custom_data_info
|
|
70
|
+
'RETURN: DataFile.new(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s, holdout: %s)',
|
|
71
|
+
environment, settings, feature_flags, custom_data_info
|
|
72
|
+
)
|
|
66
73
|
|
|
67
74
|
@property
|
|
68
75
|
def settings(self) -> Settings:
|
|
@@ -84,6 +91,11 @@ class DataFile:
|
|
|
84
91
|
"""Returns dictionary of all rule stored by segment id"""
|
|
85
92
|
return self.__rule_by_segment_id
|
|
86
93
|
|
|
94
|
+
@property
|
|
95
|
+
def rule_info_by_exp_id(self) -> Dict[int, "DataFile.RuleInfo"]:
|
|
96
|
+
"""Returns dictionary of all rule related info stored by experiment id"""
|
|
97
|
+
return self.__rule_info_by_exp_id
|
|
98
|
+
|
|
87
99
|
@property
|
|
88
100
|
def variation_by_id(self) -> Dict[int, VariationByExposition]:
|
|
89
101
|
"""Returns dictionary of all variations stored by id"""
|
|
@@ -108,9 +120,14 @@ class DataFile:
|
|
|
108
120
|
|
|
109
121
|
@property
|
|
110
122
|
def custom_data_info(self) -> CustomDataInfo:
|
|
111
|
-
"""Returns custom data info for mapping device
|
|
123
|
+
"""Returns custom data info for mapping device"""
|
|
112
124
|
return self.__custom_data_info
|
|
113
125
|
|
|
126
|
+
@property
|
|
127
|
+
def holdout(self) -> Optional[Experiment]:
|
|
128
|
+
"""Returns holdout"""
|
|
129
|
+
return self.__holdout
|
|
130
|
+
|
|
114
131
|
def has_experiment_js_css_variable(self, experiment_id: int) -> bool:
|
|
115
132
|
"""Returns `True` if the experiment has a JS or CSS variable, otherwise returns `False`"""
|
|
116
133
|
return experiment_id in self.__experiment_ids_with_js_css_variable
|
|
@@ -122,9 +139,10 @@ class DataFile:
|
|
|
122
139
|
has_feature_flag_variable_js_css = self.__has_feature_flag_variable_js_css(feature_flag)
|
|
123
140
|
for rule in feature_flag.rules:
|
|
124
141
|
self.__rule_by_segment_id[rule.segment_id] = rule
|
|
142
|
+
self.__rule_info_by_exp_id[rule.experiment.id_] = DataFile.RuleInfo(feature_flag, rule)
|
|
125
143
|
if has_feature_flag_variable_js_css:
|
|
126
|
-
self.__experiment_ids_with_js_css_variable.add(rule.
|
|
127
|
-
for variation in rule.
|
|
144
|
+
self.__experiment_ids_with_js_css_variable.add(rule.experiment.id_)
|
|
145
|
+
for variation in rule.experiment.variations_by_exposition:
|
|
128
146
|
if variation.variation_id is not None:
|
|
129
147
|
self.__variation_by_id[variation.variation_id] = variation
|
|
130
148
|
|
|
@@ -146,3 +164,20 @@ class DataFile:
|
|
|
146
164
|
f"settings:{self.__settings}"
|
|
147
165
|
f"}}"
|
|
148
166
|
)
|
|
167
|
+
|
|
168
|
+
class RuleInfo:
|
|
169
|
+
"""Aggregates some information related to a specific rule"""
|
|
170
|
+
|
|
171
|
+
def __init__(self, feature_flag: FeatureFlag, rule: Rule) -> None:
|
|
172
|
+
self.__feature_flag = feature_flag
|
|
173
|
+
self.__rule = rule
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def feature_flag(self) -> FeatureFlag:
|
|
177
|
+
"""Returns the feature flag"""
|
|
178
|
+
return self.__feature_flag
|
|
179
|
+
|
|
180
|
+
@property
|
|
181
|
+
def rule(self) -> Rule:
|
|
182
|
+
"""Returns the rule"""
|
|
183
|
+
return self.__rule
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Kameleoon Configuration"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, List, Dict, Optional
|
|
4
|
+
from kameleoon.configuration.variation_by_exposition import VariationByExposition
|
|
5
|
+
from kameleoon.exceptions import FeatureVariationNotFound
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Experiment:
|
|
9
|
+
"""Experiment"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, id_: int, variations_by_exposition: List[VariationByExposition]) -> None:
|
|
12
|
+
self.id_ = id_
|
|
13
|
+
self.variations_by_exposition = variations_by_exposition
|
|
14
|
+
self.first_variation = variations_by_exposition[0] if len(variations_by_exposition) > 0 else None
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def from_json(dict_json: Dict[str, Any]) -> "Experiment":
|
|
18
|
+
"""Creates a new instance of `Experiment` from a json object"""
|
|
19
|
+
id_ = dict_json.get("experimentId", 0)
|
|
20
|
+
variations_by_exposition: List[VariationByExposition] = VariationByExposition.from_array(
|
|
21
|
+
dict_json.get("variationByExposition", [])
|
|
22
|
+
)
|
|
23
|
+
return Experiment(id_, variations_by_exposition)
|
|
24
|
+
|
|
25
|
+
def get_variation(self, hash_double: float) -> Optional[VariationByExposition]:
|
|
26
|
+
"""Calculates the variation key for the given hash of visitor"""
|
|
27
|
+
|
|
28
|
+
total = 0.0
|
|
29
|
+
for var_by_exp in self.variations_by_exposition:
|
|
30
|
+
total += var_by_exp.exposition
|
|
31
|
+
if total >= hash_double:
|
|
32
|
+
return var_by_exp
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
def get_variation_by_key(self, variation_key: str) -> VariationByExposition:
|
|
36
|
+
"""
|
|
37
|
+
Finds variation with a passed variation key.
|
|
38
|
+
Raises the `FeatureVariationNotFound` exception if such variation does not exist.
|
|
39
|
+
"""
|
|
40
|
+
for var_by_exp in self.variations_by_exposition:
|
|
41
|
+
if var_by_exp.variation_key == variation_key:
|
|
42
|
+
return var_by_exp
|
|
43
|
+
raise FeatureVariationNotFound("'#{variation_key}'")
|
|
44
|
+
|
|
45
|
+
def __str__(self) -> str:
|
|
46
|
+
return f"Experiment{{id:{self.id_}}}"
|
{kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/rule.py
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Kameleoon Configuration"""
|
|
2
2
|
|
|
3
3
|
from typing import Any, List, Dict, Optional
|
|
4
|
+
from kameleoon.configuration.experiment import Experiment
|
|
4
5
|
from kameleoon.configuration.rule_type import RuleType, rule_type_from_literal
|
|
5
|
-
from kameleoon.configuration.variation_by_exposition import VariationByExposition
|
|
6
6
|
from kameleoon.targeting.models import Segment
|
|
7
7
|
|
|
8
8
|
|
|
@@ -23,26 +23,12 @@ class Rule:
|
|
|
23
23
|
type_literal: str = dict_json.get("type", "")
|
|
24
24
|
self.type = rule_type_from_literal(type_literal)
|
|
25
25
|
self.exposition: float = dict_json.get("exposition", 0.0)
|
|
26
|
-
self.
|
|
26
|
+
self.experiment = Experiment.from_json(dict_json)
|
|
27
27
|
self.respool_time: Optional[int] = dict_json.get("respoolTime", None)
|
|
28
|
-
self.variation_by_exposition: List[VariationByExposition] = VariationByExposition.from_array(
|
|
29
|
-
dict_json.get("variationByExposition", [])
|
|
30
|
-
)
|
|
31
|
-
self.first_variation = self.variation_by_exposition[0] if len(self.variation_by_exposition) > 0 else None
|
|
32
28
|
segment = dict_json.get("segment")
|
|
33
29
|
self.targeting_segment: Optional[Segment] = Segment(segment) if segment else None
|
|
34
30
|
self.segment_id: int = self.targeting_segment.id_ if self.targeting_segment else -1
|
|
35
31
|
|
|
36
|
-
def get_variation(self, hash_double: float) -> Optional[VariationByExposition]:
|
|
37
|
-
"""Calculates the variation key for the given hash of visitor"""
|
|
38
|
-
|
|
39
|
-
total = 0.0
|
|
40
|
-
for var_by_exp in self.variation_by_exposition:
|
|
41
|
-
total += var_by_exp.exposition
|
|
42
|
-
if total >= hash_double:
|
|
43
|
-
return var_by_exp
|
|
44
|
-
return None
|
|
45
|
-
|
|
46
32
|
@property
|
|
47
33
|
def is_experimentation(self) -> bool:
|
|
48
34
|
"""Return `true` if rule is `experimentation` type"""
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Forced Experiment Variation"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, cast
|
|
4
|
+
from kameleoon.configuration.rule import Rule
|
|
5
|
+
from kameleoon.configuration.variation_by_exposition import VariationByExposition
|
|
6
|
+
from kameleoon.data.data import DataType
|
|
7
|
+
from kameleoon.data.manager.forced_variation import ForcedVariation
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ForcedExperimentVariation(ForcedVariation):
|
|
11
|
+
"""Represents a forced experiment variation"""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self, rule: Rule, var_by_exp: VariationByExposition, force_targeting: bool
|
|
15
|
+
) -> None:
|
|
16
|
+
super().__init__(rule, var_by_exp)
|
|
17
|
+
self.__force_targeting = force_targeting
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def data_type(self) -> DataType:
|
|
21
|
+
return DataType.FORCED_EXPERIMENT_VARIATION
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def rule(self) -> Rule:
|
|
25
|
+
"""Returns the rule"""
|
|
26
|
+
return self._rule or cast(Rule, self._rule)
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def var_by_exp(self) -> VariationByExposition:
|
|
30
|
+
"""Returns the variation by exposition"""
|
|
31
|
+
return self._var_by_exp or cast(VariationByExposition, self._var_by_exp)
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def force_targeting(self) -> bool:
|
|
35
|
+
"""Returns the force targeting flag's state"""
|
|
36
|
+
return self.__force_targeting
|
|
37
|
+
|
|
38
|
+
def __eq__(self, value: Any) -> bool:
|
|
39
|
+
return super().__eq__(value) and isinstance(value, ForcedExperimentVariation) and \
|
|
40
|
+
(self.__force_targeting == value.force_targeting)
|
|
41
|
+
|
|
42
|
+
def __str__(self) -> str:
|
|
43
|
+
return (
|
|
44
|
+
"ForcedExperimentVariation{"
|
|
45
|
+
f"rule:{self._rule},"
|
|
46
|
+
f"var_by_exp:{self._var_by_exp},"
|
|
47
|
+
f"force_targeting:{self.__force_targeting},"
|
|
48
|
+
"}"
|
|
49
|
+
)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Forced Feature Variation"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
from kameleoon.configuration.rule import Rule
|
|
5
|
+
from kameleoon.configuration.variation_by_exposition import VariationByExposition
|
|
6
|
+
from kameleoon.data.data import DataType
|
|
7
|
+
from kameleoon.data.manager.forced_variation import ForcedVariation
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ForcedFeatureVariation(ForcedVariation):
|
|
11
|
+
"""Represents a forced feature variation"""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self, feature_key: str, rule: Optional[Rule], var_by_exp: Optional[VariationByExposition], simulated: bool
|
|
15
|
+
) -> None:
|
|
16
|
+
super().__init__(rule, var_by_exp)
|
|
17
|
+
self.__feature_key = feature_key
|
|
18
|
+
self.__simulated = simulated
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def data_type(self) -> DataType:
|
|
22
|
+
return DataType.FORCED_FEATURE_VARIATION
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def feature_key(self) -> str:
|
|
26
|
+
"""Returns the feature key"""
|
|
27
|
+
return self.__feature_key
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def simulated(self) -> bool:
|
|
31
|
+
"""Returns the simulated flag's state"""
|
|
32
|
+
return self.__simulated
|
|
33
|
+
|
|
34
|
+
def __eq__(self, value: Any) -> bool:
|
|
35
|
+
return super().__eq__(value) and isinstance(value, ForcedFeatureVariation) and \
|
|
36
|
+
(self.__feature_key == value.feature_key) and (self.__simulated == value.simulated)
|
|
37
|
+
|
|
38
|
+
def __str__(self) -> str:
|
|
39
|
+
return (
|
|
40
|
+
"ForcedFeatureVariation{"
|
|
41
|
+
f"feature_key:'{self.__feature_key}',"
|
|
42
|
+
f"rule:{self._rule},"
|
|
43
|
+
f"var_by_exp:{self._var_by_exp},"
|
|
44
|
+
f"simulated:{self.__simulated},"
|
|
45
|
+
"}"
|
|
46
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Forced Variation"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
from kameleoon.configuration.rule import Rule
|
|
5
|
+
from kameleoon.configuration.variation_by_exposition import VariationByExposition
|
|
6
|
+
from kameleoon.data.data import BaseData, DataType
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ForcedVariation(BaseData):
|
|
10
|
+
"""Represents a forced variation"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, rule: Optional[Rule], var_by_exp: Optional[VariationByExposition]) -> None:
|
|
13
|
+
super().__init__()
|
|
14
|
+
self._rule = rule
|
|
15
|
+
self._var_by_exp = var_by_exp
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def data_type(self) -> DataType:
|
|
19
|
+
raise NotImplementedError
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def rule(self) -> Optional[Rule]:
|
|
23
|
+
"""Returns the rule"""
|
|
24
|
+
return self._rule
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def var_by_exp(self) -> Optional[VariationByExposition]:
|
|
28
|
+
"""Returns the variation by exposition"""
|
|
29
|
+
return self._var_by_exp
|
|
30
|
+
|
|
31
|
+
def __eq__(self, value: Any) -> bool:
|
|
32
|
+
return isinstance(value, ForcedVariation) and \
|
|
33
|
+
(self._rule == value._rule) and (self._var_by_exp == value._var_by_exp)
|
{kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/visitor.py
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Visitor"""
|
|
2
2
|
from threading import Lock
|
|
3
|
-
from typing import Any, Callable, Optional, Dict, List, Iterator, cast
|
|
3
|
+
from typing import Any, Callable, Optional, Dict, List, Iterator, Iterable, cast
|
|
4
4
|
|
|
5
5
|
from kameleoon.data.visitor_visits import VisitorVisits
|
|
6
6
|
from kameleoon.data.data import Data
|
|
@@ -17,6 +17,8 @@ from kameleoon.data.page_view import PageView
|
|
|
17
17
|
from kameleoon.data.unique_identifier import UniqueIdentifier
|
|
18
18
|
from kameleoon.data.user_agent import UserAgent
|
|
19
19
|
from kameleoon.data.manager.assigned_variation import AssignedVariation
|
|
20
|
+
from kameleoon.data.manager.forced_experiment_variation import ForcedExperimentVariation
|
|
21
|
+
from kameleoon.data.manager.forced_feature_variation import ForcedFeatureVariation
|
|
20
22
|
from kameleoon.data.manager.page_view_visit import PageViewVisit
|
|
21
23
|
from kameleoon.logging.kameleoon_logger import KameleoonLogger
|
|
22
24
|
from kameleoon.network.sendable import Sendable
|
|
@@ -26,7 +28,7 @@ EMPTY_DICT: Dict[Any, Any] = {}
|
|
|
26
28
|
EMPTY_LIST: List[Any] = []
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
class Visitor:
|
|
31
|
+
class Visitor: # pylint: disable=R0904
|
|
30
32
|
"""Visitor"""
|
|
31
33
|
def __init__(self, source: Optional["Visitor"] = None) -> None:
|
|
32
34
|
if source is None:
|
|
@@ -124,6 +126,45 @@ class Visitor:
|
|
|
124
126
|
KameleoonLogger.debug('CALL/RETURN: Visitor.variations -> (variations: %s)', variations)
|
|
125
127
|
return variations
|
|
126
128
|
|
|
129
|
+
def get_forced_feature_variation(self, feature_key: str) -> Optional[ForcedFeatureVariation]:
|
|
130
|
+
"""
|
|
131
|
+
Returns an associated forced feature variation by its feature key if it is present.
|
|
132
|
+
Otherwise returns `None`.
|
|
133
|
+
"""
|
|
134
|
+
KameleoonLogger.debug('CALL: Visitor.get_forced_feature_variation(feature_key: %s)', feature_key)
|
|
135
|
+
ffv = self._data.simulated_variations.get(feature_key) if self._data.simulated_variations else None
|
|
136
|
+
KameleoonLogger.debug(
|
|
137
|
+
'RETURN: Visitor.get_forced_feature_variation(feature_key: %s) -> (variation: %s)', feature_key, ffv
|
|
138
|
+
)
|
|
139
|
+
return ffv
|
|
140
|
+
|
|
141
|
+
def get_forced_experiment_variation(self, experiment_id: int) -> Optional[ForcedExperimentVariation]:
|
|
142
|
+
"""
|
|
143
|
+
Returns an associated forced experiment variation by its experiment id if it is present.
|
|
144
|
+
Otherwise returns `None`.
|
|
145
|
+
"""
|
|
146
|
+
KameleoonLogger.debug('CALL: Visitor.get_forced_experiment_variation(experiment_id: %s)', experiment_id)
|
|
147
|
+
fev = self._data.forced_variations.get(experiment_id) if self._data.forced_variations else None
|
|
148
|
+
KameleoonLogger.debug(
|
|
149
|
+
'RETURN: Visitor.get_forced_experiment_variation(experiment_id: %s) -> (variation: %s)', experiment_id, fev
|
|
150
|
+
)
|
|
151
|
+
return fev
|
|
152
|
+
|
|
153
|
+
def reset_forced_experiment_variation(self, experiment_id: int) -> None:
|
|
154
|
+
"""Resets an associated forced experiment variation for some experiment id"""
|
|
155
|
+
KameleoonLogger.debug('CALL: Visitor.reset_forced_experiment_variation(experiment_id: %s)', experiment_id)
|
|
156
|
+
if self._data.forced_variations:
|
|
157
|
+
self._data.forced_variations.pop(experiment_id, None)
|
|
158
|
+
KameleoonLogger.debug('RETURN: Visitor.reset_forced_experiment_variation(experiment_id: %s)', experiment_id)
|
|
159
|
+
|
|
160
|
+
def update_simulated_variations(self, variations: Iterable[ForcedFeatureVariation]) -> None:
|
|
161
|
+
"""Updates the associated simulated variations"""
|
|
162
|
+
if not (self._data.simulated_variations or variations):
|
|
163
|
+
return
|
|
164
|
+
KameleoonLogger.debug('CALL: Visitor.update_simulated_variations(variations: %s)', variations)
|
|
165
|
+
self._data.simulated_variations = {sv.feature_key: sv for sv in variations}
|
|
166
|
+
KameleoonLogger.debug('RETURN: Visitor.update_simulated_variations(variations: %s)', variations)
|
|
167
|
+
|
|
127
168
|
@property
|
|
128
169
|
def kcs_heat(self) -> Optional[KcsHeat]:
|
|
129
170
|
"""Returns the KCS heat data associated with this Visitor."""
|
|
@@ -217,6 +258,8 @@ class Visitor:
|
|
|
217
258
|
self.page_view_visits: Optional[Dict[str, PageViewVisit]] = None
|
|
218
259
|
self.conversions: Optional[List[Conversion]] = None
|
|
219
260
|
self.variations: Optional[Dict[int, AssignedVariation]] = None
|
|
261
|
+
self.forced_variations: Optional[Dict[int, ForcedExperimentVariation]] = None
|
|
262
|
+
self.simulated_variations: Optional[Dict[str, ForcedFeatureVariation]] = None
|
|
220
263
|
self.kcs_heat: Optional[KcsHeat] = None
|
|
221
264
|
self.visitor_visits: Optional[VisitorVisits] = None
|
|
222
265
|
self.mapping_identifier: Optional[str] = None
|
|
@@ -294,6 +337,18 @@ class Visitor:
|
|
|
294
337
|
if context.overwrite or variation.experiment_id not in self.variations:
|
|
295
338
|
self._data.variations[variation.experiment_id] = variation
|
|
296
339
|
|
|
340
|
+
def _add_forced_feature_variation(self, context: DataAddingContext) -> None:
|
|
341
|
+
ffv = cast(ForcedFeatureVariation, context.data)
|
|
342
|
+
if self._data.simulated_variations is None:
|
|
343
|
+
self._data.simulated_variations = {}
|
|
344
|
+
self._data.simulated_variations[ffv.feature_key] = ffv
|
|
345
|
+
|
|
346
|
+
def _add_forced_experiment_variation(self, context: DataAddingContext) -> None:
|
|
347
|
+
fev = cast(ForcedExperimentVariation, context.data)
|
|
348
|
+
if self._data.forced_variations is None:
|
|
349
|
+
self._data.forced_variations = {}
|
|
350
|
+
self._data.forced_variations[fev.rule.experiment.id_] = fev
|
|
351
|
+
|
|
297
352
|
def _set_browser(self, context: DataAddingContext) -> None:
|
|
298
353
|
if context.overwrite or self._data.browser is None:
|
|
299
354
|
self._data.browser = cast(Browser, context.data)
|
|
@@ -372,5 +427,7 @@ class Visitor:
|
|
|
372
427
|
KcsHeat: _set_kcs_heat,
|
|
373
428
|
VisitorVisits: _set_visitor_visits,
|
|
374
429
|
AssignedVariation: _add_variation,
|
|
430
|
+
ForcedFeatureVariation: _add_forced_feature_variation,
|
|
431
|
+
ForcedExperimentVariation: _add_forced_experiment_variation,
|
|
375
432
|
UniqueIdentifier: _set_is_unique_identifier,
|
|
376
433
|
}
|
|
@@ -70,6 +70,15 @@ class FeatureNotFound(NotFoundError):
|
|
|
70
70
|
super().__init__(self.message)
|
|
71
71
|
|
|
72
72
|
|
|
73
|
+
class FeatureExperimentNotFound(NotFoundError): # //~ Derived from FeatureError in other SDKs
|
|
74
|
+
"""Exception indicating that the requested experiment has not been found.
|
|
75
|
+
Check that the experiment's ID matches the provided one."""
|
|
76
|
+
|
|
77
|
+
def __init__(self, message=None) -> None:
|
|
78
|
+
self.message = "Experiment " + str(message)
|
|
79
|
+
super().__init__(self.message)
|
|
80
|
+
|
|
81
|
+
|
|
73
82
|
class FeatureVariableNotFound(NotFoundError):
|
|
74
83
|
"""Exception indicating that the requested variable has not been found.
|
|
75
84
|
Check that the variable's ID (or key) matches the one in your code."""
|
{kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/functions.py
RENAMED
|
@@ -1,46 +1,8 @@
|
|
|
1
1
|
"""Helper functions"""
|
|
2
|
-
import hashlib
|
|
3
2
|
import json
|
|
4
|
-
import math
|
|
5
3
|
import sys
|
|
6
4
|
from enum import Enum
|
|
7
|
-
from typing import Dict, Any, Optional,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def obtain_hash_double(
|
|
11
|
-
visitor_code: str, respool_times=None, container_id: str = ""
|
|
12
|
-
) -> float:
|
|
13
|
-
"""Calculate the hash value for a given visitor_code"""
|
|
14
|
-
return _obtain_hash_double(visitor_code, respool_times, container_id)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def obtain_hash_double_rule(
|
|
18
|
-
visitor_code: str, container_id: int, respool_time: Optional[int] = None
|
|
19
|
-
) -> float:
|
|
20
|
-
"""Calculate the hash value for feature flag v2 for a given visitor_code"""
|
|
21
|
-
return _obtain_hash_double(
|
|
22
|
-
visitor_code=visitor_code,
|
|
23
|
-
container_id=container_id,
|
|
24
|
-
suffix=str(respool_time) if respool_time else "",
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def _obtain_hash_double(
|
|
29
|
-
visitor_code: str,
|
|
30
|
-
respool_times=None,
|
|
31
|
-
container_id: Union[str, int] = "",
|
|
32
|
-
suffix: str = "",
|
|
33
|
-
) -> float:
|
|
34
|
-
if respool_times is None:
|
|
35
|
-
respool_times = {}
|
|
36
|
-
identifier = visitor_code
|
|
37
|
-
identifier += str(container_id)
|
|
38
|
-
identifier += suffix
|
|
39
|
-
if respool_times:
|
|
40
|
-
identifier += "".join([str(v) for k, v in sorted(respool_times.items())])
|
|
41
|
-
return int(hashlib.sha256(identifier.encode("UTF-8")).hexdigest(), 16) / math.pow(
|
|
42
|
-
2, 256
|
|
43
|
-
)
|
|
5
|
+
from typing import Dict, Any, Optional, Type, TypeVar
|
|
44
6
|
|
|
45
7
|
|
|
46
8
|
def load_params_from_json(json_path) -> Dict[Any, Any]:
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Helper hash functions"""
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import math
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Hasher:
|
|
9
|
+
"""Hasher"""
|
|
10
|
+
|
|
11
|
+
@staticmethod
|
|
12
|
+
def obtain(
|
|
13
|
+
visitor_code: str, container_id: int, respool_time: Optional[int] = None
|
|
14
|
+
) -> float:
|
|
15
|
+
"""Calculate the hash value for feature flag v2 for a given visitor_code"""
|
|
16
|
+
identifier = visitor_code
|
|
17
|
+
identifier += str(container_id)
|
|
18
|
+
if respool_time:
|
|
19
|
+
identifier += str(respool_time)
|
|
20
|
+
return Hasher._calculate(identifier)
|
|
21
|
+
|
|
22
|
+
@staticmethod
|
|
23
|
+
def _calculate(str_to_hash: str) -> float:
|
|
24
|
+
return int(hashlib.sha256(str_to_hash.encode("UTF-8")).hexdigest(), 16) / math.pow(2, 256)
|