kameleoon-client-python 3.6.0__tar.gz → 3.7.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.0 → kameleoon-client-python-3.7.0}/PKG-INFO +1 -1
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/data_file.py +24 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/rule.py +11 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/data.py +2 -0
- kameleoon-client-python-3.7.0/kameleoon/data/manager/forced_experiment_variation.py +49 -0
- kameleoon-client-python-3.7.0/kameleoon/data/manager/forced_feature_variation.py +46 -0
- kameleoon-client-python-3.7.0/kameleoon/data/manager/forced_variation.py +33 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/manager/visitor.py +59 -2
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/exceptions.py +9 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/helpers/domain.py +6 -3
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/kameleoon_client.py +93 -26
- kameleoon-client-python-3.7.0/kameleoon/network/cookie/cookie_manager.py +198 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/uri_helper.py +6 -1
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/sdk_version.py +1 -1
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon_client_python.egg-info/PKG-INFO +1 -1
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon_client_python.egg-info/SOURCES.txt +3 -0
- kameleoon-client-python-3.6.0/kameleoon/network/cookie/cookie_manager.py +0 -107
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/MANIFEST.in +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/README.md +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/client_readiness/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/client_readiness/async_readiness.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/client_readiness/threading_readiness.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/custom_data_info.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/feature_flag.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/rule_type.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/settings.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/variable.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/variation.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/variation_by_exposition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/browser.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/conversion.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/cookie.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/custom_data.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/device.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/geolocation.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/kcs_heat.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/manager/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/manager/assigned_variation.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/manager/page_view_visit.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/manager/visitor_manager.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/manager/visitor_slot.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/mapping_identifier.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/operating_system.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/page_view.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/unique_identifier.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/user_agent.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/data/visitor_visits.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/defaults.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/helpers/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/helpers/functions.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/helpers/logger.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/helpers/multi_threading.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/helpers/nonce.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/helpers/repeat_timer.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/helpers/scheduler.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/helpers/string_utils.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/helpers/visitor_code.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/hybrid/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/hybrid/hybrid_manager.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/hybrid/hybrid_manager_impl.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/kameleoon_client_config.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/kameleoon_client_factory.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/logging/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/logging/kameleoon_logger.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/logging/log_level.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/logging/logger.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/asyncexec/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/asyncexec/async_executor.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/data/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/data/data_manager.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/remote_data/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/remote_data/remote_data_manager.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/remote_data/remote_visitor_data.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/tracking/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/tracking/tracking_builder.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/tracking/tracking_manager.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/tracking/visitor_tracking_registry.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/warehouse/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/managers/warehouse/warehouse_manager.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/middleware.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/access_token_source.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/access_token_source_factory.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/activity_event.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/cookie/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/net_provider.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/net_provider_impl.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/network_manager.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/network_manager_factory.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/network_manager_factory_impl.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/network_manager_impl.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/query_builder.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/query_encodable.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/sendable.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/service_initialize_context.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/service_initialize_context_impl.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/services/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/services/automation_service.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/services/automation_service_impl.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/services/configuration_service.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/services/configuration_service_impl.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/services/data_service.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/services/data_service_impl.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/services/service.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/services/service_impl.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/network/url_provider.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/real_time/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/real_time/real_time_configuration_service.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/real_time/real_time_event.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/storage/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/storage/cache.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/storage/cache_factory.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/storage/cache_factory_impl.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/storage/cache_impl.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/browser_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/constants.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/conversion_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/cookie_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/custom_datum.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/device_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/exclusive_feature_flag_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/geolocation_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/kcs_heat_range_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/number_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/operating_system_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/page_title_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/page_url_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/page_view_number_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/previous_page_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/sdk_language_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/segment_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/string_value_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/target_feature_flag_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/targeting_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/unknown_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/visit_number_today_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/visit_number_total_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/conditions/visitor_new_return_condition.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/models.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/targeting_manager.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/tree_builder.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/targeting/tree_condition_factory.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/types/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/types/remote_visitor_data_filter.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/types/variable.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/types/variation.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon_client_python.egg-info/requires.txt +15 -15
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/setup.cfg +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/setup.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/kameleoon_app/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/kameleoon_app/apps.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/kameleoon_app/migrations/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/kameleoon_app/views.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/manage.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/proj/__init__.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/proj/asgi.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/proj/settings.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/proj/urls.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/integration/proj/proj/wsgi.py +0 -0
- {kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/tests/resources/config.yml +0 -0
{kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/data_file.py
RENAMED
|
@@ -56,6 +56,7 @@ class DataFile:
|
|
|
56
56
|
)
|
|
57
57
|
self.__variation_by_id: Dict[int, VariationByExposition] = {}
|
|
58
58
|
self.__rule_by_segment_id: Dict[int, Rule] = {}
|
|
59
|
+
self.__rule_info_by_exp_id: Dict[int, DataFile.RuleInfo] = {}
|
|
59
60
|
self.__feature_flag_by_id: Dict[int, FeatureFlag] = {}
|
|
60
61
|
self.__experiment_ids_with_js_css_variable: Set[int] = set()
|
|
61
62
|
self.__collect_indices()
|
|
@@ -84,6 +85,11 @@ class DataFile:
|
|
|
84
85
|
"""Returns dictionary of all rule stored by segment id"""
|
|
85
86
|
return self.__rule_by_segment_id
|
|
86
87
|
|
|
88
|
+
@property
|
|
89
|
+
def rule_info_by_exp_id(self) -> Dict[int, "DataFile.RuleInfo"]:
|
|
90
|
+
"""Returns dictionary of all rule related info stored by experiment id"""
|
|
91
|
+
return self.__rule_info_by_exp_id
|
|
92
|
+
|
|
87
93
|
@property
|
|
88
94
|
def variation_by_id(self) -> Dict[int, VariationByExposition]:
|
|
89
95
|
"""Returns dictionary of all variations stored by id"""
|
|
@@ -122,6 +128,7 @@ class DataFile:
|
|
|
122
128
|
has_feature_flag_variable_js_css = self.__has_feature_flag_variable_js_css(feature_flag)
|
|
123
129
|
for rule in feature_flag.rules:
|
|
124
130
|
self.__rule_by_segment_id[rule.segment_id] = rule
|
|
131
|
+
self.__rule_info_by_exp_id[rule.experiment_id] = DataFile.RuleInfo(feature_flag, rule)
|
|
125
132
|
if has_feature_flag_variable_js_css:
|
|
126
133
|
self.__experiment_ids_with_js_css_variable.add(rule.experiment_id)
|
|
127
134
|
for variation in rule.variation_by_exposition:
|
|
@@ -146,3 +153,20 @@ class DataFile:
|
|
|
146
153
|
f"settings:{self.__settings}"
|
|
147
154
|
f"}}"
|
|
148
155
|
)
|
|
156
|
+
|
|
157
|
+
class RuleInfo:
|
|
158
|
+
"""Aggregates some information related to a specific rule"""
|
|
159
|
+
|
|
160
|
+
def __init__(self, feature_flag: FeatureFlag, rule: Rule) -> None:
|
|
161
|
+
self.__feature_flag = feature_flag
|
|
162
|
+
self.__rule = rule
|
|
163
|
+
|
|
164
|
+
@property
|
|
165
|
+
def feature_flag(self) -> FeatureFlag:
|
|
166
|
+
"""Returns the feature flag"""
|
|
167
|
+
return self.__feature_flag
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def rule(self) -> Rule:
|
|
171
|
+
"""Returns the rule"""
|
|
172
|
+
return self.__rule
|
{kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/configuration/rule.py
RENAMED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from typing import Any, List, Dict, Optional
|
|
4
4
|
from kameleoon.configuration.rule_type import RuleType, rule_type_from_literal
|
|
5
5
|
from kameleoon.configuration.variation_by_exposition import VariationByExposition
|
|
6
|
+
from kameleoon.exceptions import FeatureVariationNotFound
|
|
6
7
|
from kameleoon.targeting.models import Segment
|
|
7
8
|
|
|
8
9
|
|
|
@@ -43,6 +44,16 @@ class Rule:
|
|
|
43
44
|
return var_by_exp
|
|
44
45
|
return None
|
|
45
46
|
|
|
47
|
+
def get_variation_by_key(self, variation_key: str) -> VariationByExposition:
|
|
48
|
+
"""
|
|
49
|
+
Finds variation with a passed variation key.
|
|
50
|
+
Raises the `FeatureVariationNotFound` exception if such variation does not exist.
|
|
51
|
+
"""
|
|
52
|
+
for var_by_exp in self.variation_by_exposition:
|
|
53
|
+
if var_by_exp.variation_key == variation_key:
|
|
54
|
+
return var_by_exp
|
|
55
|
+
raise FeatureVariationNotFound("'#{variation_key}'")
|
|
56
|
+
|
|
46
57
|
@property
|
|
47
58
|
def is_experimentation(self) -> bool:
|
|
48
59
|
"""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.0 → kameleoon-client-python-3.7.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."""
|
|
@@ -9,6 +9,7 @@ REGEX_DOMAIN = (
|
|
|
9
9
|
r"^(\.?(([a-zA-Z\d][a-zA-Z\d-]*[a-zA-Z\d])|[a-zA-Z\d]))"
|
|
10
10
|
r"(\.(([a-zA-Z\d][a-zA-Z\d-]*[a-zA-Z\d])|[a-zA-Z\d])){1,126}$"
|
|
11
11
|
)
|
|
12
|
+
LOCALHOST = "localhost"
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
def validate_top_level_domain(top_level_domain: str) -> str:
|
|
@@ -35,8 +36,10 @@ def validate_top_level_domain(top_level_domain: str) -> str:
|
|
|
35
36
|
protocol, top_level_domain)
|
|
36
37
|
break
|
|
37
38
|
|
|
38
|
-
if not re.match(REGEX_DOMAIN, top_level_domain):
|
|
39
|
-
KameleoonLogger.error(
|
|
40
|
-
|
|
39
|
+
if not re.match(REGEX_DOMAIN, top_level_domain) and top_level_domain != LOCALHOST:
|
|
40
|
+
KameleoonLogger.error(
|
|
41
|
+
f"The top-level domain '{top_level_domain}' is invalid. The value has been set as provided, but it does "
|
|
42
|
+
f"not meet the required format for proper SDK functionality. Please check the domain for correctness.")
|
|
43
|
+
return top_level_domain
|
|
41
44
|
|
|
42
45
|
return top_level_domain
|
{kameleoon-client-python-3.6.0 → kameleoon-client-python-3.7.0}/kameleoon/kameleoon_client.py
RENAMED
|
@@ -14,10 +14,12 @@ from kameleoon.configuration.variation_by_exposition import VariationByExpositio
|
|
|
14
14
|
|
|
15
15
|
from kameleoon.data import Conversion, CustomData, Data, UniqueIdentifier
|
|
16
16
|
from kameleoon.data.manager.assigned_variation import AssignedVariation
|
|
17
|
+
from kameleoon.data.manager.forced_experiment_variation import ForcedExperimentVariation
|
|
17
18
|
from kameleoon.data.manager.visitor_manager import VisitorManager
|
|
18
19
|
|
|
19
20
|
from kameleoon.exceptions import (
|
|
20
21
|
FeatureVariationNotFound,
|
|
22
|
+
FeatureExperimentNotFound,
|
|
21
23
|
FeatureVariableNotFound,
|
|
22
24
|
FeatureEnvironmentDisabled,
|
|
23
25
|
SiteCodeIsEmpty,
|
|
@@ -130,7 +132,7 @@ class KameleoonClient:
|
|
|
130
132
|
)
|
|
131
133
|
self._hybrid_manager = HybridManagerImpl(HYBRID_EXPIRATION_TIME, self._data_manager)
|
|
132
134
|
|
|
133
|
-
self._cookie_manager = CookieManager(self._data_manager, config.top_level_domain)
|
|
135
|
+
self._cookie_manager = CookieManager(self._data_manager, self._visitor_manager, config.top_level_domain)
|
|
134
136
|
atsf = AccessTokenSourceFactory(config.client_id, config.client_secret)
|
|
135
137
|
self._network_manager = self._network_manager_factory.create(
|
|
136
138
|
self.site_code,
|
|
@@ -589,9 +591,13 @@ class KameleoonClient:
|
|
|
589
591
|
"CALL: KameleoonClient.__get_variation_info(visitor_code: %s, feature_flag: %s, track: %s)",
|
|
590
592
|
visitor_code, feature_flag, track
|
|
591
593
|
)
|
|
592
|
-
|
|
594
|
+
visitor = self._visitor_manager.get_visitor(visitor_code)
|
|
595
|
+
forced_variation = visitor.get_forced_feature_variation(feature_flag.feature_key) if visitor else None
|
|
596
|
+
var_by_exp, rule = (forced_variation.var_by_exp, forced_variation.rule) if forced_variation else \
|
|
597
|
+
self.__calculate_variation_rule_for_feature(visitor_code, feature_flag)
|
|
598
|
+
if not (forced_variation and forced_variation.simulated):
|
|
599
|
+
self.__save_variation(visitor_code, rule, var_by_exp, track)
|
|
593
600
|
variation_key = self.__calculate_variation_key(var_by_exp, rule, feature_flag)
|
|
594
|
-
self.__save_variation(visitor_code, rule, var_by_exp, track)
|
|
595
601
|
KameleoonLogger.debug(
|
|
596
602
|
"RETURN: KameleoonClient.__get_variation_info(visitor_code: %s, feature_flag: %s, track: %s)"
|
|
597
603
|
" -> (variation_key: %s, variation_by_exposition: %s, rule: %s)",
|
|
@@ -942,11 +948,14 @@ class KameleoonClient:
|
|
|
942
948
|
"Call to deprecated function `get_active_feature_list_for_visitor`. "
|
|
943
949
|
"Please use `get_active_features` instead."
|
|
944
950
|
)
|
|
951
|
+
visitor = self._visitor_manager.get_visitor(visitor_code)
|
|
945
952
|
|
|
946
953
|
def filter_conditions(feature_flag: FeatureFlag) -> bool:
|
|
947
954
|
if not feature_flag.environment_enabled:
|
|
948
955
|
return False
|
|
949
|
-
|
|
956
|
+
forced_variation = visitor.get_forced_feature_variation(feature_flag.feature_key) if visitor else None
|
|
957
|
+
variation, rule = (forced_variation.var_by_exp, forced_variation.rule) if forced_variation else \
|
|
958
|
+
self.__calculate_variation_rule_for_feature(visitor_code, feature_flag)
|
|
950
959
|
variation_key = self.__calculate_variation_key(variation, rule, feature_flag)
|
|
951
960
|
return variation_key != configuration.Variation.Type.OFF.value
|
|
952
961
|
|
|
@@ -987,11 +996,14 @@ class KameleoonClient:
|
|
|
987
996
|
)
|
|
988
997
|
KameleoonLogger.info("CALL: KameleoonClient.get_active_features(visitor_code: %s)", visitor_code)
|
|
989
998
|
validate_visitor_code(visitor_code)
|
|
999
|
+
visitor = self._visitor_manager.get_visitor(visitor_code)
|
|
990
1000
|
map_active_features: Dict[str, Variation] = {}
|
|
991
1001
|
for feature_flag in self._data_manager.data_file.feature_flags.values():
|
|
992
1002
|
if not feature_flag.environment_enabled:
|
|
993
1003
|
continue
|
|
994
|
-
|
|
1004
|
+
forced_variation = visitor.get_forced_feature_variation(feature_flag.feature_key) if visitor else None
|
|
1005
|
+
var_by_exp, rule = (forced_variation.var_by_exp, forced_variation.rule) if forced_variation else \
|
|
1006
|
+
self.__calculate_variation_rule_for_feature(visitor_code, feature_flag)
|
|
995
1007
|
variation_key = self.__calculate_variation_key(var_by_exp, rule, feature_flag)
|
|
996
1008
|
if variation_key == configuration.Variation.Type.OFF.value:
|
|
997
1009
|
continue
|
|
@@ -1303,9 +1315,13 @@ class KameleoonClient:
|
|
|
1303
1315
|
"CALL: KameleoonClient.__get_feature_variation_key(visitor_code: %s, feature_key: %s)",
|
|
1304
1316
|
visitor_code, feature_key)
|
|
1305
1317
|
feature_flag = self._data_manager.data_file.get_feature_flag(feature_key)
|
|
1306
|
-
|
|
1318
|
+
visitor = self._visitor_manager.get_visitor(visitor_code)
|
|
1319
|
+
forced_variation = visitor.get_forced_feature_variation(feature_key) if visitor else None
|
|
1320
|
+
variation, rule = (forced_variation.var_by_exp, forced_variation.rule) if forced_variation else \
|
|
1321
|
+
self.__calculate_variation_rule_for_feature(visitor_code, feature_flag)
|
|
1322
|
+
if not (forced_variation and forced_variation.simulated):
|
|
1323
|
+
self.__save_variation(visitor_code, rule, variation)
|
|
1307
1324
|
variation_key = self.__calculate_variation_key(variation, rule, feature_flag)
|
|
1308
|
-
self.__save_variation(visitor_code, rule, variation)
|
|
1309
1325
|
self._tracking_manager.add_visitor_code(visitor_code)
|
|
1310
1326
|
KameleoonLogger.debug(
|
|
1311
1327
|
"RETURN: KameleoonClient.__get_feature_variation_key(visitor_code: %s, feature_key: %s) -> "
|
|
@@ -1338,28 +1354,36 @@ class KameleoonClient:
|
|
|
1338
1354
|
KameleoonLogger.debug(
|
|
1339
1355
|
"CALL: KameleoonClient.__calculate_variation_rule_for_feature(visitor_code: %s, feature_flag: %s)",
|
|
1340
1356
|
visitor_code, feature_flag)
|
|
1357
|
+
visitor = self._visitor_manager.get_visitor(visitor_code)
|
|
1358
|
+
# use mappingIdentifier instead of visitorCode if it was set up
|
|
1359
|
+
code_for_hash = (
|
|
1360
|
+
visitor.mapping_identifier
|
|
1361
|
+
if visitor is not None and visitor.mapping_identifier is not None
|
|
1362
|
+
else visitor_code
|
|
1363
|
+
)
|
|
1364
|
+
selected_variation = None
|
|
1365
|
+
selected_rule = None
|
|
1341
1366
|
for rule in feature_flag.rules:
|
|
1367
|
+
forced_variation = visitor.get_forced_experiment_variation(rule.experiment_id) if visitor else None
|
|
1368
|
+
if forced_variation and forced_variation.force_targeting:
|
|
1369
|
+
# Forcing experiment variation in force-targeting mode
|
|
1370
|
+
selected_variation, selected_rule = forced_variation.var_by_exp, rule
|
|
1371
|
+
break
|
|
1342
1372
|
# check if visitor is targeted for rule, else next rule
|
|
1343
1373
|
if not self.__check_targeting(visitor_code, rule.experiment_id, rule):
|
|
1344
1374
|
continue
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
if visitor is not None and visitor.mapping_identifier is not None
|
|
1350
|
-
else visitor_code
|
|
1351
|
-
)
|
|
1375
|
+
if forced_variation:
|
|
1376
|
+
# Forcing experiment variation in targeting-only mode
|
|
1377
|
+
selected_variation, selected_rule = forced_variation.var_by_exp, rule
|
|
1378
|
+
break
|
|
1352
1379
|
# uses for rule exposition
|
|
1353
1380
|
hash_rule = obtain_hash_double_rule(code_for_hash, rule.id_, rule.respool_time)
|
|
1354
1381
|
KameleoonLogger.debug("Calculated hash_rule: %s for visitor_code: %s", hash_rule, code_for_hash)
|
|
1355
1382
|
# check main expostion for rule with hashRule
|
|
1356
1383
|
if hash_rule <= rule.exposition:
|
|
1357
1384
|
if rule.is_targeted_delivery:
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
"feature_flag: %s) -> (variation: %s, rule: %s)",
|
|
1361
|
-
visitor_code, feature_flag, rule.first_variation, rule)
|
|
1362
|
-
return (rule.first_variation, rule)
|
|
1385
|
+
selected_variation, selected_rule = rule.first_variation, rule
|
|
1386
|
+
break
|
|
1363
1387
|
|
|
1364
1388
|
# uses for variation's expositions
|
|
1365
1389
|
hash_variation = obtain_hash_double_rule(code_for_hash, rule.experiment_id, rule.respool_time)
|
|
@@ -1368,17 +1392,14 @@ class KameleoonClient:
|
|
|
1368
1392
|
# get variation with hash_variation
|
|
1369
1393
|
variation = rule.get_variation(hash_variation)
|
|
1370
1394
|
if variation:
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
"feature_flag: %s) -> (variation: %s, rule: %s)",
|
|
1374
|
-
visitor_code, feature_flag, variation, rule)
|
|
1375
|
-
return (variation, rule)
|
|
1395
|
+
selected_variation, selected_rule = variation, rule
|
|
1396
|
+
break
|
|
1376
1397
|
elif rule.is_targeted_delivery:
|
|
1377
1398
|
break
|
|
1378
1399
|
KameleoonLogger.debug(
|
|
1379
1400
|
"RETURN: KameleoonClient.__calculate_variation_rule_for_feature(visitor_code: %s, feature_flag: %s) "
|
|
1380
|
-
"-> (variation:
|
|
1381
|
-
return
|
|
1401
|
+
"-> (variation: %s, rule: %s)", visitor_code, feature_flag, selected_variation, selected_rule)
|
|
1402
|
+
return selected_variation, selected_rule
|
|
1382
1403
|
|
|
1383
1404
|
@staticmethod
|
|
1384
1405
|
def __calculate_variation_key(
|
|
@@ -1409,3 +1430,49 @@ class KameleoonClient:
|
|
|
1409
1430
|
def _is_consent_given(self, visitor_code: str) -> bool:
|
|
1410
1431
|
return not self._data_manager.data_file.settings.is_consent_required or \
|
|
1411
1432
|
((visitor := self._visitor_manager.get_visitor(visitor_code)) is not None) and visitor.legal_consent
|
|
1433
|
+
|
|
1434
|
+
def set_forced_variation(
|
|
1435
|
+
self, visitor_code: str, experiment_id: int, variation_key: Optional[str], force_targeting=True
|
|
1436
|
+
) -> None:
|
|
1437
|
+
"""
|
|
1438
|
+
Sets or resets a forced variation for a visitor in a specific experiment,
|
|
1439
|
+
so the experiment will be evaluated to the variation for the visitor.
|
|
1440
|
+
|
|
1441
|
+
In order to reset the forced variation set the `variation_key` parameter to `None`.
|
|
1442
|
+
If the forced variation you want to reset does not exist, the method will have no effect.
|
|
1443
|
+
|
|
1444
|
+
:param visitor_code: The unique visitor code identifying the visitor.
|
|
1445
|
+
:type visitor_code: str
|
|
1446
|
+
:param experiment_id: The identifier of the experiment you want to set/reset the forced variation for.
|
|
1447
|
+
:type experiment_id: int
|
|
1448
|
+
:param variation_key: The identifier of the variation you want the experiment to be evaluated to. \
|
|
1449
|
+
Set to `None` to reset the forced variation.
|
|
1450
|
+
:type variation_key: Optional[str]
|
|
1451
|
+
:param force_targeting: If `True`, the visitor will be targeted to the experiment regardless its conditions. \
|
|
1452
|
+
Otherwise, the normal targeting logic will be preserved. Optional (defaults to `True`).
|
|
1453
|
+
:type force_targeting: bool
|
|
1454
|
+
|
|
1455
|
+
:raises VisitorCodeInvalid: The provided **visitor code** is invalid.
|
|
1456
|
+
:raises FeatureExperimentNotFound: The provided **experiment id** does not exist in the feature flag.
|
|
1457
|
+
:raises FeatureVariationNotFound: The provided **variation key** does not belong to the experiment.
|
|
1458
|
+
"""
|
|
1459
|
+
KameleoonLogger.info(
|
|
1460
|
+
"CALL: KameleoonClient.set_forced_variation(visitor_code: %s, experiment_id: %s, variation_key: %s, "
|
|
1461
|
+
"force_targeting: %s)", visitor_code, experiment_id, variation_key, force_targeting
|
|
1462
|
+
)
|
|
1463
|
+
validate_visitor_code(visitor_code)
|
|
1464
|
+
if variation_key is None:
|
|
1465
|
+
visitor = self._visitor_manager.get_visitor(visitor_code)
|
|
1466
|
+
if visitor:
|
|
1467
|
+
visitor.reset_forced_experiment_variation(experiment_id)
|
|
1468
|
+
else:
|
|
1469
|
+
rule_info = self._data_manager.data_file.rule_info_by_exp_id.get(experiment_id)
|
|
1470
|
+
if rule_info is None:
|
|
1471
|
+
raise FeatureExperimentNotFound(experiment_id)
|
|
1472
|
+
var_by_exp = rule_info.rule.get_variation_by_key(variation_key)
|
|
1473
|
+
forced_variation = ForcedExperimentVariation(rule_info.rule, var_by_exp, force_targeting)
|
|
1474
|
+
self._visitor_manager.add_data(visitor_code, forced_variation)
|
|
1475
|
+
KameleoonLogger.info(
|
|
1476
|
+
"RETURN: KameleoonClient.set_forced_variation(visitor_code: %s, experiment_id: %s, variation_key: %s, "
|
|
1477
|
+
"force_targeting: %s)", visitor_code, experiment_id, variation_key, force_targeting
|
|
1478
|
+
)
|