kameleoon-client-python 3.6.1__tar.gz → 3.8.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 (178) hide show
  1. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/PKG-INFO +1 -1
  2. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/data_file.py +44 -9
  3. kameleoon-client-python-3.8.0/kameleoon/configuration/experiment.py +46 -0
  4. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/rule.py +2 -16
  5. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/data.py +2 -0
  6. kameleoon-client-python-3.8.0/kameleoon/data/manager/forced_experiment_variation.py +49 -0
  7. kameleoon-client-python-3.8.0/kameleoon/data/manager/forced_feature_variation.py +46 -0
  8. kameleoon-client-python-3.8.0/kameleoon/data/manager/forced_variation.py +33 -0
  9. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/visitor.py +59 -2
  10. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/exceptions.py +9 -0
  11. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/functions.py +1 -39
  12. kameleoon-client-python-3.8.0/kameleoon/helpers/hasher.py +24 -0
  13. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/kameleoon_client.py +196 -94
  14. kameleoon-client-python-3.8.0/kameleoon/managers/evaluation/evaluated_experiment.py +50 -0
  15. kameleoon-client-python-3.8.0/kameleoon/network/cookie/cookie_manager.py +200 -0
  16. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/uri_helper.py +6 -1
  17. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/sdk_version.py +1 -1
  18. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/target_feature_flag_condition.py +2 -2
  19. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon_client_python.egg-info/PKG-INFO +1 -1
  20. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon_client_python.egg-info/SOURCES.txt +7 -0
  21. kameleoon-client-python-3.8.0/tests/integration/proj/proj/__init__.py +0 -0
  22. kameleoon-client-python-3.6.1/kameleoon/network/cookie/cookie_manager.py +0 -107
  23. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/MANIFEST.in +0 -0
  24. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/README.md +0 -0
  25. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/__init__.py +0 -0
  26. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/client_readiness/__init__.py +0 -0
  27. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/client_readiness/async_readiness.py +0 -0
  28. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/client_readiness/threading_readiness.py +0 -0
  29. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/__init__.py +0 -0
  30. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/custom_data_info.py +0 -0
  31. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/feature_flag.py +0 -0
  32. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/rule_type.py +0 -0
  33. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/settings.py +0 -0
  34. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/variable.py +0 -0
  35. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/variation.py +0 -0
  36. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/configuration/variation_by_exposition.py +0 -0
  37. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/__init__.py +0 -0
  38. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/browser.py +0 -0
  39. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/conversion.py +0 -0
  40. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/cookie.py +0 -0
  41. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/custom_data.py +0 -0
  42. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/device.py +0 -0
  43. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/geolocation.py +0 -0
  44. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/kcs_heat.py +0 -0
  45. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/__init__.py +0 -0
  46. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/assigned_variation.py +0 -0
  47. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/page_view_visit.py +0 -0
  48. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/visitor_manager.py +0 -0
  49. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/manager/visitor_slot.py +0 -0
  50. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/mapping_identifier.py +0 -0
  51. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/operating_system.py +0 -0
  52. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/page_view.py +0 -0
  53. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/unique_identifier.py +0 -0
  54. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/user_agent.py +0 -0
  55. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/data/visitor_visits.py +0 -0
  56. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/defaults.py +0 -0
  57. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/__init__.py +0 -0
  58. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/domain.py +0 -0
  59. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/logger.py +0 -0
  60. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/multi_threading.py +0 -0
  61. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/nonce.py +0 -0
  62. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/repeat_timer.py +0 -0
  63. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/scheduler.py +0 -0
  64. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/string_utils.py +0 -0
  65. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/helpers/visitor_code.py +0 -0
  66. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/hybrid/__init__.py +0 -0
  67. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/hybrid/hybrid_manager.py +0 -0
  68. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/hybrid/hybrid_manager_impl.py +0 -0
  69. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/kameleoon_client_config.py +0 -0
  70. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/kameleoon_client_factory.py +0 -0
  71. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/logging/__init__.py +0 -0
  72. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/logging/kameleoon_logger.py +0 -0
  73. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/logging/log_level.py +0 -0
  74. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/logging/logger.py +0 -0
  75. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/__init__.py +0 -0
  76. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/asyncexec/__init__.py +0 -0
  77. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/asyncexec/async_executor.py +0 -0
  78. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/data/__init__.py +0 -0
  79. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/data/data_manager.py +0 -0
  80. {kameleoon-client-python-3.6.1/kameleoon/managers/remote_data → kameleoon-client-python-3.8.0/kameleoon/managers/evaluation}/__init__.py +0 -0
  81. {kameleoon-client-python-3.6.1/kameleoon/managers/tracking → kameleoon-client-python-3.8.0/kameleoon/managers/remote_data}/__init__.py +0 -0
  82. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/remote_data/remote_data_manager.py +0 -0
  83. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/remote_data/remote_visitor_data.py +0 -0
  84. {kameleoon-client-python-3.6.1/kameleoon/managers/warehouse → kameleoon-client-python-3.8.0/kameleoon/managers/tracking}/__init__.py +0 -0
  85. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/tracking/tracking_builder.py +0 -0
  86. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/tracking/tracking_manager.py +0 -0
  87. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/tracking/visitor_tracking_registry.py +0 -0
  88. {kameleoon-client-python-3.6.1/kameleoon/network → kameleoon-client-python-3.8.0/kameleoon/managers/warehouse}/__init__.py +0 -0
  89. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/managers/warehouse/warehouse_manager.py +0 -0
  90. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/middleware.py +0 -0
  91. {kameleoon-client-python-3.6.1/kameleoon/network/cookie → kameleoon-client-python-3.8.0/kameleoon/network}/__init__.py +0 -0
  92. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/access_token_source.py +0 -0
  93. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/access_token_source_factory.py +0 -0
  94. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/activity_event.py +0 -0
  95. {kameleoon-client-python-3.6.1/kameleoon/network/services → kameleoon-client-python-3.8.0/kameleoon/network/cookie}/__init__.py +0 -0
  96. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/net_provider.py +0 -0
  97. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/net_provider_impl.py +0 -0
  98. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/network_manager.py +0 -0
  99. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/network_manager_factory.py +0 -0
  100. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/network_manager_factory_impl.py +0 -0
  101. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/network_manager_impl.py +0 -0
  102. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/query_builder.py +0 -0
  103. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/query_encodable.py +0 -0
  104. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/sendable.py +0 -0
  105. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/service_initialize_context.py +0 -0
  106. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/service_initialize_context_impl.py +0 -0
  107. {kameleoon-client-python-3.6.1/kameleoon/real_time → kameleoon-client-python-3.8.0/kameleoon/network/services}/__init__.py +0 -0
  108. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/automation_service.py +0 -0
  109. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/automation_service_impl.py +0 -0
  110. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/configuration_service.py +0 -0
  111. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/configuration_service_impl.py +0 -0
  112. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/data_service.py +0 -0
  113. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/data_service_impl.py +0 -0
  114. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/service.py +0 -0
  115. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/services/service_impl.py +0 -0
  116. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/network/url_provider.py +0 -0
  117. {kameleoon-client-python-3.6.1/kameleoon/storage → kameleoon-client-python-3.8.0/kameleoon/real_time}/__init__.py +0 -0
  118. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/real_time/real_time_configuration_service.py +0 -0
  119. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/real_time/real_time_event.py +0 -0
  120. {kameleoon-client-python-3.6.1/kameleoon/targeting → kameleoon-client-python-3.8.0/kameleoon/storage}/__init__.py +0 -0
  121. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/storage/cache.py +0 -0
  122. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/storage/cache_factory.py +0 -0
  123. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/storage/cache_factory_impl.py +0 -0
  124. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/storage/cache_impl.py +0 -0
  125. {kameleoon-client-python-3.6.1/kameleoon/targeting/conditions → kameleoon-client-python-3.8.0/kameleoon/targeting}/__init__.py +0 -0
  126. {kameleoon-client-python-3.6.1/kameleoon/types → kameleoon-client-python-3.8.0/kameleoon/targeting/conditions}/__init__.py +0 -0
  127. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/browser_condition.py +0 -0
  128. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/constants.py +0 -0
  129. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/conversion_condition.py +0 -0
  130. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/cookie_condition.py +0 -0
  131. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/custom_datum.py +0 -0
  132. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/device_condition.py +0 -0
  133. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/exclusive_feature_flag_condition.py +0 -0
  134. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/geolocation_condition.py +0 -0
  135. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/kcs_heat_range_condition.py +0 -0
  136. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/number_condition.py +0 -0
  137. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/operating_system_condition.py +0 -0
  138. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/page_title_condition.py +0 -0
  139. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/page_url_condition.py +0 -0
  140. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/page_view_number_condition.py +0 -0
  141. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/previous_page_condition.py +0 -0
  142. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/sdk_language_condition.py +0 -0
  143. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/segment_condition.py +0 -0
  144. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/string_value_condition.py +0 -0
  145. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/targeting_condition.py +0 -0
  146. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.py +0 -0
  147. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/unknown_condition.py +0 -0
  148. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/visit_number_today_condition.py +0 -0
  149. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/visit_number_total_condition.py +0 -0
  150. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
  151. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/conditions/visitor_new_return_condition.py +0 -0
  152. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/models.py +0 -0
  153. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/targeting_manager.py +0 -0
  154. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/tree_builder.py +0 -0
  155. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/targeting/tree_condition_factory.py +0 -0
  156. {kameleoon-client-python-3.6.1/tests/integration/proj → kameleoon-client-python-3.8.0/kameleoon/types}/__init__.py +0 -0
  157. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/types/remote_visitor_data_filter.py +0 -0
  158. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/types/variable.py +0 -0
  159. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon/types/variation.py +0 -0
  160. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
  161. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon_client_python.egg-info/requires.txt +15 -15
  162. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
  163. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/setup.cfg +0 -0
  164. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/setup.py +0 -0
  165. {kameleoon-client-python-3.6.1/tests/integration/proj/kameleoon_app → kameleoon-client-python-3.8.0/tests/integration/proj}/__init__.py +0 -0
  166. {kameleoon-client-python-3.6.1/tests/integration/proj/kameleoon_app/migrations → kameleoon-client-python-3.8.0/tests/integration/proj/kameleoon_app}/__init__.py +0 -0
  167. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
  168. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/kameleoon_app/apps.py +0 -0
  169. {kameleoon-client-python-3.6.1/tests/integration/proj/proj → kameleoon-client-python-3.8.0/tests/integration/proj/kameleoon_app/migrations}/__init__.py +0 -0
  170. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
  171. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
  172. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/kameleoon_app/views.py +0 -0
  173. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/manage.py +0 -0
  174. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/proj/asgi.py +0 -0
  175. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/proj/settings.py +0 -0
  176. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/proj/urls.py +0 -0
  177. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.0}/tests/integration/proj/proj/wsgi.py +0 -0
  178. {kameleoon-client-python-3.6.1 → kameleoon-client-python-3.8.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.6.1
3
+ Version: 3.8.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
@@ -3,10 +3,11 @@
3
3
  from typing import Any, Dict, Optional, Set
4
4
  from kameleoon.configuration import Variable
5
5
  from kameleoon.configuration.custom_data_info import CustomDataInfo
6
- from kameleoon.configuration.variation_by_exposition import VariationByExposition
6
+ from kameleoon.configuration.experiment import Experiment
7
7
  from kameleoon.configuration.feature_flag import FeatureFlag
8
8
  from kameleoon.configuration.rule import Rule
9
9
  from kameleoon.configuration.settings import Settings
10
+ from kameleoon.configuration.variation_by_exposition import VariationByExposition
10
11
  from kameleoon.exceptions import FeatureNotFound, FeatureEnvironmentDisabled
11
12
  from kameleoon.logging.kameleoon_logger import KameleoonLogger
12
13
 
@@ -31,7 +32,8 @@ class DataFile:
31
32
  for jobj in configuration.get("featureFlags") or []
32
33
  }
