kameleoon-client-python 3.17.0__tar.gz → 3.18.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 (190) hide show
  1. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/PKG-INFO +16 -16
  2. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/__init__.py +2 -0
  3. kameleoon_client_python-3.18.0/kameleoon/data/application_version.py +39 -0
  4. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/data.py +1 -0
  5. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/manager/visitor.py +20 -3
  6. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/manager/visitor_manager.py +24 -14
  7. kameleoon_client_python-3.18.0/kameleoon/helpers/sem_version.py +60 -0
  8. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/kameleoon_client.py +36 -17
  9. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/kameleoon_client_config.py +2 -2
  10. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/remote_data/remote_visitor_data.py +8 -10
  11. kameleoon_client_python-3.18.0/kameleoon/sdk_version.py +12 -0
  12. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/browser_condition.py +4 -2
  13. kameleoon_client_python-3.18.0/kameleoon/targeting/conditions/sdk_language_condition.py +38 -0
  14. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/targeting_condition.py +1 -0
  15. kameleoon_client_python-3.18.0/kameleoon/targeting/conditions/version_condition.py +61 -0
  16. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/targeting_manager.py +3 -0
  17. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/tree_condition_factory.py +4 -0
  18. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon_client_python.egg-info/PKG-INFO +16 -16
  19. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon_client_python.egg-info/SOURCES.txt +3 -0
  20. kameleoon_client_python-3.17.0/kameleoon/sdk_version.py +0 -40
  21. kameleoon_client_python-3.17.0/kameleoon/targeting/conditions/sdk_language_condition.py +0 -79
  22. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/MANIFEST.in +0 -0
  23. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/README.md +0 -0
  24. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/__init__.py +0 -0
  25. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/client_readiness/__init__.py +0 -0
  26. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/client_readiness/async_readiness.py +0 -0
  27. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/client_readiness/threading_readiness.py +0 -0
  28. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/__init__.py +0 -0
  29. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/consent_blocking_behaviour.py +0 -0
  30. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/custom_data_info.py +0 -0
  31. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/data_file.py +0 -0
  32. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/experiment.py +0 -0
  33. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/feature_flag.py +0 -0
  34. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/me_group.py +0 -0
  35. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/rule.py +0 -0
  36. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/rule_type.py +0 -0
  37. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/settings.py +0 -0
  38. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/variable.py +0 -0
  39. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/variation.py +0 -0
  40. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/configuration/variation_by_exposition.py +0 -0
  41. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/browser.py +0 -0
  42. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/cbscores.py +0 -0
  43. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/conversion.py +0 -0
  44. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/cookie.py +0 -0
  45. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/custom_data.py +0 -0
  46. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/device.py +0 -0
  47. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/geolocation.py +0 -0
  48. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/kcs_heat.py +0 -0
  49. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/manager/__init__.py +0 -0
  50. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/manager/assigned_variation.py +0 -0
  51. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/manager/forced_experiment_variation.py +0 -0
  52. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/manager/forced_feature_variation.py +0 -0
  53. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/manager/forced_variation.py +0 -0
  54. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/manager/legal_consent.py +0 -0
  55. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/manager/page_view_visit.py +0 -0
  56. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/manager/visitor_slot.py +0 -0
  57. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/mapping_identifier.py +0 -0
  58. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/operating_system.py +0 -0
  59. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/page_view.py +0 -0
  60. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/personalization.py +0 -0
  61. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/targeted_segment.py +0 -0
  62. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/unique_identifier.py +0 -0
  63. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/user_agent.py +0 -0
  64. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/data/visitor_visits.py +0 -0
  65. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/defaults.py +0 -0
  66. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/exceptions.py +0 -0
  67. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/helpers/__init__.py +0 -0
  68. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/helpers/domain.py +0 -0
  69. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/helpers/functions.py +0 -0
  70. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/helpers/hasher.py +0 -0
  71. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/helpers/logger.py +0 -0
  72. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/helpers/multi_threading.py +0 -0
  73. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/helpers/nonce.py +0 -0
  74. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/helpers/repeat_timer.py +0 -0
  75. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/helpers/scheduler.py +0 -0
  76. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/helpers/string_utils.py +0 -0
  77. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/helpers/visitor_code.py +0 -0
  78. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/hybrid/__init__.py +0 -0
  79. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/hybrid/hybrid_manager.py +0 -0
  80. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/hybrid/hybrid_manager_impl.py +0 -0
  81. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/kameleoon_client_factory.py +0 -0
  82. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/logging/__init__.py +0 -0
  83. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/logging/kameleoon_logger.py +0 -0
  84. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/logging/log_level.py +0 -0
  85. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/logging/logger.py +0 -0
  86. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/__init__.py +0 -0
  87. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/asyncexec/__init__.py +0 -0
  88. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/asyncexec/async_executor.py +0 -0
  89. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/data/__init__.py +0 -0
  90. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/data/data_manager.py +0 -0
  91. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/evaluation/__init__.py +0 -0
  92. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/evaluation/evaluated_experiment.py +0 -0
  93. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/remote_data/__init__.py +0 -0
  94. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/remote_data/remote_data_manager.py +0 -0
  95. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/tracking/__init__.py +0 -0
  96. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/tracking/tracking_builder.py +0 -0
  97. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/tracking/tracking_manager.py +0 -0
  98. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/tracking/visitor_tracking_registry.py +0 -0
  99. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/warehouse/__init__.py +0 -0
  100. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/managers/warehouse/warehouse_manager.py +0 -0
  101. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/middleware.py +0 -0
  102. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/__init__.py +0 -0
  103. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/access_token_source.py +0 -0
  104. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/access_token_source_factory.py +0 -0
  105. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/activity_event.py +0 -0
  106. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/cookie/__init__.py +0 -0
  107. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/cookie/cookie_manager.py +0 -0
  108. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/net_provider.py +0 -0
  109. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/net_provider_impl.py +0 -0
  110. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/network_manager.py +0 -0
  111. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/network_manager_factory.py +0 -0
  112. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/network_manager_factory_impl.py +0 -0
  113. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/network_manager_impl.py +0 -0
  114. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/query_builder.py +0 -0
  115. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/query_encodable.py +0 -0
  116. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/sendable.py +0 -0
  117. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/service_initialize_context.py +0 -0
  118. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/service_initialize_context_impl.py +0 -0
  119. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/services/__init__.py +0 -0
  120. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/services/automation_service.py +0 -0
  121. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/services/automation_service_impl.py +0 -0
  122. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/services/configuration_service.py +0 -0
  123. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/services/configuration_service_impl.py +0 -0
  124. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/services/data_service.py +0 -0
  125. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/services/data_service_impl.py +0 -0
  126. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/services/service.py +0 -0
  127. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/services/service_impl.py +0 -0
  128. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/uri_helper.py +0 -0
  129. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/network/url_provider.py +0 -0
  130. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/real_time/__init__.py +0 -0
  131. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/real_time/real_time_configuration_service.py +0 -0
  132. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/real_time/real_time_event.py +0 -0
  133. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/storage/__init__.py +0 -0
  134. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/storage/cache.py +0 -0
  135. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/storage/cache_factory.py +0 -0
  136. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/storage/cache_factory_impl.py +0 -0
  137. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/storage/cache_impl.py +0 -0
  138. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/__init__.py +0 -0
  139. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/__init__.py +0 -0
  140. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/constants.py +0 -0
  141. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/conversion_condition.py +0 -0
  142. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/cookie_condition.py +0 -0
  143. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/custom_datum.py +0 -0
  144. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/device_condition.py +0 -0
  145. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/exclusive_experiment_condition.py +0 -0
  146. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/geolocation_condition.py +0 -0
  147. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/kcs_heat_range_condition.py +0 -0
  148. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/number_condition.py +0 -0
  149. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/operating_system_condition.py +0 -0
  150. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/page_title_condition.py +0 -0
  151. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/page_url_condition.py +0 -0
  152. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/page_view_number_condition.py +0 -0
  153. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/previous_page_condition.py +0 -0
  154. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/segment_condition.py +0 -0
  155. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/string_value_condition.py +0 -0
  156. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/target_experiment_condition.py +0 -0
  157. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/target_feature_flag_condition.py +0 -0
  158. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/target_personalization_condition.py +0 -0
  159. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.py +0 -0
  160. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/unknown_condition.py +0 -0
  161. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/visit_number_today_condition.py +0 -0
  162. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/visit_number_total_condition.py +0 -0
  163. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
  164. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/conditions/visitor_new_return_condition.py +0 -0
  165. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/models.py +0 -0
  166. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/targeting/tree_builder.py +0 -0
  167. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/types/__init__.py +0 -0
  168. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/types/remote_visitor_data_filter.py +0 -0
  169. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/types/variable.py +0 -0
  170. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon/types/variation.py +0 -0
  171. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
  172. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon_client_python.egg-info/requires.txt +15 -15
  173. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
  174. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/setup.cfg +0 -0
  175. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/setup.py +0 -0
  176. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/__init__.py +0 -0
  177. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/kameleoon_app/__init__.py +0 -0
  178. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
  179. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/kameleoon_app/apps.py +0 -0
  180. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/kameleoon_app/migrations/__init__.py +0 -0
  181. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
  182. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
  183. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/kameleoon_app/views.py +0 -0
  184. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/manage.py +0 -0
  185. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/proj/__init__.py +0 -0
  186. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/proj/asgi.py +0 -0
  187. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/proj/settings.py +0 -0
  188. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/proj/urls.py +0 -0
  189. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/integration/proj/proj/wsgi.py +0 -0
  190. {kameleoon_client_python-3.17.0 → kameleoon_client_python-3.18.0}/tests/resources/config.yml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kameleoon-client-python
