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.
Files changed (186) hide show
  1. {kameleoon-client-python-3.12.0/kameleoon_client_python.egg-info → kameleoon-client-python-3.13.0}/PKG-INFO +1 -1
  2. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/data_file.py +19 -9
  3. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/visitor.py +21 -8
  4. kameleoon-client-python-3.13.0/kameleoon/data/visitor_visits.py +117 -0
  5. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/kameleoon_client.py +19 -15
  6. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/remote_data/remote_data_manager.py +4 -4
  7. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/remote_data/remote_visitor_data.py +25 -15
  8. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/net_provider.py +6 -2
  9. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/net_provider_impl.py +3 -2
  10. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/query_builder.py +17 -15
  11. kameleoon-client-python-3.13.0/kameleoon/network/services/configuration_service.py +24 -0
  12. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/configuration_service_impl.py +30 -15
  13. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/url_provider.py +3 -7
  14. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/sdk_version.py +1 -1
  15. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/targeting_condition.py +0 -1
  16. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.py +9 -9
  17. kameleoon-client-python-3.13.0/kameleoon/targeting/conditions/visit_number_today_condition.py +40 -0
  18. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/visit_number_total_condition.py +7 -5
  19. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/visitor_new_return_condition.py +9 -5
  20. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/targeting_manager.py +6 -7
  21. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/tree_condition_factory.py +0 -4
  22. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0/kameleoon_client_python.egg-info}/PKG-INFO +1 -1
  23. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon_client_python.egg-info/SOURCES.txt +0 -1
  24. kameleoon-client-python-3.12.0/kameleoon/data/visitor_visits.py +0 -32
  25. kameleoon-client-python-3.12.0/kameleoon/network/services/configuration_service.py +0 -13
  26. kameleoon-client-python-3.12.0/kameleoon/targeting/conditions/exclusive_feature_flag_condition.py +0 -42
  27. kameleoon-client-python-3.12.0/kameleoon/targeting/conditions/visit_number_today_condition.py +0 -28
  28. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/MANIFEST.in +0 -0
  29. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/README.md +0 -0
  30. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/__init__.py +0 -0
  31. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/client_readiness/__init__.py +0 -0
  32. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/client_readiness/async_readiness.py +0 -0
  33. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/client_readiness/threading_readiness.py +0 -0
  34. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/__init__.py +0 -0
  35. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/custom_data_info.py +0 -0
  36. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/experiment.py +0 -0
  37. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/feature_flag.py +0 -0
  38. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/me_group.py +0 -0
  39. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/rule.py +0 -0
  40. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/rule_type.py +0 -0
  41. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/settings.py +0 -0
  42. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/variable.py +0 -0
  43. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/variation.py +0 -0
  44. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/configuration/variation_by_exposition.py +0 -0
  45. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/__init__.py +0 -0
  46. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/browser.py +0 -0
  47. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/cbscores.py +0 -0
  48. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/conversion.py +0 -0
  49. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/cookie.py +0 -0
  50. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/custom_data.py +0 -0
  51. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/data.py +0 -0
  52. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/device.py +0 -0
  53. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/geolocation.py +0 -0
  54. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/kcs_heat.py +0 -0
  55. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/__init__.py +0 -0
  56. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/assigned_variation.py +0 -0
  57. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/forced_experiment_variation.py +0 -0
  58. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/forced_feature_variation.py +0 -0
  59. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/forced_variation.py +0 -0
  60. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/page_view_visit.py +0 -0
  61. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/visitor_manager.py +0 -0
  62. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/manager/visitor_slot.py +0 -0
  63. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/mapping_identifier.py +0 -0
  64. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/operating_system.py +0 -0
  65. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/page_view.py +0 -0
  66. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/personalization.py +0 -0
  67. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/unique_identifier.py +0 -0
  68. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/data/user_agent.py +0 -0
  69. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/defaults.py +0 -0
  70. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/exceptions.py +0 -0
  71. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/__init__.py +0 -0
  72. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/domain.py +0 -0
  73. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/functions.py +0 -0
  74. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/hasher.py +0 -0
  75. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/logger.py +0 -0
  76. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/multi_threading.py +0 -0
  77. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/nonce.py +0 -0
  78. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/repeat_timer.py +0 -0
  79. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/scheduler.py +0 -0
  80. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/string_utils.py +0 -0
  81. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/helpers/visitor_code.py +0 -0
  82. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/hybrid/__init__.py +0 -0
  83. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/hybrid/hybrid_manager.py +0 -0
  84. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/hybrid/hybrid_manager_impl.py +0 -0
  85. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/kameleoon_client_config.py +0 -0
  86. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/kameleoon_client_factory.py +0 -0
  87. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/logging/__init__.py +0 -0
  88. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/logging/kameleoon_logger.py +0 -0
  89. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/logging/log_level.py +0 -0
  90. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/logging/logger.py +0 -0
  91. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/__init__.py +0 -0
  92. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/asyncexec/__init__.py +0 -0
  93. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/asyncexec/async_executor.py +0 -0
  94. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/data/__init__.py +0 -0
  95. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/data/data_manager.py +0 -0
  96. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/evaluation/__init__.py +0 -0
  97. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/evaluation/evaluated_experiment.py +0 -0
  98. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/remote_data/__init__.py +0 -0
  99. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/tracking/__init__.py +0 -0
  100. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/tracking/tracking_builder.py +1 -1
  101. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/tracking/tracking_manager.py +0 -0
  102. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/tracking/visitor_tracking_registry.py +0 -0
  103. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/warehouse/__init__.py +0 -0
  104. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/managers/warehouse/warehouse_manager.py +0 -0
  105. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/middleware.py +0 -0
  106. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/__init__.py +0 -0
  107. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/access_token_source.py +0 -0
  108. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/access_token_source_factory.py +0 -0
  109. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/activity_event.py +0 -0
  110. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/cookie/__init__.py +0 -0
  111. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/cookie/cookie_manager.py +0 -0
  112. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/network_manager.py +0 -0
  113. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/network_manager_factory.py +0 -0
  114. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/network_manager_factory_impl.py +0 -0
  115. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/network_manager_impl.py +0 -0
  116. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/query_encodable.py +0 -0
  117. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/sendable.py +0 -0
  118. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/service_initialize_context.py +0 -0
  119. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/service_initialize_context_impl.py +0 -0
  120. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/__init__.py +0 -0
  121. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/automation_service.py +0 -0
  122. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/automation_service_impl.py +0 -0
  123. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/data_service.py +0 -0
  124. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/data_service_impl.py +0 -0
  125. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/service.py +0 -0
  126. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/services/service_impl.py +0 -0
  127. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/network/uri_helper.py +0 -0
  128. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/real_time/__init__.py +0 -0
  129. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/real_time/real_time_configuration_service.py +0 -0
  130. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/real_time/real_time_event.py +0 -0
  131. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/storage/__init__.py +0 -0
  132. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/storage/cache.py +0 -0
  133. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/storage/cache_factory.py +0 -0
  134. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/storage/cache_factory_impl.py +0 -0
  135. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/storage/cache_impl.py +0 -0
  136. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/__init__.py +0 -0
  137. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/__init__.py +0 -0
  138. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/browser_condition.py +0 -0
  139. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/constants.py +0 -0
  140. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/conversion_condition.py +0 -0
  141. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/cookie_condition.py +0 -0
  142. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/custom_datum.py +0 -0
  143. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/device_condition.py +0 -0
  144. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/exclusive_experiment_condition.py +0 -0
  145. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/geolocation_condition.py +0 -0
  146. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/kcs_heat_range_condition.py +0 -0
  147. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/number_condition.py +0 -0
  148. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/operating_system_condition.py +0 -0
  149. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/page_title_condition.py +0 -0
  150. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/page_url_condition.py +0 -0
  151. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/page_view_number_condition.py +0 -0
  152. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/previous_page_condition.py +0 -0
  153. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/sdk_language_condition.py +0 -0
  154. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/segment_condition.py +0 -0
  155. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/string_value_condition.py +0 -0
  156. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/target_experiment_condition.py +0 -0
  157. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/target_feature_flag_condition.py +0 -0
  158. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/target_personalization_condition.py +0 -0
  159. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/unknown_condition.py +0 -0
  160. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
  161. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/models.py +0 -0
  162. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/targeting/tree_builder.py +0 -0
  163. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/types/__init__.py +0 -0
  164. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/types/remote_visitor_data_filter.py +0 -0
  165. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/types/variable.py +0 -0
  166. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon/types/variation.py +0 -0
  167. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
  168. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon_client_python.egg-info/requires.txt +13 -13
  169. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
  170. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/setup.cfg +0 -0
  171. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/setup.py +0 -0
  172. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/__init__.py +0 -0
  173. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/__init__.py +0 -0
  174. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
  175. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/apps.py +0 -0
  176. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/migrations/__init__.py +0 -0
  177. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
  178. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
  179. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/kameleoon_app/views.py +0 -0
  180. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/manage.py +0 -0
  181. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/proj/__init__.py +0 -0
  182. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/proj/asgi.py +0 -0
  183. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/proj/settings.py +0 -0
  184. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/proj/urls.py +0 -0
  185. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/integration/proj/proj/wsgi.py +0 -0
  186. {kameleoon-client-python-3.12.0 → kameleoon-client-python-3.13.0}/tests/resources/config.yml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kameleoon-client-python