33
34
  custom_data_info = CustomDataInfo(configuration.get("customData"))
34
- data_file = DataFile(environment, settings, feature_flags, custom_data_info)
35
+ holdout = Experiment.from_json(configuration["holdout"]) if "holdout" in configuration else None
36
+ data_file = DataFile(environment, settings, feature_flags, custom_data_info, holdout)
35
37
  return data_file
36
38
 
37
39
  # pylint: disable=R0913
@@ -41,10 +43,12 @@ class DataFile:
41
43
  settings: Settings,
42
44
  feature_flags: Dict[str, FeatureFlag],
43
45
  custom_data_info: CustomDataInfo,
46
+ holdout: Optional[Experiment] = None,
44
47
  ) -> None:
45
48
  KameleoonLogger.debug(
46
- 'CALL: DataFile(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s)',
47
- environment, settings, feature_flags, custom_data_info)
49
+ 'CALL: DataFile(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s, holdout: %s)',
50
+ environment, settings, feature_flags, custom_data_info, holdout
51
+ )
48
52
  self.__environment = environment # pylint: disable=W0238
49
53
  self.__settings = settings
50
54
  self.__feature_flags: Dict[str, FeatureFlag] = feature_flags
@@ -56,13 +60,16 @@ class DataFile:
56
60
  )