3
- Version: 3.17.0
3
+ Version: 3.18.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
@@ -20,27 +20,27 @@ Requires-Dist: requests<3.0.0,>=2.25
20
20
  Requires-Dist: sseclient-py<1.9.0,>=1.7.0
21
21
  Requires-Dist: aiohttp<4.0.0,>=3.8.0
22
22
  Provides-Extra: test
23
- Requires-Dist: pytest-asyncio==0.21.*; extra == "test"
24
- Requires-Dist: aiohttp<4.0.0,>=3.8.0; extra == "test"
25
- Requires-Dist: freezegun==1.1.0; extra == "test"
26
- Requires-Dist: twine==3.4.1; extra == "test"
27
- Requires-Dist: wheel==0.36.2; extra == "test"
28
- Requires-Dist: Werkzeug==2.0.1; extra == "test"
29
23
  Requires-Dist: mypy==0.991; extra == "test"
30
- Requires-Dist: pytest-ordering==0.6; extra == "test"
31
- Requires-Dist: pytest-cov==2.12.1; extra == "test"
32
- Requires-Dist: sseclient-py<1.9.0,>=1.7.0; extra == "test"
24
+ Requires-Dist: flake8==4.0.1; extra == "test"
25
+ Requires-Dist: types-requests==2.25.0; extra == "test"
26
+ Requires-Dist: pytest-pythonpath==0.7.3; extra == "test"
33
27
  Requires-Dist: aioresponses==0.7.*; extra == "test"
