kameleoon-client-python 3.12.0__tar.gz → 3.13.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.12.0/kameleoon_client_python.egg-info → kameleoon-client-python-3.13.0}/PKG-INFO +1 -1
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/data_file.py +19 -9
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/visitor.py +21 -8
- kameleoon-client-python-3.13.0/kameleoon/data/visitor_visits.py +117 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/kameleoon_client.py +19 -15
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/remote_data/remote_data_manager.py +4 -4
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/remote_data/remote_visitor_data.py +25 -15
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/net_provider.py +6 -2
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/net_provider_impl.py +3 -2
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/query_builder.py +17 -15
- kameleoon-client-python-3.13.0/kameleoon/network/services/configuration_service.py +24 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/configuration_service_impl.py +30 -15
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/url_provider.py +3 -7
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/sdk_version.py +1 -1
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/targeting_condition.py +0 -1
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.py +9 -9
- kameleoon-client-python-3.13.0/kameleoon/targeting/conditions/visit_number_today_condition.py +40 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/visit_number_total_condition.py +7 -5
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/visitor_new_return_condition.py +9 -5
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/targeting_manager.py +6 -7
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/tree_condition_factory.py +0 -4
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0/kameleoon_client_python.egg-info}/PKG-INFO +1 -1
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon_client_python.egg-info/SOURCES.txt +0 -1
- kameleoon-client-python-3.12.0/kameleoon/data/visitor_visits.py +0 -32
- kameleoon-client-python-3.12.0/kameleoon/network/services/configuration_service.py +0 -13
- kameleoon-client-python-3.12.0/kameleoon/targeting/conditions/exclusive_feature_flag_condition.py +0 -42
- kameleoon-client-python-3.12.0/kameleoon/targeting/conditions/visit_number_today_condition.py +0 -28
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/MANIFEST.in +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/README.md +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/client_readiness/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/client_readiness/async_readiness.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/client_readiness/threading_readiness.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/custom_data_info.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/experiment.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/feature_flag.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/me_group.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/rule.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/rule_type.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/settings.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/variable.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/variation.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/variation_by_exposition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/browser.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/cbscores.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/conversion.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/cookie.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/custom_data.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/data.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/device.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/geolocation.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/kcs_heat.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/assigned_variation.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/forced_experiment_variation.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/forced_feature_variation.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/forced_variation.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/page_view_visit.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/visitor_manager.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/visitor_slot.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/mapping_identifier.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/operating_system.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/page_view.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/personalization.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/unique_identifier.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/user_agent.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/defaults.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/exceptions.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/domain.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/functions.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/hasher.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/logger.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/multi_threading.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/nonce.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/repeat_timer.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/scheduler.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/string_utils.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/visitor_code.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/hybrid/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/hybrid/hybrid_manager.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/hybrid/hybrid_manager_impl.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/kameleoon_client_config.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/kameleoon_client_factory.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/logging/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/logging/kameleoon_logger.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/logging/log_level.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/logging/logger.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/asyncexec/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/asyncexec/async_executor.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/data/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/data/data_manager.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/evaluation/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/evaluation/evaluated_experiment.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/remote_data/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/tracking/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/tracking/tracking_builder.py +1 -1
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/tracking/tracking_manager.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/tracking/visitor_tracking_registry.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/warehouse/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/warehouse/warehouse_manager.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/middleware.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/access_token_source.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/access_token_source_factory.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/activity_event.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/cookie/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/cookie/cookie_manager.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/network_manager.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/network_manager_factory.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/network_manager_factory_impl.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/network_manager_impl.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/query_encodable.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/sendable.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/service_initialize_context.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/service_initialize_context_impl.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/automation_service.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/automation_service_impl.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/data_service.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/data_service_impl.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/service.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/service_impl.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/uri_helper.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/real_time/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/real_time/real_time_configuration_service.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/real_time/real_time_event.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/storage/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/storage/cache.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/storage/cache_factory.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/storage/cache_factory_impl.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/storage/cache_impl.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/browser_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/constants.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/conversion_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/cookie_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/custom_datum.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/device_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/exclusive_experiment_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/geolocation_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/kcs_heat_range_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/number_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/operating_system_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/page_title_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/page_url_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/page_view_number_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/previous_page_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/sdk_language_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/segment_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/string_value_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/target_experiment_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/target_feature_flag_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/target_personalization_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/unknown_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/models.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/tree_builder.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/types/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/types/remote_visitor_data_filter.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/types/variable.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/types/variation.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon_client_python.egg-info/requires.txt +13 -13
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/setup.cfg +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/setup.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/apps.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/migrations/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/views.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/manage.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/proj/__init__.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/proj/asgi.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/proj/settings.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/proj/urls.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/proj/wsgi.py +0 -0
- {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/resources/config.yml +0 -0
|
@@ -19,12 +19,12 @@ class DataFile:
|
|
|
19
19
|
@staticmethod
|
|
20
20
|
def default(environment: Optional[str]) -> "DataFile":
|
|
21
21
|
"""Creates new instance of `DataFile` initialized with default values"""
|
|
22
|
-
data_file = DataFile(environment, Settings(), {}, CustomDataInfo(None))
|
|
22
|
+
data_file = DataFile(environment, None, Settings(), {}, CustomDataInfo(None))
|
|
23
23
|
return data_file
|
|
24
24
|
|
|
25
25
|
@staticmethod
|
|
26
26
|
def from_json(
|
|
27
|
-
environment: Optional[str], configuration: Dict[str, Any]
|
|
27
|
+
environment: Optional[str], last_modified: Optional[str], configuration: Dict[str, Any]
|
|
28
28
|
) -> "DataFile":
|
|
29
29
|
"""Creates new instance of `DataFile` initialized from the specified configuration JSON"""
|
|
30
30
|
settings = Settings(configuration.get("configuration"))
|
|
@@ -34,23 +34,26 @@ class DataFile:
|
|
|
34
34
|
}
|
|
35
35
|
custom_data_info = CustomDataInfo(configuration.get("customData"))
|
|
36
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)
|
|
37
|
+
data_file = DataFile(environment, last_modified, settings, feature_flags, custom_data_info, holdout)
|
|
38
38
|
return data_file
|
|
39
39
|
|
|
40
40
|
# pylint: disable=R0913
|
|
41
41
|
def __init__(
|
|
42
42
|
self,
|
|
43
43
|
environment: Optional[str],
|
|
44
|
+
last_modified: Optional[str],
|
|
44
45
|
settings: Settings,
|
|
45
46
|
feature_flags: Dict[str, FeatureFlag],
|
|
46
47
|
custom_data_info: CustomDataInfo,
|
|
47
48
|
holdout: Optional[Experiment] = None,
|
|
48
49
|
) -> None:
|
|
49
50
|
KameleoonLogger.debug(
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
"CALL: DataFile(environment: %s, last_modified: %s, settings: %s, feature_flags: %s,"
|
|
52
|
+
" custom_data_info: %s, holdout: %s)",
|
|
53
|
+
environment, last_modified, settings, feature_flags, custom_data_info, holdout
|
|
52
54
|
)
|
|
53
55
|
self.__environment = environment # pylint: disable=W0238
|
|
56
|
+
self.__last_modified = last_modified
|
|
54
57
|
self.__settings = settings
|
|
55
58
|
self.__feature_flags: Dict[str, FeatureFlag] = feature_flags
|
|
56
59
|
self.__me_groups = self.__make_me_groups(feature_flags.values())
|
|
@@ -69,10 +72,16 @@ class DataFile:
|
|
|
69
72
|
self.__custom_data_info = custom_data_info
|
|
70
73
|
self.__holdout = holdout
|
|
71
74
|
KameleoonLogger.debug(
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
"RETURN: DataFile(environment: %s, last_modified: %s, settings: %s, feature_flags: %s,"
|
|
76
|
+
" custom_data_info: %s, holdout: %s)",
|
|
77
|
+
environment, last_modified, settings, feature_flags, custom_data_info, holdout
|
|
74
78
|
)
|
|
75
79
|
|
|
80
|
+
@property
|
|
81
|
+
def last_modified(self) -> Optional[str]:
|
|
82
|
+
"""Returns last modified string"""
|
|
83
|
+
return self.__last_modified
|
|
84
|
+
|
|
76
85
|
@property
|
|
77
86
|
def settings(self) -> Settings:
|
|
78
87
|
"""Returns settings"""
|
|
@@ -177,11 +186,12 @@ class DataFile:
|
|
|
177
186
|
|
|
178
187
|
def __str__(self):
|
|
179
188
|
return (
|
|
180
|
-
|
|
189
|
+
"DataFile{"
|
|
181
190
|
f"environment:'{self.__environment}',"
|
|
191
|
+
f"last_modified:'{self.__last_modified}',"
|
|
182
192
|
f"feature_flags:{len(self.__feature_flags)},"
|
|
183
193
|
f"settings:{self.__settings}"
|
|
184
|
-
|
|
194
|
+
"}"
|
|
185
195
|
)
|
|
186
196
|
|
|
187
197
|
class RuleInfo:
|
{kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/visitor.py
RENAMED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
"""Visitor"""
|
|
2
|
+
import time
|
|
3
|
+
|
|
2
4
|
from threading import Lock
|
|
3
5
|
from typing import Any, Callable, Optional, Dict, List, Iterator, Iterable, cast
|
|
4
6
|
|
|
@@ -44,6 +46,11 @@ class Visitor: # pylint: disable=R0904
|
|
|
44
46
|
"""Creates and returns a clone of the current Visitor instance which shares all the visitor data."""
|
|
45
47
|
return Visitor(self)
|
|
46
48
|
|
|
49
|
+
@property
|
|
50
|
+
def time_started(self) -> int:
|
|
51
|
+
"""Returns the current visit's start time"""
|
|
52
|
+
return self._data.time_started
|
|
53
|
+
|
|
47
54
|
def enumerate_sendable_data(self) -> Iterator[Sendable]:
|
|
48
55
|
"""Enumerates all sendable data associated with this Visitor."""
|
|
49
56
|
KameleoonLogger.debug('CALL: Visitor.enumerate_sendable_data()')
|
|
@@ -263,6 +270,7 @@ class Visitor: # pylint: disable=R0904
|
|
|
263
270
|
class VisitorData:
|
|
264
271
|
"""Visitor Data"""
|
|
265
272
|
def __init__(self) -> None:
|
|
273
|
+
self.time_started = int(time.time() * 1000)
|
|
266
274
|
self.lock = Lock()
|
|
267
275
|
self.user_agent: Optional[str] = None
|
|
268
276
|
self.device: Optional[Device] = None
|
|
@@ -289,18 +297,20 @@ class Visitor: # pylint: disable=R0904
|
|
|
289
297
|
yield self.device
|
|
290
298
|
if self.browser:
|
|
291
299
|
yield self.browser
|
|
292
|
-
if self.geolocation:
|
|
293
|
-
yield self.geolocation
|
|
294
300
|
if self.operating_system:
|
|
295
301
|
yield self.operating_system
|
|
302
|
+
if self.geolocation:
|
|
303
|
+
yield self.geolocation
|
|
304
|
+
if self.visitor_visits:
|
|
305
|
+
yield self.visitor_visits
|
|
296
306
|
if self.custom_data_dict is not None:
|
|
297
307
|
yield from list(self.custom_data_dict.values())
|
|
298
308
|
if self.page_view_visits is not None:
|
|
299
309
|
yield from (visit.page_view for visit in list(self.page_view_visits.values()))
|
|
300
|
-
if self.conversions is not None:
|
|
301
|
-
yield from list(self.conversions)
|
|
302
310
|
if self.variations is not None:
|
|
303
311
|
yield from list(self.variations.values())
|
|
312
|
+
if self.conversions is not None:
|
|
313
|
+
yield from list(self.conversions)
|
|
304
314
|
|
|
305
315
|
def count_sendable_data(self) -> int:
|
|
306
316
|
"""Counts the total number of sendable data items associated with the visitor."""
|
|
@@ -309,18 +319,20 @@ class Visitor: # pylint: disable=R0904
|
|
|
309
319
|
count += 1
|
|
310
320
|
if self.browser is not None:
|
|
311
321
|
count += 1
|
|
322
|
+
if self.operating_system is not None:
|
|
323
|
+
count += 1
|
|
312
324
|
if self.geolocation is not None:
|
|
313
325
|
count += 1
|
|
314
|
-
if self.
|
|
326
|
+
if self.visitor_visits:
|
|
315
327
|
count += 1
|
|
316
328
|
if self.custom_data_dict is not None:
|
|
317
329
|
count += len(self.custom_data_dict)
|
|
318
330
|
if self.page_view_visits is not None:
|
|
319
331
|
count += len(self.page_view_visits)
|
|
320
|
-
if self.conversions is not None:
|
|
321
|
-
count += len(self.conversions)
|
|
322
332
|
if self.variations is not None:
|
|
323
333
|
count += len(self.variations)
|
|
334
|
+
if self.conversions is not None:
|
|
335
|
+
count += len(self.conversions)
|
|
324
336
|
return count
|
|
325
337
|
|
|
326
338
|
class DataAddingContext:
|
|
@@ -433,7 +445,8 @@ class Visitor: # pylint: disable=R0904
|
|
|
433
445
|
self._data.cbscores = cast(CBScores, context.data)
|
|
434
446
|
|
|
435
447
|
def _set_visitor_visits(self, context: DataAddingContext) -> None:
|
|
436
|
-
self._data.visitor_visits
|
|
448
|
+
if context.overwrite or (self._data.visitor_visits is None):
|
|
449
|
+
self._data.visitor_visits = cast(VisitorVisits, context.data).localize(self._data.time_started)
|
|
437
450
|
|
|
438
451
|
def _set_is_unique_identifier(self, context: DataAddingContext) -> None:
|
|
439
452
|
self._is_unique_identifier = cast(UniqueIdentifier, context.data).value
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Visitor visits"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, List, Optional, Tuple
|
|
4
|
+
|
|
5
|
+
from kameleoon.data import DataType
|
|
6
|
+
from kameleoon.network.sendable import DuplicationUnsafeSendableBase
|
|
7
|
+
from kameleoon.network.query_builder import QueryBuilder, QueryParam, QueryParams
|
|
8
|
+
|
|
9
|
+
from kameleoon.data.data import BaseData
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class VisitorVisits(BaseData, DuplicationUnsafeSendableBase):
|
|
13
|
+
"""Visitor visits"""
|
|
14
|
+
|
|
15
|
+
EVENT_TYPE = "staticData"
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self, prev_visits: List["Visit"], visit_number=0, *, time_started=0, time_since_previous_visit=0
|
|
19
|
+
) -> None:
|
|
20
|
+
super().__init__()
|
|
21
|
+
self.__visit_number = max(visit_number, len(prev_visits))
|
|
22
|
+
self.__prev_visits = prev_visits
|
|
23
|
+
self.__time_started = time_started
|
|
24
|
+
self.__time_since_previous_visit = time_since_previous_visit
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def data_type(self) -> DataType:
|
|
28
|
+
return DataType.VISITOR_VISITS
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def visit_number(self) -> int:
|
|
32
|
+
"""Returns the visit number"""
|
|
33
|
+
return self.__visit_number
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def prev_visits(self) -> List["Visit"]:
|
|
37
|
+
"""Returns the previous visit list"""
|
|
38
|
+
return self.__prev_visits
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def time_started(self) -> int:
|
|
42
|
+
"""Returns the current visit's start time"""
|
|
43
|
+
return self.__time_started
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def time_since_previous_visit(self) -> int:
|
|
47
|
+
"""Returns the time since the previous visit"""
|
|
48
|
+
return self.__time_since_previous_visit
|
|
49
|
+
|
|
50
|
+
def localize(self, time_started: int) -> "VisitorVisits":
|
|
51
|
+
"""
|
|
52
|
+
Localizes a remote instance of `VisitorVisits` creating a new instance
|
|
53
|
+
with a specific current visit's start time.
|
|
54
|
+
"""
|
|
55
|
+
time_since_previous_visit = 0
|
|
56
|
+
for visit in self.__prev_visits:
|
|
57
|
+
time_delta = time_started - visit.time_last_activity
|
|
58
|
+
if time_delta >= 0:
|
|
59
|
+
time_since_previous_visit = time_delta
|
|
60
|
+
break
|
|
61
|
+
return VisitorVisits(
|
|
62
|
+
self.__prev_visits, self.__visit_number,
|
|
63
|
+
time_started=time_started, time_since_previous_visit=time_since_previous_visit,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
def _add_query_params(self, query_builder: QueryBuilder) -> None:
|
|
67
|
+
query_builder.extend(
|
|
68
|
+
QueryParam(QueryParams.EVENT_TYPE, self.EVENT_TYPE),
|
|
69
|
+
QueryParam(QueryParams.VISIT_NUMBER, str(self.__visit_number)),
|
|
70
|
+
QueryParam(QueryParams.TIME_SINCE_PREVIOUS_VISIT, str(self.__time_since_previous_visit)),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def __eq__(self, value: Any) -> bool:
|
|
74
|
+
return isinstance(value, VisitorVisits) and (self.__visit_number == value.visit_number) and \
|
|
75
|
+
(self.__prev_visits == value.prev_visits) and (self.__time_started == value.time_started) and \
|
|
76
|
+
(self.__time_since_previous_visit == value.time_since_previous_visit)
|
|
77
|
+
|
|
78
|
+
def __str__(self) -> str:
|
|
79
|
+
return (
|
|
80
|
+
"VisitorVisits{"
|
|
81
|
+
f"visit_number:{self.__visit_number},"
|
|
82
|
+
f"prev_visits:{[str(v) for v in self.__prev_visits]},"
|
|
83
|
+
f"time_started:{self.__time_started},"
|
|
84
|
+
f"time_since_previous_visit:{self.__time_since_previous_visit}"
|
|
85
|
+
"}"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def get_visitor_visits(obj: Any) -> Tuple["VisitorVisits", bool]:
|
|
90
|
+
"""Determines if an object is `VisitorVisits` or `None` and returns a valid instance of `VisitorVisits`."""
|
|
91
|
+
if isinstance(obj, VisitorVisits):
|
|
92
|
+
return obj, True
|
|
93
|
+
return VisitorVisits([]), obj is None
|
|
94
|
+
|
|
95
|
+
class Visit:
|
|
96
|
+
"""Visit"""
|
|
97
|
+
|
|
98
|
+
def __init__(self, time_started: int, time_last_activity: Optional[int] = None) -> None:
|
|
99
|
+
self.__time_started = time_started
|
|
100
|
+
self.__time_last_activity = time_last_activity or time_started
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def time_started(self) -> int:
|
|
104
|
+
"""Returns the start time"""
|
|
105
|
+
return self.__time_started
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def time_last_activity(self) -> int:
|
|
109
|
+
"""Returns the last activity time"""
|
|
110
|
+
return self.__time_last_activity
|
|
111
|
+
|
|
112
|
+
def __eq__(self, value: Any) -> bool:
|
|
113
|
+
return isinstance(value, VisitorVisits.Visit) and (self.__time_started == value.time_started) and \
|
|
114
|
+
(self.__time_last_activity == value.time_last_activity)
|
|
115
|
+
|
|
116
|
+
def __str__(self) -> str:
|
|
117
|
+
return f"Visit{{time_started:{self.__time_started},time_last_activity:{self.__time_last_activity}}}"
|
{kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/kameleoon_client.py
RENAMED
|
@@ -47,7 +47,7 @@ from kameleoon.network.net_provider_impl import NetProviderImpl
|
|
|
47
47
|
from kameleoon.network.network_manager_factory import NetworkManagerFactory
|
|
48
48
|
from kameleoon.network.network_manager_factory_impl import NetworkManagerFactoryImpl
|
|
49
49
|
from kameleoon.network.sendable import Sendable
|
|
50
|
-
from kameleoon.network.services.configuration_service import ConfigurationService
|
|
50
|
+
from kameleoon.network.services.configuration_service import ConfigurationService, FetchedConfiguration
|
|
51
51
|
from kameleoon.network.cookie.cookie_manager import CookieManager
|
|
52
52
|
|
|
53
53
|
from kameleoon.real_time.real_time_configuration_service import RealTimeConfigurationService
|
|
@@ -1435,13 +1435,18 @@ class KameleoonClient:
|
|
|
1435
1435
|
KameleoonLogger.debug("CALL: KameleoonClient._fetch_configuration(time_stamp: %s)", time_stamp)
|
|
1436
1436
|
success = False
|
|
1437
1437
|
try:
|
|
1438
|
-
|
|
1439
|
-
if
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1438
|
+
fetched_configuration = await self._obtain_configuration(time_stamp)
|
|
1439
|
+
if fetched_configuration:
|
|
1440
|
+
if fetched_configuration.configuration:
|
|
1441
|
+
data_file = DataFile.from_json(
|
|
1442
|
+
self._config.environment,
|
|
1443
|
+
fetched_configuration.last_modified,
|
|
1444
|
+
fetched_configuration.configuration
|
|
1445
|
+
)
|
|
1446
|
+
self._data_manager.data_file = data_file
|
|
1447
|
+
self._network_manager.url_provider.apply_data_api_domain(data_file.settings.data_api_domain)
|
|
1448
|
+
self._call_update_handler_if_needed(time_stamp is not None)
|
|
1449
|
+
success = True
|
|
1445
1450
|
except Exception as ex:
|
|
1446
1451
|
KameleoonLogger.error("Error occurred during configuration fetching: %s", ex)
|
|
1447
1452
|
self._manage_configuration_update(self._data_manager.data_file.settings.real_time_update)
|
|
@@ -1532,7 +1537,7 @@ class KameleoonClient:
|
|
|
1532
1537
|
if not self._data_manager.data_file.settings.real_time_update:
|
|
1533
1538
|
await self._fetch_configuration()
|
|
1534
1539
|
|
|
1535
|
-
async def _obtain_configuration(self, time_stamp: Optional[int]) -> Optional[
|
|
1540
|
+
async def _obtain_configuration(self, time_stamp: Optional[int]) -> Optional[FetchedConfiguration]:
|
|
1536
1541
|
"""
|
|
1537
1542
|
Obtaining configuration from CDN service.
|
|
1538
1543
|
Should be run in a separate thead.
|
|
@@ -1541,15 +1546,14 @@ class KameleoonClient:
|
|
|
1541
1546
|
:return: None
|
|
1542
1547
|
"""
|
|
1543
1548
|
KameleoonLogger.debug("CALL: KameleoonClient._obtain_configuration(time_stamp: %s)", time_stamp)
|
|
1549
|
+
last_modified = self._data_manager.data_file.last_modified
|
|
1544
1550
|
service: ConfigurationService = self._network_manager.get_service(ConfigurationService)
|
|
1545
|
-
|
|
1546
|
-
content = None
|
|
1547
|
-
if response.code and (response.code // 100 == 2):
|
|
1548
|
-
content = response.content
|
|
1551
|
+
fetched_configuration = await service.fetch_configuration(self._config.environment, time_stamp, last_modified)
|
|
1549
1552
|
KameleoonLogger.debug(
|
|
1550
|
-
"RETURN: KameleoonClient._obtain_configuration(time_stamp: %s) -> (
|
|
1553
|
+
"RETURN: KameleoonClient._obtain_configuration(time_stamp: %s) -> (fetched_configuration: %s)",
|
|
1554
|
+
time_stamp, fetched_configuration
|
|
1551
1555
|
)
|
|
1552
|
-
return
|
|
1556
|
+
return fetched_configuration
|
|
1553
1557
|
|
|
1554
1558
|
def __get_feature_variation_key(self, visitor_code: str, feature_key: str) -> Tuple[FeatureFlag, str]:
|
|
1555
1559
|
"""
|
|
@@ -63,7 +63,7 @@ class RemoteDataManager:
|
|
|
63
63
|
if response.content is None:
|
|
64
64
|
return []
|
|
65
65
|
custom_data_info = self._data_manager.data_file.custom_data_info
|
|
66
|
-
remote_visitor_data = RemoteDataManager.__parse_remote_visitor_data(response.content)
|
|
66
|
+
remote_visitor_data = RemoteDataManager.__parse_remote_visitor_data(response.content, data_filter)
|
|
67
67
|
remote_visitor_data.mark_data_as_sent(custom_data_info)
|
|
68
68
|
data_to_add = remote_visitor_data.collect_data_to_add()
|
|
69
69
|
if add_data and data_to_add:
|
|
@@ -77,9 +77,9 @@ class RemoteDataManager:
|
|
|
77
77
|
return remote_visitor_data.collect_data_to_return()
|
|
78
78
|
|
|
79
79
|
@staticmethod
|
|
80
|
-
def __parse_remote_visitor_data(raw: Any) -> RemoteVisitorData:
|
|
80
|
+
def __parse_remote_visitor_data(raw: Any, data_filter: RemoteVisitorDataFilter) -> RemoteVisitorData:
|
|
81
81
|
try:
|
|
82
|
-
return RemoteVisitorData(raw)
|
|
82
|
+
return RemoteVisitorData(raw, data_filter)
|
|
83
83
|
except Exception as ex: # pylint: disable=W0703
|
|
84
84
|
KameleoonLogger.error("Parsing of remote visitor data failed: %s", ex)
|
|
85
|
-
return RemoteVisitorData({})
|
|
85
|
+
return RemoteVisitorData({}, data_filter)
|
|
@@ -28,12 +28,14 @@ from kameleoon.data import (
|
|
|
28
28
|
OperatingSystemType,
|
|
29
29
|
Data,
|
|
30
30
|
)
|
|
31
|
+
from kameleoon.types.remote_visitor_data_filter import RemoteVisitorDataFilter
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
class RemoteVisitorData:
|
|
34
35
|
"""Remote visitor data"""
|
|
35
36
|
|
|
36
|
-
def __init__(self, json: Dict[str, Any]) -> None:
|
|
37
|
+
def __init__(self, json: Dict[str, Any], data_filter: RemoteVisitorDataFilter) -> None:
|
|
38
|
+
self.__filter = data_filter
|
|
37
39
|
self.__geolocation: Optional[Geolocation] = None
|
|
38
40
|
self.__device: Optional[Device] = None
|
|
39
41
|
self.__browser: Optional[Browser] = None
|
|
@@ -43,18 +45,22 @@ class RemoteVisitorData:
|
|
|
43
45
|
self.__experiments: Optional[Dict[int, AssignedVariation]] = None
|
|
44
46
|
self.__personalizations: Optional[Dict[int, Personalization]] = None
|
|
45
47
|
self.__conversions: Optional[List[Conversion]] = None
|
|
46
|
-
self.
|
|
48
|
+
self.__visit_number = 0
|
|
49
|
+
self.__visitor_visits: Optional[VisitorVisits] = None
|
|
47
50
|
self.__visitor_code: Optional[str] = None
|
|
48
51
|
current_visit = json.get("currentVisit")
|
|
49
52
|
if current_visit is not None:
|
|
50
|
-
self.__parse_visit(current_visit)
|
|
53
|
+
self.__parse_visit(current_visit, False)
|
|
51
54
|
previous_visits = json.get("previousVisits")
|
|
52
55
|
if previous_visits:
|
|
53
|
-
|
|
56
|
+
prev_visits = []
|
|
54
57
|
for visit in previous_visits:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
time_started = visit.get("timeStarted", 0)
|
|
59
|
+
time_last_event = visit.get("timeLastEvent", time_started)
|
|
60
|
+
prev_visits.append(VisitorVisits.Visit(time_started, time_last_event))
|
|
61
|
+
self.__parse_visit(visit, True)
|
|
62
|
+
if len(prev_visits) > 0:
|
|
63
|
+
self.__visitor_visits = VisitorVisits(prev_visits, self.__visit_number)
|
|
58
64
|
self.__kcs_heat = self.__parse_kcs_heat(json.get("kcs"))
|
|
59
65
|
self.__cbs = self.__parse_cbscores(json.get("cbs"))
|
|
60
66
|
|
|
@@ -63,8 +69,8 @@ class RemoteVisitorData:
|
|
|
63
69
|
data_to_add: List[BaseData] = []
|
|
64
70
|
if self.__custom_data_dict:
|
|
65
71
|
data_to_add += self.__custom_data_dict.values()
|
|
66
|
-
if self.
|
|
67
|
-
data_to_add.append(self.
|
|
72
|
+
if self.__visitor_visits:
|
|
73
|
+
data_to_add.append(self.__visitor_visits)
|
|
68
74
|
if self.__kcs_heat:
|
|
69
75
|
data_to_add.append(self.__kcs_heat)
|
|
70
76
|
if self.__cbs:
|
|
@@ -117,7 +123,7 @@ class RemoteVisitorData:
|
|
|
117
123
|
"""Returns the `visitorCode` from the most recent visit"""
|
|
118
124
|
return self.__visitor_code
|
|
119
125
|
|
|
120
|
-
def __parse_visit(self, json_visit: Dict[str, Any]) -> None:
|
|
126
|
+
def __parse_visit(self, json_visit: Dict[str, Any], is_prev_visit: bool) -> None:
|
|
121
127
|
if (self.__visitor_code is None) and isinstance(visitor_code := json_visit.get("visitorCode"), str):
|
|
122
128
|
self.__visitor_code = visitor_code
|
|
123
129
|
custom_data_events = json_visit.get("customDataEvents")
|
|
@@ -137,7 +143,7 @@ class RemoteVisitorData:
|
|
|
137
143
|
self.__parse_geolocation(geolocation_events[-1])
|
|
138
144
|
static_data_event = json_visit.get("staticDataEvent")
|
|
139
145
|
if static_data_event:
|
|
140
|
-
self.__parse_static_data(static_data_event)
|
|
146
|
+
self.__parse_static_data(static_data_event, is_prev_visit)
|
|
141
147
|
personalization_events = json_visit.get("personalizationEvents")
|
|
142
148
|
if personalization_events:
|
|
143
149
|
self.__parse_personalizations(personalization_events)
|
|
@@ -203,20 +209,24 @@ class RemoteVisitorData:
|
|
|
203
209
|
if country is not None:
|
|
204
210
|
self.__geolocation = Geolocation(country, data.get("region"), data.get("city"))
|
|
205
211
|
|
|
206
|
-
def __parse_static_data(self, static_data_event: Dict[str, Any]) -> None:
|
|
212
|
+
def __parse_static_data(self, static_data_event: Dict[str, Any], is_prev_visit: bool) -> None:
|
|
207
213
|
if self.__device and self.__browser and self.__operating_system:
|
|
208
214
|
return
|
|
209
215
|
data = static_data_event.get("data")
|
|
210
216
|
if data is not None:
|
|
211
|
-
if self.
|
|
217
|
+
if self.__visit_number == 0:
|
|
218
|
+
self.__visit_number = data.get("visitNumber", 0)
|
|
219
|
+
if is_prev_visit and (self.__visit_number > 0):
|
|
220
|
+
self.__visit_number += 1
|
|
221
|
+
if self.__filter.device and (self.__device is None):
|
|
212
222
|
device_type = enum_from_name_literal(data.get("deviceType"), DeviceType, None)
|
|
213
223
|
if device_type is not None:
|
|
214
224
|
self.__device = Device(device_type)
|
|
215
|
-
if self.__browser is None:
|
|
225
|
+
if self.__filter.browser and (self.__browser is None):
|
|
216
226
|
browser_type = enum_from_name_literal(data.get("browser"), BrowserType, None)
|
|
217
227
|
if browser_type is not None:
|
|
218
228
|
self.__browser = Browser(browser_type, data.get("browserVersion"))
|
|
219
|
-
if self.__operating_system is None:
|
|
229
|
+
if self.__filter.operating_system and (self.__operating_system is None):
|
|
220
230
|
operating_system_type = enum_from_name_literal(data.get("os"), OperatingSystemType, None)
|
|
221
231
|
if operating_system_type is not None:
|
|
222
232
|
self.__operating_system = OperatingSystem(operating_system_type)
|
{kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/net_provider.py
RENAMED
|
@@ -18,10 +18,14 @@ class HttpMethod(Enum):
|
|
|
18
18
|
|
|
19
19
|
class Response:
|
|
20
20
|
"""Response"""
|
|
21
|
-
def __init__(
|
|
21
|
+
def __init__(
|
|
22
|
+
self, error: Optional[Exception], code: Optional[int], content: Optional[Any],
|
|
23
|
+
headers: Optional[Dict[str, str]] = None
|
|
24
|
+
) -> None:
|
|
22
25
|
self.error = error
|
|
23
26
|
self.code = code
|
|
24
27
|
self.content = content
|
|
28
|
+
self.headers = headers or {}
|
|
25
29
|
|
|
26
30
|
@property
|
|
27
31
|
def success(self) -> bool:
|
|
@@ -31,7 +35,7 @@ class Response:
|
|
|
31
35
|
@property
|
|
32
36
|
def is_expected_status_code(self) -> bool:
|
|
33
37
|
"""Checks if the status code is one of the expected codes."""
|
|
34
|
-
return (self.code is not None) and ((self.code // 100 == 2) or (self.code == 403))
|
|
38
|
+
return (self.code is not None) and ((self.code // 100 == 2) or (self.code == 403) or (self.code == 304))
|
|
35
39
|
|
|
36
40
|
def __str__(self):
|
|
37
41
|
return f"HttpResponse{{Code:{self.code},Error:{self.error},Body:'{self.content}'}}"
|
|
@@ -66,7 +66,7 @@ class NetProviderImpl(NetProvider):
|
|
|
66
66
|
return headers
|
|
67
67
|
|
|
68
68
|
@staticmethod
|
|
69
|
-
async def __form_response(resp, response_content_type: ResponseContentType) -> Response:
|
|
69
|
+
async def __form_response(resp: aiohttp.ClientResponse, response_content_type: ResponseContentType) -> Response:
|
|
70
70
|
try:
|
|
71
71
|
if response_content_type == ResponseContentType.TEXT:
|
|
72
72
|
content = await resp.text()
|
|
@@ -76,4 +76,5 @@ class NetProviderImpl(NetProvider):
|
|
|
76
76
|
content = None
|
|
77
77
|
except aiohttp.ContentTypeError:
|
|
78
78
|
content = None
|
|
79
|
-
|
|
79
|
+
headers = dict(resp.headers)
|
|
80
|
+
return Response(None, resp.status, content, headers)
|
{kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/query_builder.py
RENAMED
|
@@ -10,53 +10,55 @@ class QueryParams(str, Enum):
|
|
|
10
10
|
BROWSER_INDEX = "browserIndex"
|
|
11
11
|
BROWSER_VERSION = "browserVersion"
|
|
12
12
|
CBS = "cbs"
|
|
13
|
+
CITY = "city"
|
|
13
14
|
CLIENT_ID = "client_id"
|
|
14
15
|
CLIENT_SECRET = "client_secret"
|
|
16
|
+
CONVERSION = "conversion"
|
|
17
|
+
COUNTRY = "country"
|
|
15
18
|
CURRENT_VISIT = "currentVisit"
|
|
16
19
|
CUSTOM_DATA = "customData"
|
|
17
20
|
DEVICE_TYPE = "deviceType"
|
|
18
21
|
ENVIRONMENT = "environment"
|
|
19
22
|
EVENT_TYPE = "eventType"
|
|
23
|
+
EXPERIMENT = "experiment"
|
|
20
24
|
EXPERIMENT_ID = "id"
|
|
25
|
+
GEOLOCATION = "geolocation"
|
|
21
26
|
GOAL_ID = "goalId"
|
|
22
27
|
GRANT_TYPE = "grant_type"
|
|
23
28
|
HREF = "href"
|
|
24
29
|
INDEX = "index"
|
|
25
30
|
KCS = "kcs"
|
|
26
31
|
KEY = "key"
|
|
32
|
+
LATITUDE = "latitude"
|
|
33
|
+
LONGITUDE = "longitude"
|
|
34
|
+
MAPPING_IDENTIFIER = "mappingIdentifier"
|
|
35
|
+
MAPPING_VALUE = "mappingValue"
|
|
27
36
|
MAX_NUMBER_PREVIOUS_VISITS = "maxNumberPreviousVisits"
|
|
28
37
|
METADATA = "metadata"
|
|
29
38
|
NEGATIVE = "negative"
|
|
30
39
|
NONCE = "nonce"
|
|
40
|
+
OPERATING_SYSTEM = "os"
|
|
41
|
+
OPERATING_SYSTEM_INDEX = "osIndex"
|
|
31
42
|
OVERWRITE = "overwrite"
|
|
43
|
+
PAGE = "page"
|
|
32
44
|
PERSONALIZATION = "personalization"
|
|
45
|
+
POSTAL_CODE = "postalCode"
|
|
33
46
|
REFERRERS_INDICES = "referrersIndices"
|
|
47
|
+
REGION = "region"
|
|
34
48
|
REVENUE = "revenue"
|
|
35
49
|
SDK_NAME = "sdkName"
|
|
36
50
|
SDK_VERSION = "sdkVersion"
|
|
37
51
|
SITE_CODE = "siteCode"
|
|
52
|
+
STATIC_DATA = "staticData"
|
|
53
|
+
TIME_SINCE_PREVIOUS_VISIT = "timeSincePreviousVisit"
|
|
38
54
|
TITLE = "title"
|
|
39
55
|
TS = "ts"
|
|
40
56
|
USER_AGENT = "userAgent"
|
|
41
57
|
VALUES_COUNT_MAP = "valuesCountMap"
|
|
42
58
|
VARIATION_ID = "variationId"
|
|
43
59
|
VERSION = "version"
|
|
60
|
+
VISIT_NUMBER = "visitNumber"
|
|
44
61
|
VISITOR_CODE = "visitorCode"
|
|
45
|
-
COUNTRY = "country"
|
|
46
|
-
REGION = "region"
|
|
47
|
-
CITY = "city"
|
|
48
|
-
POSTAL_CODE = "postalCode"
|
|
49
|
-
LATITUDE = "latitude"
|
|
50
|
-
LONGITUDE = "longitude"
|
|
51
|
-
OPERATING_SYSTEM = "os"
|
|
52
|
-
GEOLOCATION = "geolocation"
|
|
53
|
-
OPERATING_SYSTEM_INDEX = "osIndex"
|
|
54
|
-
MAPPING_IDENTIFIER = "mappingIdentifier"
|
|
55
|
-
MAPPING_VALUE = "mappingValue"
|
|
56
|
-
CONVERSION = "conversion"
|
|
57
|
-
EXPERIMENT = "experiment"
|
|
58
|
-
PAGE = "page"
|
|
59
|
-
STATIC_DATA = "staticData"
|
|
60
62
|
|
|
61
63
|
def __str__(self) -> str:
|
|
62
64
|
return self.value
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Services"""
|
|
2
|
+
from typing import Any, Dict, Optional
|
|
3
|
+
from kameleoon.network.services.service import Service
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FetchedConfiguration:
|
|
7
|
+
"""Represents fetched configuration in json format and its last modification date"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, configuration: Optional[Dict[str, Any]], last_modified: Optional[str]) -> None:
|
|
10
|
+
self.configuration = configuration
|
|
11
|
+
self.last_modified = last_modified
|
|
12
|
+
|
|
13
|
+
def __str__(self) -> str:
|
|
14
|
+
return f"FetchedConfiguration{{configuration:{self.configuration},last_modified:'{self.last_modified}'}}"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ConfigurationService(Service):
|
|
18
|
+
"""Abstract configuration service"""
|
|
19
|
+
async def fetch_configuration(
|
|
20
|
+
self, environment: Optional[str] = None, time_stamp: Optional[int] = None,
|
|
21
|
+
if_modified_since: Optional[str] = None, timeout: Optional[float] = None
|
|
22
|
+
) -> Optional[FetchedConfiguration]:
|
|
23
|
+
"""Asynchronously fetches configuration data from a remote service."""
|
|
24
|
+
raise NotImplementedError()
|