57
61
  self.__variation_by_id: Dict[int, VariationByExposition] = {}
58
62
  self.__rule_by_segment_id: Dict[int, Rule] = {}
63
+ self.__rule_info_by_exp_id: Dict[int, DataFile.RuleInfo] = {}
59
64
  self.__feature_flag_by_id: Dict[int, FeatureFlag] = {}
60
65
  self.__experiment_ids_with_js_css_variable: Set[int] = set()
61
66
  self.__collect_indices()
62
67
  self.__custom_data_info = custom_data_info
68
+ self.__holdout = holdout
63
69
  KameleoonLogger.debug(
64
- 'RETURN: DataFile.new(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s)',
65
- environment, settings, feature_flags, custom_data_info)
70
+ 'RETURN: DataFile.new(environment: %s, settings: %s, feature_flags: %s, custom_data_info: %s, holdout: %s)',
71
+ environment, settings, feature_flags, custom_data_info
72
+ )
66
73
 
67
74
  @property
68
75
  def settings(self) -> Settings:
@@ -84,6 +91,11 @@ class DataFile:
84
91
  """Returns dictionary of all rule stored by segment id"""
85
92
  return self.__rule_by_segment_id
86
93
 
94
+ @property
95
+ def rule_info_by_exp_id(self) -> Dict[int, "DataFile.RuleInfo"]:
96
+ """Returns dictionary of all rule related info stored by experiment id"""
97
+ return self.__rule_info_by_exp_id
98
+
87
99
  @property