28
+ Requires-Dist: twine==3.4.1; extra == "test"
34
29
  Requires-Dist: pytest-django==4.4.0; extra == "test"
35
30
  Requires-Dist: Django==3.2.4; extra == "test"
36
- Requires-Dist: requests<3.0.0,>=2.25; extra == "test"
37
- Requires-Dist: flake8==4.0.1; extra == "test"
38
- Requires-Dist: pyyaml<6.1.0,>=5.4.0; extra == "test"
31
+ Requires-Dist: pytest-cov==2.12.1; extra == "test"
32
+ Requires-Dist: types-python-dateutil==2.8.2; extra == "test"
39
33
  Requires-Dist: pylint==2.12.*; extra == "test"
34
+ Requires-Dist: aiohttp<4.0.0,>=3.8.0; extra == "test"
35
+ Requires-Dist: Werkzeug==2.0.1; extra == "test"
36
+ Requires-Dist: pytest-asyncio==0.21.*; extra == "test"
37
+ Requires-Dist: sseclient-py<1.9.0,>=1.7.0; extra == "test"
38
+ Requires-Dist: wheel==0.36.2; extra == "test"
40
39
  Requires-Dist: types-PyYAML==5.4.3; extra == "test"
41
- Requires-Dist: pytest-pythonpath==0.7.3; extra == "test"
42
- Requires-Dist: types-requests==2.25.0; extra == "test"
43
- Requires-Dist: types-python-dateutil==2.8.2; extra == "test"
40
+ Requires-Dist: pyyaml<6.1.0,>=5.4.0; extra == "test"
41
+ Requires-Dist: pytest-ordering==0.6; extra == "test"
42
+ Requires-Dist: freezegun==1.1.0; extra == "test"
43
+ Requires-Dist: requests<3.0.0,>=2.25; extra == "test"
44
44
  Dynamic: author
45
45
  Dynamic: author-email
46
46
  Dynamic: classifier
@@ -1,5 +1,6 @@
1
1
  """ Imports all kameleoon data objects """
2
2
 
3
+ from .application_version import ApplicationVersion
3
4
  from .browser import Browser, BrowserType
4
5
  from .conversion import Conversion
5
6
  from .cookie import Cookie
@@ -13,6 +14,7 @@ from .user_agent import UserAgent
13
14
  from .unique_identifier import UniqueIdentifier
14
15
 