3
- Version: 3.12.0
3
+ Version: 3.13.0
4
4
  Summary: Kameleoon Client Python Software Development Kit.
5
5
  Home-page: https://developers.kameleoon.com/python-sdk.html
6
6
  Author: Kameleoon
@@ -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
- 'CALL: DataFile(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s, holdout: %s)',
51
- environment, settings, feature_flags, custom_data_info, holdout
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
- 'RETURN: DataFile.new(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s, holdout: %s)',
73
- environment, settings, feature_flags, custom_data_info
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
- f"DataFile{{"
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
- f"}}"
194
+ "}"
185
195
  )
186
196
 
187
197
  class RuleInfo:
@@ -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.operating_system is not None:
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 = cast(VisitorVisits, context.data)
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}}}"
@@ -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
- configuration_json = await self._obtain_configuration(time_stamp)
1439
- if configuration_json:
1440
- data_file = DataFile.from_json(self._config.environment, configuration_json)
1441
- self._data_manager.data_file = data_file
1442
- self._network_manager.url_provider.apply_data_api_domain(data_file.settings.data_api_domain)
1443
- self._call_update_handler_if_needed(time_stamp is not None)
1444
- success = True
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[Dict[str, Any]]:
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
- response = await service.fetch_configuration(self._config.environment, time_stamp)
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) -> (content: %s)", time_stamp, content
1553
+ "RETURN: KameleoonClient._obtain_configuration(time_stamp: %s) -> (fetched_configuration: %s)",
1554
+ time_stamp, fetched_configuration
1551
1555
  )
1552
- return content
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.__previous_visitor_visits: Optional[VisitorVisits] = None
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
- times_started = []
56
+ prev_visits = []
54
57
  for visit in previous_visits:
55
- times_started.append(visit.get("timeStarted", 0))
56
- self.__parse_visit(visit)
57
- self.__previous_visitor_visits = VisitorVisits(times_started)
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.__previous_visitor_visits:
67
- data_to_add.append(self.__previous_visitor_visits)
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.__device is None:
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)
@@ -18,10 +18,14 @@ class HttpMethod(Enum):
18
18
 
19
19
  class Response:
20
20
  """Response"""
21
- def __init__(self, error: Optional[Exception], code: Optional[int], content: Optional[Any]):
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
- return Response(None, resp.status, content)
79
+ headers = dict(resp.headers)
80
+ return Response(None, resp.status, content, headers)
@@ -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()