88
100
  def variation_by_id(self) -> Dict[int, VariationByExposition]:
89
101
  """Returns dictionary of all variations stored by id"""
@@ -108,9 +120,14 @@ class DataFile:
108
120
 
109
121
  @property
110
122
  def custom_data_info(self) -> CustomDataInfo:
111
- """Returns custom data info for mapping device`"""
123
+ """Returns custom data info for mapping device"""
112
124
  return self.__custom_data_info
113
125
 
126
+ @property
127
+ def holdout(self) -> Optional[Experiment]:
128
+ """Returns holdout"""
129
+ return self.__holdout
130
+
114
131
  def has_experiment_js_css_variable(self, experiment_id: int) -> bool:
115
132
  """Returns `True` if the experiment has a JS or CSS variable, otherwise returns `False`"""
116
133
  return experiment_id in self.__experiment_ids_with_js_css_variable
@@ -122,9 +139,10 @@ class DataFile:
122
139
  has_feature_flag_variable_js_css = self.__has_feature_flag_variable_js_css(feature_flag)
123
140
  for rule in feature_flag.rules:
124
141
  self.__rule_by_segment_id[rule.segment_id] = rule
142
+ self.__rule_info_by_exp_id[rule.experiment.id_] = DataFile.RuleInfo(feature_flag, rule)
125
143
  if has_feature_flag_variable_js_css:
126
- self.__experiment_ids_with_js_css_variable.add(rule.experiment_id)
127
- for variation in rule.variation_by_exposition:
144
+ self.__experiment_ids_with_js_css_variable.add(rule.experiment.id_)
145
+ for variation in rule.experiment.variations_by_exposition:
128
146
  if variation.variation_id is not None:
129
147
  self.__variation_by_id[variation.variation_id] = variation
130
148
 
@@ -146,3 +164,20 @@ class DataFile:
146
164
  f"settings:{self.__settings}"
147
165
  f"}}"
148
166
  )
167
+
168
+ class RuleInfo:
169
+ """Aggregates some information related to a specific rule"""
170
+
171
+ def __init__(self, feature_flag: FeatureFlag, rule: Rule) -> None:
172
+ self.__feature_flag = feature_flag
173
+ self.__rule = rule
174
+
175
+ @property
176
+ def feature_flag(self) -> FeatureFlag:
177
+ """Returns the feature flag"""
178
+ return self.__feature_flag
179
+
180
+ @property
181
+ def rule(self) -> Rule:
182
+ """Returns the rule"""
183
+ return self.__rule
@@ -0,0 +1,46 @@
1
+ """Kameleoon Configuration"""
2
+
3
+ from typing import Any, List, Dict, Optional
4
+ from kameleoon.configuration.variation_by_exposition import VariationByExposition
5
+ from kameleoon.exceptions import FeatureVariationNotFound
6
+
7
+
8
+ class Experiment:
9
+ """Experiment"""
10
+
11
+ def __init__(self, id_: int, variations_by_exposition: List[VariationByExposition]) -> None:
12
+ self.id_ = id_
13
+ self.variations_by_exposition = variations_by_exposition
14
+ self.first_variation = variations_by_exposition[0] if len(variations_by_exposition) > 0 else None
15
+
16
+ @staticmethod
17
+ def from_json(dict_json: Dict[str, Any]) -> "Experiment":
18
+ """Creates a new instance of `Experiment` from a json object"""
19
+ id_ = dict_json.get("experimentId", 0)
20
+ variations_by_exposition: List[VariationByExposition] = VariationByExposition.from_array(
21
+ dict_json.get("variationByExposition", [])
22
+ )
23
+ return Experiment(id_, variations_by_exposition)
24
+
25
+ def get_variation(self, hash_double: float) -> Optional[VariationByExposition]:
26
+ """Calculates the variation key for the given hash of visitor"""
27
+
28
+ total = 0.0
29
+ for var_by_exp in self.variations_by_exposition:
30
+ total += var_by_exp.exposition
31
+ if total >= hash_double:
32
+ return var_by_exp
33
+ return None
34
+
35
+ def get_variation_by_key(self, variation_key: str) -> VariationByExposition:
36
+ """
37
+ Finds variation with a passed variation key.
38
+ Raises the `FeatureVariationNotFound` exception if such variation does not exist.
39
+ """
40
+ for var_by_exp in self.variations_by_exposition:
41
+ if var_by_exp.variation_key == variation_key:
42
+ return var_by_exp
43
+ raise FeatureVariationNotFound("'#{variation_key}'")
44
+
45
+ def __str__(self) -> str:
46
+ return f"Experiment{{id:{self.id_}}}"
@@ -1,8 +1,8 @@
1
1
  """Kameleoon Configuration"""