15
16
  __all__ = [
17
+ "ApplicationVersion",
16
18
  "Browser",
17
19
  "BrowserType",
18
20
  "Conversion",
@@ -0,0 +1,39 @@
1
+ """Application version data"""
2
+
3
+ from kameleoon.data.data import Data, DataType
4
+
5
+
6
+ class ApplicationVersion(Data):
7
+ """Application version data for targeting by application version.
8
+
9
+ The ApplicationVersion class represents the version of a user's application
10
+ and is used for targeting users based on semantic versioning (major, major.minor,
11
+ or major.minor.patch).
12
+ """
13
+
14
+ def __init__(self, version: str) -> None:
15
+ """
16
+ Creates a new ApplicationVersion.
17
+
18
+ :param version: The application version string (semantic versioning: major, major.minor, or
19
+ major.minor.patch). Examples: "1", "1.2", "1.2.3"
20
+
21
+ Example:
22
+
23
+ .. code-block:: python3
24
+
25
+ kameleoon_client.add_data(visitor_code, ApplicationVersion("1.2.3"))
26
+ """
27
+ self.__version = version
28
+
29
+ @property
30
+ def version(self) -> str:
31
+ """Returns the application version string."""
32
+ return self.__version
33
+
34
+ @property
35
+ def data_type(self) -> DataType:
36
+ return DataType.APPLICATION_VERSION
37
+
38
+ def __str__(self):
39
+ return f"ApplicationVersion{{version:{self.__version}}}"
@@ -25,6 +25,7 @@ class DataType(IntEnum):
25
25
  CBS = 16
26
26
  PERSONALIZATION = 17
27
27
  TARGETED_SEGMENT = 18
28
+ APPLICATION_VERSION = 19
28
29
 
29
30
 
30
31
  class BaseData:
@@ -6,6 +6,7 @@ from typing import Any, Callable, Optional, Dict, List, Iterator, Iterable, cast
6
6
 
7
7
  from kameleoon.data.visitor_visits import VisitorVisits
8
8
  from kameleoon.data.data import Data
9
+ from kameleoon.data.application_version import ApplicationVersion
9
10
  from kameleoon.data.browser import Browser
10
11
  from kameleoon.data.cbscores import CBScores
11
12
  from kameleoon.data.conversion import Conversion
@@ -102,6 +103,14 @@ class Visitor: # pylint: disable=R0904
102
103
  KameleoonLogger.debug('CALL/RETURN: Visitor.operating_system -> (operating_system: %s)', operating_system)
103
104
  return operating_system
104
105
 
106
+ @property
107
+ def application_version(self) -> Optional[ApplicationVersion]:
108
+ """Returns the application version information associated with this Visitor."""
109
+ application_version = self._data.application_version
110
+ KameleoonLogger.debug('CALL/RETURN: Visitor.application_version -> (application_version: %s)',
111
+ application_version)
112
+ return application_version
113
+
105
114
  @property
106
115
  def cookie(self) -> Optional[Cookie]:
107
116
  """Returns the cookie information associated with this Visitor."""
@@ -223,20 +232,22 @@ class Visitor: # pylint: disable=R0904
223
232
  self._data.variations[variation.experiment_id] = variation
224
233
  KameleoonLogger.debug('RETURN: Visitor.assign_variation(variation: %s)', variation)
225
234
 
226
- def add_data(self, *args, overwrite: bool = True) -> None:
235
+ def add_data(self, *args, overwrite: bool = True, track: bool = True) -> None:
227
236
  """Adds data to the Visitor."""
228
- KameleoonLogger.debug('CALL: Visitor.add_data(args: %s, overwrite: %s)', args, overwrite)
237
+ KameleoonLogger.debug('CALL: Visitor.add_data(args: %s, overwrite: %s, track: %s)', args, overwrite, track)
229
238
  with self._data.lock:
230
239
  for data in args:
231
240
  if data is None:
232
241
  continue
242
+ if not track and isinstance(data, Sendable):
243
+ data.mark_as_sent()
233
244
  data_type = type(data)
234
245
  data_adder = self.DATA_ADDERS.get(data_type)
235
246
  if data_adder:
236
247
  data_adder(self, self.DataAddingContext(data, overwrite))
237
248
  else:
238
249
  KameleoonLogger.warning("Data has unsupported type %s", data_type)
239
- KameleoonLogger.debug('RETURN: Visitor.add_data(args: %s, overwrite: %s)', args, overwrite)
250
+ KameleoonLogger.debug('RETURN: Visitor.add_data(args: %s, overwrite: %s, track: %s)', args, overwrite, track)
240
251
 
241
252
  @property
242
253
  def mapping_identifier(self) -> Optional[str]:
@@ -302,6 +313,7 @@ class Visitor: # pylint: disable=R0904
302
313
  self.visitor_visits: Optional[VisitorVisits] = None
303
314
  self.mapping_identifier: Optional[str] = None
304
315
  self.legal_consent = LegalConsent.UNKNOWN
316
+ self.application_version: Optional[ApplicationVersion] = None
305
317
 
306
318
  def enumerate_sendable_data(self) -> Iterator[Sendable]:
307
319
  """Iterates over all sendable data associated with the visitor."""
@@ -420,6 +432,10 @@ class Visitor: # pylint: disable=R0904
420
432
  if context.overwrite or self._data.operating_system is None:
421
433
  self._data.operating_system = cast(OperatingSystem, context.data)
422
434
 
435
+ def _set_application_version(self, context: DataAddingContext) -> None:
436
+ if context.overwrite or self._data.application_version is None:
437
+ self._data.application_version = cast(ApplicationVersion, context.data)
438
+
423
439
  def _set_cookie(self, context: DataAddingContext) -> None:
424
440
  self._data.cookie = cast(Cookie, context.data)
425
441
 
@@ -482,6 +498,7 @@ class Visitor: # pylint: disable=R0904
482
498
  Browser: _set_browser,
483
499
  Geolocation: _set_geolocation,
484
500
  OperatingSystem: _set_operating_system,
501
+ ApplicationVersion: _set_application_version,
485
502
  Cookie: _set_cookie,
486
503
  CustomData: _add_custom_data,
487
504
  MappingIdentifier: _add_custom_data,
@@ -1,4 +1,5 @@
1
1
  """Visitor Manager"""
2
+
2
3
  import collections
3
4
  import time
4
5
  from typing import Any, Dict, Iterator, List, Optional
@@ -14,17 +15,16 @@ from kameleoon.managers.data.data_manager import DataManager
14
15
 
15
16
  class VisitorManager:
16
17
  """Visitor manager"""
17
- def __init__(
18
- self, data_manager: DataManager, expiration_period: float, scheduler: Scheduler
19
- ) -> None:
20
- KameleoonLogger.debug("CALL: VisitorManager(data_manager, expiration_period: %s, scheduler)",
21
- expiration_period)
18
+
19
+ def __init__(self, data_manager: DataManager, expiration_period: float, scheduler: Scheduler) -> None:
20
+ KameleoonLogger.debug("CALL: VisitorManager(data_manager, expiration_period: %s, scheduler)", expiration_period)
22
21
  self._data_manager = data_manager
23
22
  self.__expiration_period = expiration_period
24
23
  self._slots: Dict[str, VisitorSlot] = collections.defaultdict(VisitorSlot)
25
24
  scheduler.schedule_job("VisitorManager.purge", expiration_period, self.__purge)
26
- KameleoonLogger.debug("RETURN: VisitorManager(data_manager, expiration_period: %s, scheduler)",
27
- expiration_period)
25
+ KameleoonLogger.debug(
26
+ "RETURN: VisitorManager(data_manager, expiration_period: %s, scheduler)", expiration_period
27
+ )
28
28
 
29
29
  def __iter__(self) -> Iterator[str]:
30
30
  yield from list(self._slots)
@@ -44,8 +44,9 @@ class VisitorManager:
44
44
  visitor = slot.visitor
45
45
  finally:
46
46
  slot.lock.release()
47
- KameleoonLogger.debug("RETURN: VisitorManager.get_visitor(visitor_code: %s) -> (visitor: %s)",
48
- visitor_code, visitor)
47
+ KameleoonLogger.debug(
48
+ "RETURN: VisitorManager.get_visitor(visitor_code: %s) -> (visitor: %s)", visitor_code, visitor
49
+ )
49
50
  return visitor
50
51
 
51
52
  def get_or_create_visitor(self, visitor_code: str) -> Visitor:
@@ -62,7 +63,7 @@ class VisitorManager:
62
63
  slot.lock.release()
63
64
  KameleoonLogger.debug("RETURN: VisitorManager.get_or_create_visitor(visitor_code: %s)", visitor_code)
64
65
 
65
- def add_data(self, visitor_code: str, *args) -> Visitor:
66
+ def add_data(self, visitor_code: str, *args, track: bool = True) -> Visitor:
66
67
  """
67
68
  Adds data to a visitor.
68
69
 
@@ -70,8 +71,13 @@ class VisitorManager:
70
71
  * marks custom data of the local scope as unsent
71
72
  * converts custom data with the mapping identifier index to the mapping identifier
72
73
  * maps a visitor by its mapping identifier
74
+
75
+ :param track: A boolean indicating whether the data should be tracked (sent to server).
76
+ If False, sendable data will be marked as sent immediately. Default is True.
73
77
  """
74
- KameleoonLogger.debug("CALL: VisitorManager.add_data(visitor_code: %s, args: %s)", visitor_code, args)
78
+ KameleoonLogger.debug(
79
+ "CALL: VisitorManager.add_data(visitor_code: %s, args: %s, track: %s)", visitor_code, args, track
80
+ )
75
81
  visitor = self.get_or_create_visitor(visitor_code)
76
82
  custom_data_info = self._data_manager.data_file.custom_data_info
77
83
  data_to_add: List[Any] = [None] * len(args)
@@ -81,9 +87,13 @@ class VisitorManager:
81
87
  elif isinstance(data, Conversion):
82
88
  data = self.__process_conversion(data, custom_data_info)
83
89
  data_to_add[i] = data
84
- visitor.add_data(*data_to_add)
85
- KameleoonLogger.debug("RETURN: VisitorManager.add_data(visitor_code: %s, args: %s) -> (visitor)",
86
- visitor_code, args)
90
+ visitor.add_data(*data_to_add, track=track)
91
+ KameleoonLogger.debug(
92
+ "RETURN: VisitorManager.add_data(visitor_code: %s, args: %s, track: %s) -> (visitor)",
93
+ visitor_code,
94
+ args,
95
+ track,
96
+ )
87
97
  return visitor
88
98
 
89
99
  def __process_custom_data(
@@ -0,0 +1,60 @@
1
+ """Version utility for parsing and comparing semantic versions"""
2
+
3
+ from typing import Optional
4
+
5
+ from kameleoon.logging.kameleoon_logger import KameleoonLogger
6
+
7
+
8
+ class SemVersion:
9
+ """SemVersion (Semantic versions) is a utility class for parsing and comparing semantic versions.
10
+
11
+ Supports semantic versioning with major, minor, and patch components.
12
+ """
13
+
14
+ @staticmethod
15
+ def from_string(version_string: str) -> Optional["SemVersion"]:
16
+ """
17
+ Parses a version string into a Version object.
18
+
19
+ :param version_string: The version string to parse (e.g., "1", "1.2", "1.2.3")
20
+ :return: Version object or None if parsing failed
21
+ """
22
+ versions = [0, 0, 0]
23
+ version_parts = version_string.split(".")
24
+
25
+ for i in range(min(len(versions), len(version_parts))):
26
+ try:
27
+ versions[i] = int(version_parts[i])
28
+ except ValueError:
29
+ KameleoonLogger.error("Invalid version component, index: %s, value: %s", i, version_parts[i])
30
+ return None
31
+
32
+ return SemVersion(versions[0], versions[1], versions[2])
33
+
34
+ def __init__(self, major: int = 0, minor: int = 0, patch: int = 0) -> None:
35
+ """
36
+ Creates a new Version.
37
+
38
+ :param major: Major version number
39
+ :param minor: Minor version number
40
+ :param patch: Patch version number
41
+ """
42
+ self.major = major
43
+ self.minor = minor
44
+ self.patch = patch
45
+
46
+ def compare_to(self, other: "SemVersion") -> int:
47
+ """
48
+ Compares SemVersion instances
49
+ """
50
+ a = (self.major, self.minor, self.patch)
51
+ b = (other.major, other.minor, other.patch)
52
+ return (a > b) - (a < b)
53
+
54
+ def to_float(self) -> float:
55
+ """
56
+ Converts the version to a float (only major and minor are considered).
57
+
58
+ :return: Float representation of the version (e.g., 1.2)
59
+ """
60
+ return float(f"{self.major}.{self.minor}")
@@ -324,7 +324,7 @@ class KameleoonClient:
324
324
  cookies,
325
325
  )
326
326
 
327
- def add_data(self, visitor_code: str, *args) -> None:
327
+ def add_data(self, visitor_code: str, *args, track: bool = True) -> None:
328
328
  """
329
329
  To associate various data with the current user, we can use the add_data() method.
330
330
  This method requires the visitor_code as a first parameter, and then accepts several additional parameters.
@@ -337,7 +337,9 @@ class KameleoonClient:
337
337
 
338
338
  :param visitor_code: Unique identifier of the user. This field is mandatory.
339
339
  :type visitor_code: str
340
- :param args:
340
+ :param args: One or more Kameleoon Data objects to associate with the visitor.
341
+ :param track: A boolean indicating whether the data should be tracked (sent to server). Default is True.
342
+ :type track: bool
341
343
  :return: None
342
344
 
343
345
  Examples:
@@ -349,13 +351,17 @@ class KameleoonClient:
349
351
  visitor_code = kameleoon_client.get_visitor_code(request.COOKIES)
350
352
  kameleoon_client.add_data(visitor_code, CustomData("test-id", "test-value"))
351
353
  kameleoon_client.add_data(visitor_code, Browser(BrowserType.CHROME))
352
- kameleoon_client.add_data(visitor_code, PageView("www.test.com", "test-title"))
353
- kameleoon_client.add_data(visitor_code, Conversion(1, 100.0))
354
+ kameleoon_client.add_data(visitor_code, PageView("www.test.com", "test-title"), track=True)
355
+ kameleoon_client.add_data(visitor_code, Conversion(1, 100.0), track=False)
354
356
  """
355
- KameleoonLogger.info("CALL: KameleoonClient.add_data(visitor_code: %s, args: %s)", visitor_code, args)
357
+ KameleoonLogger.info(
358
+ "CALL: KameleoonClient.add_data(visitor_code: %s, args: %s, track: %s)", visitor_code, args, track
359
+ )
356
360
  validate_visitor_code(visitor_code)
357
- self._visitor_manager.add_data(visitor_code, *args)
358
- KameleoonLogger.info("RETURN: KameleoonClient.add_data(visitor_code: %s, args: %s)", visitor_code, args)
361
+ self._visitor_manager.add_data(visitor_code, *args, track=track)
362
+ KameleoonLogger.info(
363
+ "RETURN: KameleoonClient.add_data(visitor_code: %s, args: %s, track: %s)", visitor_code, args, track
364
+ )
359
365
 
360
366
  def track_conversion(
361
367
  self,
@@ -481,7 +487,7 @@ class KameleoonClient:
481
487
  )
482
488
 
483
489
  def is_feature_active(
484
- self, visitor_code: str, feature_key: str, is_unique_identifier: Optional[bool] = None, track=True
490
+ self, visitor_code: str, feature_key: str, is_unique_identifier: Optional[bool] = None, track: bool = True
485
491
  ) -> bool:
486
492
  """
487
493
  Check if feature is active for a given visitor code
@@ -561,7 +567,7 @@ class KameleoonClient:
561
567
  )
562
568
  return feature_active
563
569
 
564
- def get_variation(self, visitor_code: str, feature_key: str, track=True) -> Variation:
570
+ def get_variation(self, visitor_code: str, feature_key: str, track: bool = True) -> Variation:
565
571
  """
566
572
  Retrieves the variation assigned to the given visitor for a specific feature flag.
567
573
 
@@ -605,7 +611,7 @@ class KameleoonClient:
605
611
  )
