kameleoon-client-python 3.7.0__tar.gz → 3.9.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.7.0 → kameleoon-client-python-3.9.0}/PKG-INFO +1 -1
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/data_file.py +41 -11
- kameleoon-client-python-3.9.0/kameleoon/configuration/experiment.py +46 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/feature_flag.py +3 -1
- kameleoon-client-python-3.9.0/kameleoon/configuration/me_group.py +24 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/rule.py +2 -27
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/manager/visitor.py +1 -1
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/exceptions.py +1 -1
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/helpers/functions.py +1 -39
- kameleoon-client-python-3.9.0/kameleoon/helpers/hasher.py +29 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/kameleoon_client.py +162 -100
- kameleoon-client-python-3.9.0/kameleoon/managers/evaluation/evaluated_experiment.py +50 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/cookie/cookie_manager.py +4 -2
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/sdk_version.py +1 -1
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/target_feature_flag_condition.py +2 -2
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon_client_python.egg-info/PKG-INFO +1 -1
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon_client_python.egg-info/SOURCES.txt +5 -0
- kameleoon-client-python-3.9.0/tests/integration/proj/proj/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/MANIFEST.in +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/README.md +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/client_readiness/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/client_readiness/async_readiness.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/client_readiness/threading_readiness.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/custom_data_info.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/rule_type.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/settings.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/variable.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/variation.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/variation_by_exposition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/browser.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/conversion.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/cookie.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/custom_data.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/data.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/device.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/geolocation.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/kcs_heat.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/manager/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/manager/assigned_variation.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/manager/forced_experiment_variation.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/manager/forced_feature_variation.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/manager/forced_variation.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/manager/page_view_visit.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/manager/visitor_manager.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/manager/visitor_slot.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/mapping_identifier.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/operating_system.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/page_view.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/unique_identifier.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/user_agent.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/visitor_visits.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/defaults.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/helpers/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/helpers/domain.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/helpers/logger.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/helpers/multi_threading.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/helpers/nonce.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/helpers/repeat_timer.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/helpers/scheduler.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/helpers/string_utils.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/helpers/visitor_code.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/hybrid/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/hybrid/hybrid_manager.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/hybrid/hybrid_manager_impl.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/kameleoon_client_config.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/kameleoon_client_factory.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/logging/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/logging/kameleoon_logger.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/logging/log_level.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/logging/logger.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/managers/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/managers/asyncexec/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/managers/asyncexec/async_executor.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/managers/data/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/managers/data/data_manager.py +0 -0
- {kameleoon-client-python-3.7.0/kameleoon/managers/remote_data → kameleoon-client-python-3.9.0/kameleoon/managers/evaluation}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0/kameleoon/managers/tracking → kameleoon-client-python-3.9.0/kameleoon/managers/remote_data}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/managers/remote_data/remote_data_manager.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/managers/remote_data/remote_visitor_data.py +0 -0
- {kameleoon-client-python-3.7.0/kameleoon/managers/warehouse → kameleoon-client-python-3.9.0/kameleoon/managers/tracking}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/managers/tracking/tracking_builder.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/managers/tracking/tracking_manager.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/managers/tracking/visitor_tracking_registry.py +0 -0
- {kameleoon-client-python-3.7.0/kameleoon/network → kameleoon-client-python-3.9.0/kameleoon/managers/warehouse}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/managers/warehouse/warehouse_manager.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/middleware.py +0 -0
- {kameleoon-client-python-3.7.0/kameleoon/network/cookie → kameleoon-client-python-3.9.0/kameleoon/network}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/access_token_source.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/access_token_source_factory.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/activity_event.py +0 -0
- {kameleoon-client-python-3.7.0/kameleoon/network/services → kameleoon-client-python-3.9.0/kameleoon/network/cookie}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/net_provider.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/net_provider_impl.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/network_manager.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/network_manager_factory.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/network_manager_factory_impl.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/network_manager_impl.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/query_builder.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/query_encodable.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/sendable.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/service_initialize_context.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/service_initialize_context_impl.py +0 -0
- {kameleoon-client-python-3.7.0/kameleoon/real_time → kameleoon-client-python-3.9.0/kameleoon/network/services}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/services/automation_service.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/services/automation_service_impl.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/services/configuration_service.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/services/configuration_service_impl.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/services/data_service.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/services/data_service_impl.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/services/service.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/services/service_impl.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/uri_helper.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/network/url_provider.py +0 -0
- {kameleoon-client-python-3.7.0/kameleoon/storage → kameleoon-client-python-3.9.0/kameleoon/real_time}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/real_time/real_time_configuration_service.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/real_time/real_time_event.py +0 -0
- {kameleoon-client-python-3.7.0/kameleoon/targeting → kameleoon-client-python-3.9.0/kameleoon/storage}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/storage/cache.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/storage/cache_factory.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/storage/cache_factory_impl.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/storage/cache_impl.py +0 -0
- {kameleoon-client-python-3.7.0/kameleoon/targeting/conditions → kameleoon-client-python-3.9.0/kameleoon/targeting}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0/kameleoon/types → kameleoon-client-python-3.9.0/kameleoon/targeting/conditions}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/browser_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/constants.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/conversion_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/cookie_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/custom_datum.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/device_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/exclusive_feature_flag_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/geolocation_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/kcs_heat_range_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/number_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/operating_system_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/page_title_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/page_url_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/page_view_number_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/previous_page_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/sdk_language_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/segment_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/string_value_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/targeting_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/unknown_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/visit_number_today_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/visit_number_total_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/conditions/visitor_new_return_condition.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/models.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/targeting_manager.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/tree_builder.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/targeting/tree_condition_factory.py +0 -0
- {kameleoon-client-python-3.7.0/tests/integration/proj → kameleoon-client-python-3.9.0/kameleoon/types}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/types/remote_visitor_data_filter.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/types/variable.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/types/variation.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon_client_python.egg-info/requires.txt +12 -12
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/setup.cfg +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/setup.py +0 -0
- {kameleoon-client-python-3.7.0/tests/integration/proj/kameleoon_app → kameleoon-client-python-3.9.0/tests/integration/proj}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0/tests/integration/proj/kameleoon_app/migrations → kameleoon-client-python-3.9.0/tests/integration/proj/kameleoon_app}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/tests/integration/proj/kameleoon_app/apps.py +0 -0
- {kameleoon-client-python-3.7.0/tests/integration/proj/proj → kameleoon-client-python-3.9.0/tests/integration/proj/kameleoon_app/migrations}/__init__.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/tests/integration/proj/kameleoon_app/views.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/tests/integration/proj/manage.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/tests/integration/proj/proj/asgi.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/tests/integration/proj/proj/settings.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/tests/integration/proj/proj/urls.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/tests/integration/proj/proj/wsgi.py +0 -0
- {kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/tests/resources/config.yml +0 -0
{kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/data_file.py
RENAMED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"""Kameleoon Configuration"""
|
|
2
2
|
|
|
3
|
-
from typing import Any, Dict, Optional, Set
|
|
3
|
+
from typing import Any, Dict, Iterable, List, 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
|
+
from kameleoon.configuration.me_group import MEGroup
|
|
8
9
|
from kameleoon.configuration.rule import Rule
|
|
9
10
|
from kameleoon.configuration.settings import Settings
|
|
11
|
+
from kameleoon.configuration.variation_by_exposition import VariationByExposition
|
|
10
12
|
from kameleoon.exceptions import FeatureNotFound, FeatureEnvironmentDisabled
|
|
11
13
|
from kameleoon.logging.kameleoon_logger import KameleoonLogger
|
|
12
14
|
|
|
@@ -31,7 +33,8 @@ class DataFile:
|
|
|
31
33
|
for jobj in configuration.get("featureFlags") or []
|
|
32
34
|
}
|
|
33
35
|
custom_data_info = CustomDataInfo(configuration.get("customData"))
|
|
34
|
-
|
|
36
|
+
holdout = Experiment.from_json(configuration["holdout"]) if "holdout" in configuration else None
|
|
37
|
+
data_file = DataFile(environment, settings, feature_flags, custom_data_info, holdout)
|
|
35
38
|
return data_file
|
|
36
39
|
|
|
37
40
|
# pylint: disable=R0913
|
|
@@ -41,13 +44,16 @@ class DataFile:
|
|
|
41
44
|
settings: Settings,
|
|
42
45
|
feature_flags: Dict[str, FeatureFlag],
|
|
43
46
|
custom_data_info: CustomDataInfo,
|
|
47
|
+
holdout: Optional[Experiment] = None,
|
|
44
48
|
) -> None:
|
|
45
49
|
KameleoonLogger.debug(
|
|
46
|
-
'CALL: DataFile(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s)',
|
|
47
|
-
environment, settings, feature_flags, custom_data_info
|
|
50
|
+
'CALL: DataFile(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s, holdout: %s)',
|
|
51
|
+
environment, settings, feature_flags, custom_data_info, holdout
|
|
52
|
+
)
|
|
48
53
|
self.__environment = environment # pylint: disable=W0238
|
|
49
54
|
self.__settings = settings
|
|
50
55
|
self.__feature_flags: Dict[str, FeatureFlag] = feature_flags
|
|
56
|
+
self.__me_groups = self.__make_me_groups(feature_flags.values())
|
|
51
57
|
self.__has_any_targeted_delivery_rule = any(
|
|
52
58
|
rule.is_targeted_delivery
|
|
53
59
|
for ff in self.__feature_flags.values()
|
|
@@ -61,9 +67,11 @@ class DataFile:
|
|
|
61
67
|
self.__experiment_ids_with_js_css_variable: Set[int] = set()
|
|
62
68
|
self.__collect_indices()
|
|
63
69
|
self.__custom_data_info = custom_data_info
|
|
70
|
+
self.__holdout = holdout
|
|
64
71
|
KameleoonLogger.debug(
|
|
65
|
-
'RETURN: DataFile.new(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s)',
|
|
66
|
-
environment, settings, feature_flags, custom_data_info
|
|
72
|
+
'RETURN: DataFile.new(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s, holdout: %s)',
|
|
73
|
+
environment, settings, feature_flags, custom_data_info
|
|
74
|
+
)
|
|
67
75
|
|
|
68
76
|
@property
|
|
69
77
|
def settings(self) -> Settings:
|
|
@@ -75,6 +83,11 @@ class DataFile:
|
|
|
75
83
|
"""Returns dictionary of all feature flags stored by feature keys"""
|
|
76
84
|
return self.__feature_flags
|
|
77
85
|
|
|
86
|
+
@property
|
|
87
|
+
def me_groups(self) -> Dict[str, MEGroup]:
|
|
88
|
+
"""Returns the mutually exclusive groups by their names"""
|
|
89
|
+
return self.__me_groups
|
|
90
|
+
|
|
78
91
|
@property
|
|
79
92
|
def feature_flag_by_id(self) -> Dict[int, FeatureFlag]:
|
|
80
93
|
"""Returns dictionary of all feature flags stored by id"""
|
|
@@ -114,9 +127,14 @@ class DataFile:
|
|
|
114
127
|
|
|
115
128
|
@property
|
|
116
129
|
def custom_data_info(self) -> CustomDataInfo:
|
|
117
|
-
"""Returns custom data info for mapping device
|
|
130
|
+
"""Returns custom data info for mapping device"""
|
|
118
131
|
return self.__custom_data_info
|
|
119
132
|
|
|
133
|
+
@property
|
|
134
|
+
def holdout(self) -> Optional[Experiment]:
|
|
135
|
+
"""Returns holdout"""
|
|
136
|
+
return self.__holdout
|
|
137
|
+
|
|
120
138
|
def has_experiment_js_css_variable(self, experiment_id: int) -> bool:
|
|
121
139
|
"""Returns `True` if the experiment has a JS or CSS variable, otherwise returns `False`"""
|
|
122
140
|
return experiment_id in self.__experiment_ids_with_js_css_variable
|
|
@@ -128,13 +146,25 @@ class DataFile:
|
|
|
128
146
|
has_feature_flag_variable_js_css = self.__has_feature_flag_variable_js_css(feature_flag)
|
|
129
147
|
for rule in feature_flag.rules:
|
|
130
148
|
self.__rule_by_segment_id[rule.segment_id] = rule
|
|
131
|
-
self.__rule_info_by_exp_id[rule.
|
|
149
|
+
self.__rule_info_by_exp_id[rule.experiment.id_] = DataFile.RuleInfo(feature_flag, rule)
|
|
132
150
|
if has_feature_flag_variable_js_css:
|
|
133
|
-
self.__experiment_ids_with_js_css_variable.add(rule.
|
|
134
|
-
for variation in rule.
|
|
151
|
+
self.__experiment_ids_with_js_css_variable.add(rule.experiment.id_)
|
|
152
|
+
for variation in rule.experiment.variations_by_exposition:
|
|
135
153
|
if variation.variation_id is not None:
|
|
136
154
|
self.__variation_by_id[variation.variation_id] = variation
|
|
137
155
|
|
|
156
|
+
@staticmethod
|
|
157
|
+
def __make_me_groups(feature_flags: Iterable[FeatureFlag]) -> Dict[str, MEGroup]:
|
|
158
|
+
me_group_lists: Dict[str, List[FeatureFlag]] = {}
|
|
159
|
+
for feature_flag in feature_flags:
|
|
160
|
+
if feature_flag.me_group_name:
|
|
161
|
+
me_group_list = me_group_lists.get(feature_flag.me_group_name)
|
|
162
|
+
if me_group_list:
|
|
163
|
+
me_group_list.append(feature_flag)
|
|
164
|
+
else:
|
|
165
|
+
me_group_lists[feature_flag.me_group_name] = [feature_flag]
|
|
166
|
+
return {me_group_name: MEGroup(me_group_list) for me_group_name, me_group_list in me_group_lists.items()}
|
|
167
|
+
|
|
138
168
|
@staticmethod
|
|
139
169
|
def __has_feature_flag_variable_js_css(feature_flag: FeatureFlag) -> bool:
|
|
140
170
|
variations = feature_flag.variations
|
|
@@ -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_}}}"
|
|
@@ -17,10 +17,11 @@ class FeatureFlag:
|
|
|
17
17
|
"""Create a list of FeatureFlags from the json array"""
|
|
18
18
|
return [FeatureFlag(item) for item in array]
|
|
19
19
|
|
|
20
|
-
def __init__(self, dict_json: Dict[str, Any]):
|
|
20
|
+
def __init__(self, dict_json: Dict[str, Any]) -> None:
|
|
21
21
|
self.id_: int = dict_json.get("id", 0)
|
|
22
22
|
self.feature_key: str = dict_json.get("featureKey", "")
|
|
23
23
|
self.default_variation_key: str = dict_json.get("defaultVariationKey", "")
|
|
24
|
+
self.me_group_name: Optional[str] = dict_json.get("mutuallyExclusiveGroup")
|
|
24
25
|
self.variations: List[Variation] = Variation.from_array(
|
|
25
26
|
dict_json.get("variations", [])
|
|
26
27
|
)
|
|
@@ -39,6 +40,7 @@ class FeatureFlag:
|
|
|
39
40
|
f"environment_enabled:{self.environment_enabled},"
|
|
40
41
|
f"variations:{StringUtils.object_to_string(self.variations)},"
|
|
41
42
|
f"default_variation_key:'{self.default_variation_key}',"
|
|
43
|
+
f"me_group_name:'{self.me_group_name}',"
|
|
42
44
|
f"rules:{len(self.rules)}"
|
|
43
45
|
f"}}"
|
|
44
46
|
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Kameleoon Configuration"""
|
|
2
|
+
|
|
3
|
+
from typing import List
|
|
4
|
+
from kameleoon.configuration.feature_flag import FeatureFlag
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MEGroup:
|
|
8
|
+
"""Represents a mutually exclusive group"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, feature_flags: List[FeatureFlag]) -> None:
|
|
11
|
+
feature_flags.sort(key=lambda ff: ff.id_)
|
|
12
|
+
self.__feature_flags = feature_flags
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def feature_flags(self) -> List[FeatureFlag]:
|
|
16
|
+
"""Returns the feature flags"""
|
|
17
|
+
return self.__feature_flags
|
|
18
|
+
|
|
19
|
+
def get_feature_flag_by_hash(self, hash_double: float) -> FeatureFlag:
|
|
20
|
+
"""Finds a feature flag by the given hash"""
|
|
21
|
+
idx = int(hash_double * len(self.__feature_flags))
|
|
22
|
+
if idx >= len(self.__feature_flags):
|
|
23
|
+
idx = len(self.__feature_flags) - 1
|
|
24
|
+
return self.__feature_flags[idx]
|
{kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/configuration/rule.py
RENAMED
|
@@ -1,9 +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
|
-
from kameleoon.exceptions import FeatureVariationNotFound
|
|
7
6
|
from kameleoon.targeting.models import Segment
|
|
8
7
|
|
|
9
8
|
|
|
@@ -24,36 +23,12 @@ class Rule:
|
|
|
24
23
|
type_literal: str = dict_json.get("type", "")
|
|
25
24
|
self.type = rule_type_from_literal(type_literal)
|
|
26
25
|
self.exposition: float = dict_json.get("exposition", 0.0)
|
|
27
|
-
self.
|
|
26
|
+
self.experiment = Experiment.from_json(dict_json)
|
|
28
27
|
self.respool_time: Optional[int] = dict_json.get("respoolTime", None)
|
|
29
|
-
self.variation_by_exposition: List[VariationByExposition] = VariationByExposition.from_array(
|
|
30
|
-
dict_json.get("variationByExposition", [])
|
|
31
|
-
)
|
|
32
|
-
self.first_variation = self.variation_by_exposition[0] if len(self.variation_by_exposition) > 0 else None
|
|
33
28
|
segment = dict_json.get("segment")
|
|
34
29
|
self.targeting_segment: Optional[Segment] = Segment(segment) if segment else None
|
|
35
30
|
self.segment_id: int = self.targeting_segment.id_ if self.targeting_segment else -1
|
|
36
31
|
|
|
37
|
-
def get_variation(self, hash_double: float) -> Optional[VariationByExposition]:
|
|
38
|
-
"""Calculates the variation key for the given hash of visitor"""
|
|
39
|
-
|
|
40
|
-
total = 0.0
|
|
41
|
-
for var_by_exp in self.variation_by_exposition:
|
|
42
|
-
total += var_by_exp.exposition
|
|
43
|
-
if total >= hash_double:
|
|
44
|
-
return var_by_exp
|
|
45
|
-
return None
|
|
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
|
-
|
|
57
32
|
@property
|
|
58
33
|
def is_experimentation(self) -> bool:
|
|
59
34
|
"""Return `true` if rule is `experimentation` type"""
|
{kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.0}/kameleoon/data/manager/visitor.py
RENAMED
|
@@ -347,7 +347,7 @@ class Visitor: # pylint: disable=R0904
|
|
|
347
347
|
fev = cast(ForcedExperimentVariation, context.data)
|
|
348
348
|
if self._data.forced_variations is None:
|
|
349
349
|
self._data.forced_variations = {}
|
|
350
|
-
self._data.forced_variations[fev.rule.
|
|
350
|
+
self._data.forced_variations[fev.rule.experiment.id_] = fev
|
|
351
351
|
|
|
352
352
|
def _set_browser(self, context: DataAddingContext) -> None:
|
|
353
353
|
if context.overwrite or self._data.browser is None:
|
|
@@ -70,7 +70,7 @@ class FeatureNotFound(NotFoundError):
|
|
|
70
70
|
super().__init__(self.message)
|
|
71
71
|
|
|
72
72
|
|
|
73
|
-
class FeatureExperimentNotFound(NotFoundError):
|
|
73
|
+
class FeatureExperimentNotFound(NotFoundError):
|
|
74
74
|
"""Exception indicating that the requested experiment has not been found.
|
|
75
75
|
Check that the experiment's ID matches the provided one."""
|
|
76
76
|
|
{kameleoon-client-python-3.7.0 → kameleoon-client-python-3.9.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,29 @@
|
|
|
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 obtain_hash_for_me_group(visitor_code: str, me_group_name: str) -> float:
|
|
24
|
+
"""Calculate the hash value for a mutually exclusive group for a given visitor code"""
|
|
25
|
+
return Hasher._calculate(visitor_code + me_group_name)
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def _calculate(str_to_hash: str) -> float:
|
|
29
|
+
return int(hashlib.sha256(str_to_hash.encode("UTF-8")).hexdigest(), 16) / math.pow(2, 256)
|