2
2
 
3
3
  from typing import Any, List, Dict, Optional
4
+ from kameleoon.configuration.experiment import Experiment
4
5
  from kameleoon.configuration.rule_type import RuleType, rule_type_from_literal
5
- from kameleoon.configuration.variation_by_exposition import VariationByExposition
6
6
  from kameleoon.targeting.models import Segment
7
7
 
8
8
 
@@ -23,26 +23,12 @@ class Rule:
23
23
  type_literal: str = dict_json.get("type", "")
24
24
  self.type = rule_type_from_literal(type_literal)
25
25
  self.exposition: float = dict_json.get("exposition", 0.0)
26
- self.experiment_id: int = dict_json.get("experimentId", 0)
26
+ self.experiment = Experiment.from_json(dict_json)
27
27
  self.respool_time: Optional[int] = dict_json.get("respoolTime", None)
28
- self.variation_by_exposition: List[VariationByExposition] = VariationByExposition.from_array(
29
- dict_json.get("variationByExposition", [])
30
- )
31
- self.first_variation = self.variation_by_exposition[0] if len(self.variation_by_exposition) > 0 else None
32
28
  segment = dict_json.get("segment")
33
29
  self.targeting_segment: Optional[Segment] = Segment(segment) if segment else None
34
30
  self.segment_id: int = self.targeting_segment.id_ if self.targeting_segment else -1
35
31
 
36
- def get_variation(self, hash_double: float) -> Optional[VariationByExposition]:
37
- """Calculates the variation key for the given hash of visitor"""
38
-
39
- total = 0.0
40
- for var_by_exp in self.variation_by_exposition:
41
- total += var_by_exp.exposition
42
- if total >= hash_double:
43
- return var_by_exp
44
- return None
45
-
46
32
  @property
47
33
  def is_experimentation(self) -> bool:
48
34
  """Return `true` if rule is `experimentation` type"""
@@ -20,6 +20,8 @@ class DataType(IntEnum):
20
20
  VISITOR_VISITS = 11
21
21
  KCS_HEAT = 12
22
22
  UNIQUE_IDENTIFIER = 13
23
+ FORCED_EXPERIMENT_VARIATION = 14
24
+ FORCED_FEATURE_VARIATION = 15
23
25
 
24
26
 
25
27
  class BaseData:
@@ -0,0 +1,49 @@
1
+ """Forced Experiment Variation"""
2
+
3
+ from typing import Any, cast
4
+ from kameleoon.configuration.rule import Rule
5
+ from kameleoon.configuration.variation_by_exposition import VariationByExposition
6
+ from kameleoon.data.data import DataType
7
+ from kameleoon.data.manager.forced_variation import ForcedVariation
8
+
9
+
10
+ class ForcedExperimentVariation(ForcedVariation):
11
+ """Represents a forced experiment variation"""
12
+
13
+ def __init__(
14
+ self, rule: Rule, var_by_exp: VariationByExposition, force_targeting: bool
15
+ ) -> None:
16
+ super().__init__(rule, var_by_exp)
17
+ self.__force_targeting = force_targeting
18
+
19
+ @property
20
+ def data_type(self) -> DataType:
21
+ return DataType.FORCED_EXPERIMENT_VARIATION
22
+
23
+ @property
24
+ def rule(self) -> Rule:
25
+ """Returns the rule"""
26
+ return self._rule or cast(Rule, self._rule)
27
+
28
+ @property
29
+ def var_by_exp(self) -> VariationByExposition:
30
+ """Returns the variation by exposition"""
31
+ return self._var_by_exp or cast(VariationByExposition, self._var_by_exp)
32
+
33
+ @property
34
+ def force_targeting(self) -> bool:
35
+ """Returns the force targeting flag's state"""
36
+ return self.__force_targeting
37
+
38
+ def __eq__(self, value: Any) -> bool:
39
+ return super().__eq__(value) and isinstance(value, ForcedExperimentVariation) and \
40
+ (self.__force_targeting == value.force_targeting)
41
+
42
+ def __str__(self) -> str:
43
+ return (
44
+ "ForcedExperimentVariation{"
45
+ f"rule:{self._rule},"
46
+ f"var_by_exp:{self._var_by_exp},"
47
+ f"force_targeting:{self.__force_targeting},"
48
+ "}"
49
+ )
@@ -0,0 +1,46 @@
1
+ """Forced Feature Variation"""
2
+
3
+ from typing import Any, Optional
4
+ from kameleoon.configuration.rule import Rule
5
+ from kameleoon.configuration.variation_by_exposition import VariationByExposition
6
+ from kameleoon.data.data import DataType
7
+ from kameleoon.data.manager.forced_variation import ForcedVariation
8
+
9
+
10
+ class ForcedFeatureVariation(ForcedVariation):
11
+ """Represents a forced feature variation"""
12
+
13
+ def __init__(
14
+ self, feature_key: str, rule: Optional[Rule], var_by_exp: Optional[VariationByExposition], simulated: bool
15
+ ) -> None:
16
+ super().__init__(rule, var_by_exp)
17
+ self.__feature_key = feature_key
18
+ self.__simulated = simulated
19
+
20
+ @property
21
+ def data_type(self) -> DataType:
22
+ return DataType.FORCED_FEATURE_VARIATION
23
+
24
+ @property
25
+ def feature_key(self) -> str:
26
+ """Returns the feature key"""
27
+ return self.__feature_key
28
+
29
+ @property
30
+ def simulated(self) -> bool:
31
+ """Returns the simulated flag's state"""
32
+ return self.__simulated
33
+
34
+ def __eq__(self, value: Any) -> bool:
35
+ return super().__eq__(value) and isinstance(value, ForcedFeatureVariation) and \
36
+ (self.__feature_key == value.feature_key) and (self.__simulated == value.simulated)
37
+
38
+ def __str__(self) -> str:
39
+ return (
40
+ "ForcedFeatureVariation{"
41
+ f"feature_key:'{self.__feature_key}',"
42
+ f"rule:{self._rule},"
43
+ f"var_by_exp:{self._var_by_exp},"
44
+ f"simulated:{self.__simulated},"
45
+ "}"
46
+ )
@@ -0,0 +1,33 @@
1
+ """Forced Variation"""
2
+
3
+ from typing import Any, Optional
4
+ from kameleoon.configuration.rule import Rule
5
+ from kameleoon.configuration.variation_by_exposition import VariationByExposition
6
+ from kameleoon.data.data import BaseData, DataType
7
+
8
+
9
+ class ForcedVariation(BaseData):
10
+ """Represents a forced variation"""
11
+
12
+ def __init__(self, rule: Optional[Rule], var_by_exp: Optional[VariationByExposition]) -> None:
13
+ super().__init__()
14
+ self._rule = rule
15
+ self._var_by_exp = var_by_exp
16
+
17
+ @property
18
+ def data_type(self) -> DataType:
19
+ raise NotImplementedError
20
+
21
+ @property
22
+ def rule(self) -> Optional[Rule]:
23
+ """Returns the rule"""
24
+ return self._rule
25
+
26
+ @property
27
+ def var_by_exp(self) -> Optional[VariationByExposition]:
28
+ """Returns the variation by exposition"""
29
+ return self._var_by_exp
30
+
31
+ def __eq__(self, value: Any) -> bool:
32
+ return isinstance(value, ForcedVariation) and \
33
+ (self._rule == value._rule) and (self._var_by_exp == value._var_by_exp)
@@ -1,6 +1,6 @@
1
1
  """Visitor"""
2
2
  from threading import Lock
3
- from typing import Any, Callable, Optional, Dict, List, Iterator, cast
3
+ from typing import Any, Callable, Optional, Dict, List, Iterator, Iterable, cast
4
4
 
5
5
  from kameleoon.data.visitor_visits import VisitorVisits
6
6
  from kameleoon.data.data import Data
@@ -17,6 +17,8 @@ from kameleoon.data.page_view import PageView
17
17
  from kameleoon.data.unique_identifier import UniqueIdentifier
18
18
  from kameleoon.data.user_agent import UserAgent
19
19
  from kameleoon.data.manager.assigned_variation import AssignedVariation