606
612
  return external_variation
607
613
 
608
- def get_variations(self, visitor_code: str, only_active=False, track=True) -> Dict[str, Variation]:
614
+ def get_variations(self, visitor_code: str, only_active=False, track: bool = True) -> Dict[str, Variation]:
609
615
  """
610
616
  Forms a dictionary of variations assigned to a given visitor across all feature flags.
611
617
  This method iterates over all available feature flags and returns the assigned variation for each flag
@@ -757,6 +763,11 @@ class KameleoonClient:
757
763
  save,
758
764
  bucketing_cd_index,
759
765
  )
766
+ consent, blocking_behaviour = self.__get_consent_and_blocking_behaviour(visitor)
767
+ if consent == LegalConsent.NOT_GIVEN and blocking_behaviour == ConsentBlockingBehaviour.COMPLETELY_BLOCKED:
768
+ raise FeatureEnvironmentDisabled(
769
+ "Evaluation for a holdout is blocked because visitor's consent was not provided."
770
+ )
760
771
  is_not_in_holdout = True
761
772
  code_for_hash = self.__get_code_for_hash(visitor, visitor_code, bucketing_cd_index)
762
773
  variation_hash = Hasher.obtain(code_for_hash, holdout.id_)
@@ -1610,7 +1621,7 @@ class KameleoonClient:
1610
1621
  )
1611
1622
  return (feature_flag, variation_key)
1612
1623
 
1613
- def __save_variation(self, visitor_code: str, eval_exp: Optional[EvaluatedExperiment], track=True) -> None:
1624
+ def __save_variation(self, visitor_code: str, eval_exp: Optional[EvaluatedExperiment], track: bool = True) -> None:
1614
1625
  if (eval_exp is None) or (eval_exp.experiment.id_ is None) or (eval_exp.var_by_exp.variation_id is None):
1615
1626
  return
1616
1627
  KameleoonLogger.debug(
@@ -1695,11 +1706,7 @@ class KameleoonClient:
1695
1706
  feature_flag,
1696
1707
  )
1697
1708
  visitor = self._visitor_manager.get_visitor(visitor_code)
1698
- datafile = self._data_manager.data_file
1699
- if datafile.settings.is_consent_required:
1700
- consent = visitor.legal_consent if visitor else LegalConsent.UNKNOWN
1701
- else:
1702
- consent = LegalConsent.GIVEN
1709
+ consent, blocking_behaviour = self.__get_consent_and_blocking_behaviour(visitor)
1703
1710
  code_for_hash = self.__get_code_for_hash(visitor, visitor_code, feature_flag.bucketing_custom_data_index)
1704
1711
  eval_exp = None
1705
1712
  for rule in feature_flag.rules:
@@ -1722,7 +1729,6 @@ class KameleoonClient:
1722
1729
  if hash_rule <= rule.exposition:
1723
1730
  # Checking if the evaluation is blocked due to the consent policy
1724
1731
  if (consent == LegalConsent.NOT_GIVEN) and rule.is_experimentation:
1725
- blocking_behaviour = datafile.settings.blocking_behaviour_if_consent_not_given
1726
1732
  if blocking_behaviour == ConsentBlockingBehaviour.PARTIALLY_BLOCKED:
1727
1733
  break
1728
1734
  raise FeatureEnvironmentDisabled(
@@ -1757,6 +1763,19 @@ class KameleoonClient:
1757
1763
  )
1758
1764
  return eval_exp
1759
1765
 
1766
+ def __get_consent_and_blocking_behaviour(
1767
+ self,
1768
+ visitor: Optional[Visitor],
1769
+ ) -> Tuple[LegalConsent, ConsentBlockingBehaviour]:
1770
+ datafile = self._data_manager.data_file
1771
+ if datafile.settings.is_consent_required:
1772
+ consent = visitor.legal_consent if visitor else LegalConsent.UNKNOWN
1773
+ else:
1774
+ consent = LegalConsent.GIVEN
1775
+ behaviour = datafile.settings.blocking_behaviour_if_consent_not_given
1776
+
1777
+ return consent, behaviour
1778
+
1760
1779
  @staticmethod
1761
1780
  def __calculate_variation_key(eval_exp: Optional[EvaluatedExperiment], default_value: str) -> str:
1762
1781
  KameleoonLogger.debug(
@@ -15,8 +15,8 @@ DEFAULT_REFRESH_INTERVAL_MINUTES = 60
15
15
  DEFAULT_SESSION_DURATION_MINUTES = 30
16
16
  DEFAULT_DEFAULT_TIMEOUT_MILLISECONDS = 10_000
17
17
  DEFAULT_TRACKING_INTERVAL_MILLISECONDS = 1000
18
- MIN_TRACKING_INTERVAL_MILLISECONDS = 100
19
- MAX_TRACKING_INTERVAL_MILLISECONDS = 1000
18
+ MIN_TRACKING_INTERVAL_MILLISECONDS = 1_000
19
+ MAX_TRACKING_INTERVAL_MILLISECONDS = 5_000
20
20
  DEFAULT_CONFIGURATION_PATH = "/etc/kameleoon/client-python.yaml"
21
21
 
22
22
 
@@ -50,15 +50,15 @@ class RemoteVisitorData:
50
50
  self.__visitor_code: Optional[str] = None
51
51
  current_visit = json.get("currentVisit")
52
52
  if current_visit is not None:
53
- self.__parse_visit(current_visit, False)
53
+ self.__parse_visit(current_visit, 0)
54
54
  previous_visits = json.get("previousVisits")
55
55
  if previous_visits:
56
56
  prev_visits = []
57
- for visit in previous_visits:
57
+ for i, visit in enumerate(previous_visits):
58
58
  time_started = visit.get("timeStarted", 0)
59
59
  time_last_event = visit.get("timeLastEvent", time_started)
60
60
  prev_visits.append(VisitorVisits.Visit(time_started, time_last_event))
61
- self.__parse_visit(visit, True)
61
+ self.__parse_visit(visit, i + 1)
62
62
  if len(prev_visits) > 0:
63
63
  self.__visitor_visits = VisitorVisits(prev_visits, self.__visit_number)
64
64
  self.__kcs_heat = self.__parse_kcs_heat(json.get("kcs"))
@@ -123,7 +123,7 @@ class RemoteVisitorData:
123
123
  """Returns the `visitorCode` from the most recent visit"""
124
124
  return self.__visitor_code
125
125
 
126
- def __parse_visit(self, json_visit: Dict[str, Any], is_prev_visit: bool) -> None:
126
+ def __parse_visit(self, json_visit: Dict[str, Any], visit_offset: int) -> None:
127
127
  if (self.__visitor_code is None) and isinstance(visitor_code := json_visit.get("visitorCode"), str):
128
128
  self.__visitor_code = visitor_code
129
129
  custom_data_events = json_visit.get("customDataEvents")
@@ -143,7 +143,7 @@ class RemoteVisitorData:
143
143
  self.__parse_geolocation(geolocation_events[-1])
144
144
  static_data_event = json_visit.get("staticDataEvent")
145
145
  if static_data_event:
146
- self.__parse_static_data(static_data_event, is_prev_visit)
146
+ self.__parse_static_data(static_data_event, visit_offset)
147
147
  personalization_events = json_visit.get("personalizationEvents")
148
148
  if personalization_events:
149
149
  self.__parse_personalizations(personalization_events)
@@ -209,15 +209,13 @@ class RemoteVisitorData:
209
209
  if country is not None:
210
210
  self.__geolocation = Geolocation(country, data.get("region"), data.get("city"))
211
211
 
212
- def __parse_static_data(self, static_data_event: Dict[str, Any], is_prev_visit: bool) -> None:
212
+ def __parse_static_data(self, static_data_event: Dict[str, Any], visit_offset: int) -> None:
213
213
  if self.__device and self.__browser and self.__operating_system:
214
214
  return
215
215
  data = static_data_event.get("data")
216
216
  if data is not 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
217
+ if (self.__visit_number == 0) and (remote_visit_number := data.get("visitNumber")):
218
+ self.__visit_number = remote_visit_number + visit_offset
221
219
  if self.__filter.device and (self.__device is None):
222
220
  device_type = enum_from_name_literal(data.get("deviceType"), DeviceType, None)
223
221
  if device_type is not None:
@@ -0,0 +1,12 @@
1
+ """Kameleoon SDK version"""
2
+
3
+ version_info = (3, 18, 0)
4
+ __version__ = ".".join(str(v) for v in version_info) # uses in scripts
5
+
6
+
7
+ # pylint: disable=R0903
8
+ class SdkVersion:
9
+ """SdkVersion is a helper class for get name and version of sdk"""
10
+
11
+ NAME = "PYTHON"
12
+ VERSION = __version__
@@ -1,8 +1,9 @@
1
1
  """Browser condition"""
2
+
2
3
  from typing import Any, Dict, Union
3
4
  from kameleoon.data import Browser, BrowserType
5
+ from kameleoon.helpers.sem_version import SemVersion
4
6
  from kameleoon.logging.kameleoon_logger import KameleoonLogger
5
- from kameleoon.sdk_version import SdkVersion
6
7
  from kameleoon.targeting.conditions.constants import TargetingOperator
7
8
  from kameleoon.targeting.conditions.targeting_condition import TargetingCondition
8
9
 
@@ -40,7 +41,8 @@ class BrowserCondition(TargetingCondition):
40
41
  return True
41
42
 
42
43
  # If browser types are equal and browser version is defined in condition, then need to compare versions
43
- version_number = SdkVersion.get_float_version(str(self.__version))
44
+ version = SemVersion.from_string(str(self.__version))
45
+ version_number = version.to_float() if version else None
44
46
  if version_number is None:
45
47
  return False
46
48
 
@@ -0,0 +1,38 @@
1
+ """Sdk language condition"""
2
+ from typing import Any, Dict, Union
3
+
4
+ from kameleoon.logging.kameleoon_logger import KameleoonLogger
5
+ from kameleoon.targeting.conditions.version_condition import VersionCondition
6
+
7
+
8
+ class SdkLanguageCondition(VersionCondition):
9
+ """SdkLanguage uses in case if you need to target by sdk type and version"""
10
+
11
+ class SdkInfo:
12
+ """SdkInfo is a helper class to pass sdk name and version as parameters"""
13
+
14
+ def __init__(self, sdk_language: str, version: str) -> None:
15
+ self.__sdk_language = sdk_language
16
+ self.__version = version
17
+
18
+ @property
19
+ def sdk_language(self):
20
+ """Return sdk language (type)"""
21
+ return self.__sdk_language
22
+
23
+ @property
24
+ def version(self):
25
+ """Return sdk version"""
26
+ return self.__version
27
+
28
+ def __init__(self, json_condition: Dict[str, Union[str, int, Any]]):
29
+ super().__init__(json_condition)
30
+ try:
31
+ self.__sdk_language = json_condition.get("sdkLanguage", "")
32
+ except KeyError as ex:
33
+ KameleoonLogger.error("%s has wrong JSON structure: %s", self.__class__, ex)
34
+
35
+ def check(self, data: Any) -> bool:
36
+ return isinstance(data, SdkLanguageCondition.SdkInfo) and \
37
+ self.__sdk_language == data.sdk_language and \
38
+ (self._condition_version is None or self.check_targeting(data.version))
@@ -37,6 +37,7 @@ class TargetingConditionType(Enum):
37
37
  SAME_DAY_VISITS = "SAME_DAY_VISITS"
38
38
  NEW_VISITORS = "NEW_VISITORS"
39
39
  HEAT_SLICE = "HEAT_SLICE"
40
+ APPLICATION_VERSION = "APPLICATION_VERSION"
40
41
  UNKNOWN = "UNKNOWN"
41
42
 
42
43