20
+ from kameleoon.data.manager.forced_experiment_variation import ForcedExperimentVariation
21
+ from kameleoon.data.manager.forced_feature_variation import ForcedFeatureVariation
20
22
  from kameleoon.data.manager.page_view_visit import PageViewVisit
21
23
  from kameleoon.logging.kameleoon_logger import KameleoonLogger
22
24
  from kameleoon.network.sendable import Sendable
@@ -26,7 +28,7 @@ EMPTY_DICT: Dict[Any, Any] = {}
26
28
  EMPTY_LIST: List[Any] = []
27
29
 
28
30
 
29
- class Visitor:
31
+ class Visitor: # pylint: disable=R0904
30
32
  """Visitor"""
31
33
  def __init__(self, source: Optional["Visitor"] = None) -> None:
32
34
  if source is None:
@@ -124,6 +126,45 @@ class Visitor:
124
126
  KameleoonLogger.debug('CALL/RETURN: Visitor.variations -> (variations: %s)', variations)
125
127
  return variations
126
128
 
129
+ def get_forced_feature_variation(self, feature_key: str) -> Optional[ForcedFeatureVariation]:
130
+ """
131
+ Returns an associated forced feature variation by its feature key if it is present.
132
+ Otherwise returns `None`.
133
+ """
134
+ KameleoonLogger.debug('CALL: Visitor.get_forced_feature_variation(feature_key: %s)', feature_key)
135
+ ffv = self._data.simulated_variations.get(feature_key) if self._data.simulated_variations else None
136
+ KameleoonLogger.debug(
137
+ 'RETURN: Visitor.get_forced_feature_variation(feature_key: %s) -> (variation: %s)', feature_key, ffv
138
+ )
139
+ return ffv
140
+
141
+ def get_forced_experiment_variation(self, experiment_id: int) -> Optional[ForcedExperimentVariation]:
142
+ """
143
+ Returns an associated forced experiment variation by its experiment id if it is present.
144
+ Otherwise returns `None`.
145
+ """
146
+ KameleoonLogger.debug('CALL: Visitor.get_forced_experiment_variation(experiment_id: %s)', experiment_id)
147
+ fev = self._data.forced_variations.get(experiment_id) if self._data.forced_variations else None
148
+ KameleoonLogger.debug(
149
+ 'RETURN: Visitor.get_forced_experiment_variation(experiment_id: %s) -> (variation: %s)', experiment_id, fev
150
+ )
151
+ return fev
152
+
153
+ def reset_forced_experiment_variation(self, experiment_id: int) -> None:
154
+ """Resets an associated forced experiment variation for some experiment id"""
155
+ KameleoonLogger.debug('CALL: Visitor.reset_forced_experiment_variation(experiment_id: %s)', experiment_id)
156
+ if self._data.forced_variations:
157
+ self._data.forced_variations.pop(experiment_id, None)
158
+ KameleoonLogger.debug('RETURN: Visitor.reset_forced_experiment_variation(experiment_id: %s)', experiment_id)
159
+
160
+ def update_simulated_variations(self, variations: Iterable[ForcedFeatureVariation]) -> None:
161
+ """Updates the associated simulated variations"""
162
+ if not (self._data.simulated_variations or variations):
163
+ return
164
+ KameleoonLogger.debug('CALL: Visitor.update_simulated_variations(variations: %s)', variations)
165
+ self._data.simulated_variations = {sv.feature_key: sv for sv in variations}
166
+ KameleoonLogger.debug('RETURN: Visitor.update_simulated_variations(variations: %s)', variations)
167
+
127
168
  @property
128
169
  def kcs_heat(self) -> Optional[KcsHeat]:
129
170
  """Returns the KCS heat data associated with this Visitor."""
@@ -217,6 +258,8 @@ class Visitor:
217
258
  self.page_view_visits: Optional[Dict[str, PageViewVisit]] = None
218
259
  self.conversions: Optional[List[Conversion]] = None
219
260
  self.variations: Optional[Dict[int, AssignedVariation]] = None
261
+ self.forced_variations: Optional[Dict[int, ForcedExperimentVariation]] = None
262
+ self.simulated_variations: Optional[Dict[str, ForcedFeatureVariation]] = None
220
263
  self.kcs_heat: Optional[KcsHeat] = None
221
264
  self.visitor_visits: Optional[VisitorVisits] = None
222
265
  self.mapping_identifier: Optional[str] = None
@@ -294,6 +337,18 @@ class Visitor:
294
337
  if context.overwrite or variation.experiment_id not in self.variations:
295
338
  self._data.variations[variation.experiment_id] = variation
296
339
 
340
+ def _add_forced_feature_variation(self, context: DataAddingContext) -> None:
341
+ ffv = cast(ForcedFeatureVariation, context.data)
342
+ if self._data.simulated_variations is None:
343
+ self._data.simulated_variations = {}
344
+ self._data.simulated_variations[ffv.feature_key] = ffv
345
+
346
+ def _add_forced_experiment_variation(self, context: DataAddingContext) -> None:
347
+ fev = cast(ForcedExperimentVariation, context.data)
348
+ if self._data.forced_variations is None:
349
+ self._data.forced_variations = {}
350
+ self._data.forced_variations[fev.rule.experiment.id_] = fev
351
+
297
352
  def _set_browser(self, context: DataAddingContext) -> None:
298
353
  if context.overwrite or self._data.browser is None:
299
354
  self._data.browser = cast(Browser, context.data)
@@ -372,5 +427,7 @@ class Visitor:
372
427
  KcsHeat: _set_kcs_heat,
373
428
  VisitorVisits: _set_visitor_visits,
374
429
  AssignedVariation: _add_variation,
430
+ ForcedFeatureVariation: _add_forced_feature_variation,
431
+ ForcedExperimentVariation: _add_forced_experiment_variation,
375
432
  UniqueIdentifier: _set_is_unique_identifier,
376
433
  }
@@ -70,6 +70,15 @@ class FeatureNotFound(NotFoundError):
70
70
  super().__init__(self.message)
71
71
 
72
72
 
73
+ class FeatureExperimentNotFound(NotFoundError): # //~ Derived from FeatureError in other SDKs
74
+ """Exception indicating that the requested experiment has not been found.
75
+ Check that the experiment's ID matches the provided one."""
76
+
77
+ def __init__(self, message=None) -> None:
78
+ self.message = "Experiment " + str(message)
79
+ super().__init__(self.message)
80
+
81
+
73
82
  class FeatureVariableNotFound(NotFoundError):
74
83
  """Exception indicating that the requested variable has not been found.
75
84
  Check that the variable's ID (or key) matches the one in your code."""
@@ -1,46 +1,8 @@
1
1
  """Helper functions"""
2
- import hashlib
3
2
  import json
4
- import math
5
3
  import sys
6
4
  from enum import Enum
7
- from typing import Dict, Any, Optional, Union, Type, TypeVar
8
-
9
-
10
- def obtain_hash_double(
11
- visitor_code: str, respool_times=None, container_id: str = ""
12
- ) -> float:
13
- """Calculate the hash value for a given visitor_code"""
14
- return _obtain_hash_double(visitor_code, respool_times, container_id)
15
-
16
-
17
- def obtain_hash_double_rule(
18
- visitor_code: str, container_id: int, respool_time: Optional[int] = None
19
- ) -> float:
20
- """Calculate the hash value for feature flag v2 for a given visitor_code"""
21
- return _obtain_hash_double(
22
- visitor_code=visitor_code,
23
- container_id=container_id,
24
- suffix=str(respool_time) if respool_time else "",
25
- )
26
-
27
-
28
- def _obtain_hash_double(
29
- visitor_code: str,
30
- respool_times=None,
31
- container_id: Union[str, int] = "",
32
- suffix: str = "",
33
- ) -> float:
34
- if respool_times is None:
35
- respool_times = {}
36
- identifier = visitor_code
37
- identifier += str(container_id)
38
- identifier += suffix
39
- if respool_times:
40
- identifier += "".join([str(v) for k, v in sorted(respool_times.items())])
41
- return int(hashlib.sha256(identifier.encode("UTF-8")).hexdigest(), 16) / math.pow(
42
- 2, 256
43
- )
5
+ from typing import Dict, Any, Optional, Type, TypeVar
44
6
 
45
7
 
46
8
  def load_params_from_json(json_path) -> Dict[Any, Any]:
@@ -0,0 +1,24 @@
1
+ """Helper hash functions"""
2
+
3
+ import hashlib
4
+ import math
5
+ from typing import Optional
6
+
7
+
8
+ class Hasher:
9
+ """Hasher"""
10
+
11
+ @staticmethod
12
+ def obtain(
13
+ visitor_code: str, container_id: int, respool_time: Optional[int] = None
14
+ ) -> float:
15
+ """Calculate the hash value for feature flag v2 for a given visitor_code"""
16
+ identifier = visitor_code
17
+ identifier += str(container_id)
18
+ if respool_time:
19
+ identifier += str(respool_time)
20
+ return Hasher._calculate(identifier)
21
+
22
+ @staticmethod
23
+ def _calculate(str_to_hash: str) -> float:
24
+ return int(hashlib.sha256(str_to_hash.encode("UTF-8")).hexdigest(), 16) / math.pow(2, 256)