wingify-fme-python-sdk 1.60.0__tar.gz → 1.61.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 (152) hide show
  1. {wingify_fme_python_sdk-1.60.0/wingify_fme_python_sdk.egg-info → wingify_fme_python_sdk-1.61.0}/PKG-INFO +1 -1
  2. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/setup.py +1 -1
  3. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/api/get_flag_api.py +15 -5
  4. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/constants/Constants.py +1 -1
  5. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/core/segmentation_manager.py +18 -7
  6. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/resources/error-messages.json +3 -1
  7. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/services/hooks_manager.py +10 -1
  8. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/campaign_util.py +81 -0
  9. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/meg_util.py +9 -5
  10. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/rule_evaluation_util.py +2 -1
  11. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/wingify_client.py +24 -20
  12. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0/wingify_fme_python_sdk.egg-info}/PKG-INFO +1 -1
  13. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/LICENSE +0 -0
  14. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/MANIFEST.in +0 -0
  15. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/NOTICE +0 -0
  16. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/README.md +0 -0
  17. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/requirements-dev.txt +0 -0
  18. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/requirements.txt +0 -0
  19. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/setup.cfg +0 -0
  20. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/vwo/__init__.py +0 -0
  21. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/vwo/vwo.py +0 -0
  22. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/vwo/vwo_builder.py +0 -0
  23. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/vwo/vwo_client.py +0 -0
  24. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/__init__.py +0 -0
  25. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/api/__init__.py +0 -0
  26. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/api/set_attribute_api.py +0 -0
  27. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/api/track_api.py +0 -0
  28. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/constants/__init__.py +0 -0
  29. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/decorators/__init__.py +0 -0
  30. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/decorators/storage_decorator.py +0 -0
  31. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/enums/__init__.py +0 -0
  32. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/enums/api_enum.py +0 -0
  33. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/enums/campaign_type_enum.py +0 -0
  34. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/enums/debug_category_enum.py +0 -0
  35. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/enums/event_enum.py +0 -0
  36. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/enums/headers_enum.py +0 -0
  37. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/enums/hooks_enum.py +0 -0
  38. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/enums/status_enum.py +0 -0
  39. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/enums/storage_enum.py +0 -0
  40. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/enums/url_enum.py +0 -0
  41. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/Alias.py +0 -0
  42. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/AliasSetResponse.py +0 -0
  43. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/__init__.py +0 -0
  44. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/batch_event_data.py +0 -0
  45. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/campaign/__init__.py +0 -0
  46. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/campaign/campaign_model.py +0 -0
  47. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/campaign/feature_model.py +0 -0
  48. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/campaign/holdout_model.py +0 -0
  49. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/campaign/impact_campaign_model.py +0 -0
  50. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/campaign/metric_model.py +0 -0
  51. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/campaign/rule_model.py +0 -0
  52. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/campaign/variable_model.py +0 -0
  53. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/campaign/variation_model.py +0 -0
  54. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/gateway_service_model.py +0 -0
  55. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/__init__.py +0 -0
  56. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/campaign_group_schema.py +0 -0
  57. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/campaign_metric_schema.py +0 -0
  58. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/campaign_schema.py +0 -0
  59. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/campaign_variation_schema.py +0 -0
  60. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/empty_object_schema.py +0 -0
  61. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/feature_schema.py +0 -0
  62. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/group_schema.py +0 -0
  63. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/holdout_schema.py +0 -0
  64. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/rule_schema.py +0 -0
  65. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/settings_schema.py +0 -0
  66. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/schemas/variable_schema.py +0 -0
  67. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/settings/__init__.py +0 -0
  68. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/settings/settings_model.py +0 -0
  69. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/storage/__init__.py +0 -0
  70. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/storage/storage_model.py +0 -0
  71. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/user/__init__.py +0 -0
  72. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/user/context_model.py +0 -0
  73. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/user/context_vwo_model.py +0 -0
  74. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/user/get_flag.py +0 -0
  75. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/vwo_options_model.py +0 -0
  76. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/models/wingify_options_model.py +0 -0
  77. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/__init__.py +0 -0
  78. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/decision_maker/__init__.py +0 -0
  79. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/decision_maker/decision_maker.py +0 -0
  80. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/logger/__init__.py +0 -0
  81. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/logger/core/__init__.py +0 -0
  82. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/logger/core/log_manager.py +0 -0
  83. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/logger/core/log_transport_manager.py +0 -0
  84. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/logger/enums/__init__.py +0 -0
  85. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/logger/enums/log_level_enum.py +0 -0
  86. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/logger/enums/log_level_number_enum.py +0 -0
  87. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/logger/log_message_builder.py +0 -0
  88. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/logger/logger.py +0 -0
  89. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/logger/transports/__init__.py +0 -0
  90. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/logger/transports/console_transport.py +0 -0
  91. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/network_layer/__init__.py +0 -0
  92. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/network_layer/client/__init__.py +0 -0
  93. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/network_layer/client/network_client.py +0 -0
  94. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/network_layer/handlers/__init__.py +0 -0
  95. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/network_layer/handlers/request_handler.py +0 -0
  96. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/network_layer/manager/__init__.py +0 -0
  97. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/network_layer/manager/network_manager.py +0 -0
  98. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/network_layer/models/__init__.py +0 -0
  99. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/network_layer/models/global_request_model.py +0 -0
  100. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/network_layer/models/request_model.py +0 -0
  101. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/network_layer/models/response_model.py +0 -0
  102. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/__init__.py +0 -0
  103. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/core/__init__.py +0 -0
  104. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/enums/__init__.py +0 -0
  105. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/enums/segment_operand_regex_enum.py +0 -0
  106. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/enums/segment_operand_value_enum.py +0 -0
  107. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/enums/segment_operator_value_enum.py +0 -0
  108. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/evaluators/__init__.py +0 -0
  109. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/evaluators/segment_evaluator.py +0 -0
  110. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/evaluators/segment_operand_evaluator.py +0 -0
  111. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/utils/__init__.py +0 -0
  112. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/utils/segment_util.py +0 -0
  113. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/segmentation_evaluator/utils/web_testing_segment_util.py +0 -0
  114. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/storage/__init__.py +0 -0
  115. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/storage/connector.py +0 -0
  116. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/packages/storage/storage.py +0 -0
  117. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/resources/__init__.py +0 -0
  118. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/resources/debug-messages.json +0 -0
  119. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/resources/info-message.json +0 -0
  120. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/resources/trace-messages.json +0 -0
  121. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/resources/warn-messages.json +0 -0
  122. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/services/__init__.py +0 -0
  123. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/services/batch_event_queue.py +0 -0
  124. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/services/campaign_decision_service.py +0 -0
  125. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/services/settings_manager.py +0 -0
  126. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/services/storage_service.py +0 -0
  127. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/services/url_service.py +0 -0
  128. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/__init__.py +0 -0
  129. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/aliasing_util.py +0 -0
  130. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/brand_context.py +0 -0
  131. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/brand_util.py +0 -0
  132. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/data_type_util.py +0 -0
  133. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/debugger_service_util.py +0 -0
  134. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/decision_util.py +0 -0
  135. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/event_util.py +0 -0
  136. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/function_util.py +0 -0
  137. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/gateway_service_util.py +0 -0
  138. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/holdout_util.py +0 -0
  139. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/impression_util.py +0 -0
  140. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/log_message_util.py +0 -0
  141. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/model_utils.py +0 -0
  142. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/network_util.py +0 -0
  143. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/settings_util.py +0 -0
  144. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/usage_stats_util.py +0 -0
  145. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/utils/uuid_util.py +0 -0
  146. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/vwo_client.py +0 -0
  147. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/wingify.py +0 -0
  148. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify/wingify_builder.py +0 -0
  149. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify_fme_python_sdk.egg-info/SOURCES.txt +0 -0
  150. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify_fme_python_sdk.egg-info/dependency_links.txt +0 -0
  151. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify_fme_python_sdk.egg-info/requires.txt +0 -0
  152. {wingify_fme_python_sdk-1.60.0 → wingify_fme_python_sdk-1.61.0}/wingify_fme_python_sdk.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wingify-fme-python-sdk
3
- Version: 1.60.0
3
+ Version: 1.61.0
4
4
  Summary: Wingify Feature Management and Experimentation SDK for Python
5
5
  Home-page: https://github.com/wingify/vwo-fme-python-sdk
6
6
  Author: Wingify
@@ -143,7 +143,7 @@ class PostDevelopCommand(develop):
143
143
 
144
144
  setup(
145
145
  name=_brand["name"],
146
- version="1.60.0",
146
+ version="1.61.0",
147
147
  description=_brand["description"],
148
148
  long_description=long_description,
149
149
  long_description_content_type="text/markdown",
@@ -41,7 +41,11 @@ from ..utils.impression_util import (
41
41
  from ..models.user.get_flag import GetFlag
42
42
  from ..services.storage_service import StorageService
43
43
  from ..decorators.storage_decorator import StorageDecorator
44
- from ..utils.campaign_util import get_variation_from_campaign_key
44
+ from ..utils.campaign_util import (
45
+ get_experiment_key,
46
+ get_rollout_key,
47
+ get_variation_from_campaign_key,
48
+ )
45
49
  from ..enums.debug_category_enum import DebugCategoryEnum
46
50
  from ..packages.logger.enums.log_level_enum import LogLevelEnum
47
51
  from ..constants.Constants import Constants
@@ -392,7 +396,7 @@ class GetFlagApi:
392
396
 
393
397
  self._evaluated_feature_map[feature_key] = {
394
398
  "rolloutId": rule.get_id(),
395
- "rolloutKey": rule.get_key(),
399
+ "rolloutKey": get_rollout_key(rule, feature_key),
396
400
  "rolloutVariationId": (
397
401
  rule.get_variations()[0].get_id()
398
402
  if rule.get_variations()
@@ -493,7 +497,9 @@ class GetFlagApi:
493
497
  self._passed_rules_information.update(
494
498
  {
495
499
  "experimentId": rule.get_id(),
496
- "experimentKey": rule.get_key(),
500
+ "experimentKey": get_experiment_key(
501
+ rule, feature.get_key()
502
+ ),
497
503
  "experimentVariationId": whitelisted_object[
498
504
  "variationId"
499
505
  ],
@@ -627,7 +633,9 @@ class GetFlagApi:
627
633
  self._passed_rules_information.update(
628
634
  {
629
635
  "rolloutId": campaign.get_id(),
630
- "rolloutKey": campaign.get_key(),
636
+ "rolloutKey": get_rollout_key(
637
+ campaign, decision.get("featureKey")
638
+ ),
631
639
  "rolloutVariationId": variation.get_id(),
632
640
  }
633
641
  )
@@ -635,7 +643,9 @@ class GetFlagApi:
635
643
  self._passed_rules_information.update(
636
644
  {
637
645
  "experimentId": campaign.get_id(),
638
- "experimentKey": campaign.get_key(),
646
+ "experimentKey": get_experiment_key(
647
+ campaign, decision.get("featureKey")
648
+ ),
639
649
  "experimentVariationId": variation.get_id(),
640
650
  }
641
651
  )
@@ -17,7 +17,7 @@ class Constants:
17
17
  # TODO: read from setup.py
18
18
  sdk_meta = {
19
19
  "name": "vwo-fme-python-sdk",
20
- "version": "1.60.0",
20
+ "version": "1.61.0",
21
21
  }
22
22
 
23
23
  SDK_VERSION = sdk_meta["version"]
@@ -85,14 +85,25 @@ class SegmentationManager:
85
85
 
86
86
  # Check if any holdout requires gateway service
87
87
  holdouts = settings.get_holdouts() or []
88
- is_gateway_service_required_for_holdouts = len(list(filter(lambda holdout: holdout.get_is_gateway_service_required(), holdouts))) > 0
89
- # Call gateway service if required for segmentation OR if gateway service is provided and user agent is available
88
+ is_gateway_service_required_for_holdouts = len(
89
+ list(
90
+ filter(
91
+ lambda holdout: holdout.get_is_gateway_service_required(), holdouts
92
+ )
93
+ )
94
+ ) > 0
95
+ is_segmentation_gateway_required = (
96
+ feature.get_is_gateway_service_required()
97
+ or is_gateway_service_required_for_holdouts
98
+ )
99
+ # Call get-user-details only when gateway_service is configured and
100
+ # segmentation (feature or holdout) requires gateway data.
101
+ # proxy_url alone must never trigger a gateway call.
90
102
  should_call_gateway_service = (
91
- (feature.get_is_gateway_service_required() and not SettingsManager.get_instance().is_on_platform_host()) or
92
- (not SettingsManager.get_instance().is_on_platform_host() and
93
- (context.get_user_agent() or context.get_ip_address()))
94
- ) or is_gateway_service_required_for_holdouts
95
-
103
+ SettingsManager.get_instance().is_gateway_service_provided
104
+ and is_segmentation_gateway_required
105
+ )
106
+
96
107
  if should_call_gateway_service and context.get_vwo() is None:
97
108
  query_params = {}
98
109
  if not context.get_user_agent() and not context.get_ip_address():
@@ -12,13 +12,15 @@
12
12
  "UPDATING_CLIENT_INSTANCE_FAILED_WHEN_WEBHOOK_TRIGGERED": "Failed to fetch settings. {brand} client instance couldn't be updated. API:{apiName} called having isViaWebhook:{isViaWebhook}. Error: {err}",
13
13
 
14
14
  "EXECUTION_FAILED": "API - {apiName} failed to execute. Error:{err}",
15
+ "INTEGRATIONS_CALLBACK_FAILED": "Error while executing integrations_callback: Error: {err}",
15
16
  "INVALID_PARAM": "Key:{key} passed to API:{apiName} is not of valid type. Got type:{type}, should be:{correctType}",
16
17
  "INVALID_CONTEXT_PASSED": "Context should be of type:object and must contain a mandatory key: id, which is User ID",
18
+ "INVALID_CONTEXT_USER_ID": "user_id under context must be a string value",
17
19
  "INVALID_BUCKETING_SEED": "Invalid bucketingSeed passed, since it can only be a valid string. Removing it from context so that userId is used for decisioning.",
18
20
 
19
21
  "FEATURE_NOT_FOUND": "Feature not found for the key:{featureKey}",
20
22
  "FEATURE_NOT_FOUND_WITH_ID": "Feature not found for the id:{featureId}",
21
- "EVENT_NOT_FOUND": "Event:{eventName} not found in any of the features' metrics",
23
+ "EVENT_NOT_FOUND": "Event:{eventName} not found in any of the features' metrics, please ensure event API name is being used correctly",
22
24
 
23
25
  "ERROR_READING_STORED_DATA_IN_STORAGE": "Error reading data from storage. Error:{err}",
24
26
  "ERROR_STORING_DATA_IN_STORAGE": "Key:{featureKey} is not valid. Unable to store data into storage",
@@ -14,6 +14,7 @@
14
14
 
15
15
 
16
16
  from typing import Callable, Dict, Any, Optional
17
+ from ..packages.logger.core.log_manager import LogManager
17
18
 
18
19
 
19
20
  class HooksManager:
@@ -36,7 +37,15 @@ class HooksManager:
36
37
  :param properties: A dictionary of properties to pass to the callback.
37
38
  """
38
39
  if self.is_callback_function and self.callback:
39
- self.callback(properties)
40
+ try:
41
+ self.callback(properties)
42
+ except Exception as err:
43
+ LogManager.get_instance().error_log(
44
+ "INTEGRATIONS_CALLBACK_FAILED",
45
+ data={"err": str(err)},
46
+ debug_data={"an": properties.get("api")},
47
+ should_send_log_to_vwo=False,
48
+ )
40
49
 
41
50
  def set(self, properties: Dict[str, Any]) -> None:
42
51
  """
@@ -27,6 +27,69 @@ import math
27
27
  from ..models.user.context_model import ContextModel
28
28
 
29
29
 
30
+ def _resolve_feature_rule_key(
31
+ campaign: CampaignModel, feature_key: Optional[str] = None
32
+ ) -> Optional[str]:
33
+ """
34
+ Resolves ``{featureKey}_{ruleKey}`` when rules share a parent campaign key.
35
+
36
+ Args:
37
+ campaign (CampaignModel): The campaign containing the rule key.
38
+ feature_key (Optional[str]): Feature key; inferred from campaign key if omitted.
39
+
40
+ Returns:
41
+ Optional[str]: Resolved rule key, or ``None`` if rule key is missing.
42
+ """
43
+ if not campaign.get_rule_key():
44
+ return None
45
+ resolved_feature_key = feature_key
46
+ if not resolved_feature_key and campaign.get_key():
47
+ resolved_feature_key = campaign.get_key().rsplit("_", 1)[0]
48
+ if resolved_feature_key:
49
+ return f"{resolved_feature_key}_{campaign.get_rule_key()}"
50
+ return None
51
+
52
+
53
+ def get_experiment_key(
54
+ campaign: CampaignModel, feature_key: Optional[str] = None
55
+ ) -> str:
56
+ """
57
+ Returns the experiment key for integrations callbacks and storage.
58
+
59
+ Args:
60
+ campaign (CampaignModel): The campaign to resolve the key for.
61
+ feature_key (Optional[str]): Feature key for personalize rules.
62
+
63
+ Returns:
64
+ str: ``{featureKey}_{ruleKey}`` for personalize rules; otherwise campaign key.
65
+ """
66
+ if campaign.get_type() == CampaignTypeEnum.PERSONALIZE.value:
67
+ rule_key = _resolve_feature_rule_key(campaign, feature_key)
68
+ if rule_key:
69
+ return rule_key
70
+ return campaign.get_key()
71
+
72
+
73
+ def get_rollout_key(
74
+ campaign: CampaignModel, feature_key: Optional[str] = None
75
+ ) -> str:
76
+ """
77
+ Returns the rollout key for integrations callbacks and storage.
78
+
79
+ Args:
80
+ campaign (CampaignModel): The campaign to resolve the key for.
81
+ feature_key (Optional[str]): Feature key for rollout rules.
82
+
83
+ Returns:
84
+ str: ``{featureKey}_{ruleKey}`` for rollout rules; otherwise campaign key.
85
+ """
86
+ if campaign.get_type() == CampaignTypeEnum.ROLLOUT.value:
87
+ rule_key = _resolve_feature_rule_key(campaign, feature_key)
88
+ if rule_key:
89
+ return rule_key
90
+ return campaign.get_key()
91
+
92
+
30
93
  def set_variation_allocation(campaign: CampaignModel) -> None:
31
94
  """
32
95
  Allocates traffic ranges to variations within a campaign.
@@ -176,6 +239,24 @@ def get_variation_from_campaign_key(
176
239
  if variation:
177
240
  return variation
178
241
 
242
+ for feature in settings.get_features() or []:
243
+ feature_key = feature.get_key()
244
+ for linked_campaign in feature.get_rules_linked_campaign() or []:
245
+ if (
246
+ get_experiment_key(linked_campaign, feature_key) == campaign_key
247
+ or get_rollout_key(linked_campaign, feature_key) == campaign_key
248
+ ):
249
+ variation = next(
250
+ (
251
+ v
252
+ for v in linked_campaign.get_variations()
253
+ if v.get_id() == variation_id
254
+ ),
255
+ None,
256
+ )
257
+ if variation:
258
+ return variation
259
+
179
260
  return None
180
261
 
181
262
 
@@ -29,6 +29,8 @@ from ..utils.campaign_util import (
29
29
  get_bucketing_seed,
30
30
  get_campaign_ids_from_feature_key,
31
31
  get_campaigns_by_group_id,
32
+ get_experiment_key,
33
+ get_rollout_key,
32
34
  get_feature_keys_from_campaign_ids,
33
35
  set_campaign_allocation,
34
36
  get_variation_from_campaign_key,
@@ -207,7 +209,7 @@ def _is_rollout_rule_for_feature_passed(
207
209
  if isinstance(variation, VariationModel) and not None:
208
210
  evaluated_feature_map[feature.get_key()] = {
209
211
  "rolloutId": rule.get_id(),
210
- "rolloutKey": rule.get_key(),
212
+ "rolloutKey": get_rollout_key(rule, feature.get_key()),
211
213
  "rolloutVariationId": rule.get_variations()[0].get_id(),
212
214
  }
213
215
  return True
@@ -241,7 +243,8 @@ def _get_eligible_campaigns(
241
243
  )
242
244
 
243
245
  if stored_data and stored_data.get("experimentVariationId"):
244
- if stored_data.get("experimentKey") == campaign.get_key():
246
+ campaign_experiment_key = get_experiment_key(campaign, feature_key)
247
+ if stored_data.get("experimentKey") == campaign_experiment_key:
245
248
  variation = get_variation_from_campaign_key(
246
249
  settings,
247
250
  stored_data["experimentKey"],
@@ -261,7 +264,8 @@ def _get_eligible_campaigns(
261
264
  )
262
265
  )
263
266
  if not any(
264
- item.get_key() == campaign.get_key()
267
+ get_experiment_key(item, feature_key)
268
+ == campaign_experiment_key
265
269
  for item in eligible_campaigns_with_storage
266
270
  ):
267
271
  eligible_campaigns_with_storage.append(
@@ -428,7 +432,7 @@ def _normalize_weights_and_find_winning_campaign(
428
432
  "featureKey": Constants.VWO_META_MEG_KEY + str(group_id),
429
433
  "context": context,
430
434
  "experimentId": winner_campaign.get_id(),
431
- "experimentKey": winner_campaign.get_key(),
435
+ "experimentKey": get_experiment_key(winner_campaign),
432
436
  "experimentVariationId": (
433
437
  winner_campaign.get_variations()[0].get_id()
434
438
  if winner_campaign.get_type() == CampaignTypeEnum.PERSONALIZE.value
@@ -538,7 +542,7 @@ def _get_campaign_using_advanced_algo(
538
542
  "featureKey": Constants.VWO_META_MEG_KEY + str(group_id),
539
543
  "context": context,
540
544
  "experimentId": winner_campaign.get_id(),
541
- "experimentKey": winner_campaign.get_key(),
545
+ "experimentKey": get_experiment_key(winner_campaign),
542
546
  "experimentVariationId": (
543
547
  winner_campaign.get_variations()[0].get_id()
544
548
  if winner_campaign.get_type() == CampaignTypeEnum.PERSONALIZE.value
@@ -19,6 +19,7 @@ from ..models.campaign.feature_model import FeatureModel
19
19
  from ..models.user.context_model import ContextModel
20
20
  from ..utils.data_type_util import is_object
21
21
  from ..utils.decision_util import check_whitelisting_and_pre_seg
22
+ from ..utils.campaign_util import get_experiment_key
22
23
  from ..services.storage_service import StorageService
23
24
  from ..utils.network_util import get_track_user_payload_data
24
25
  from typing import Dict
@@ -74,7 +75,7 @@ def evaluate_rule(
74
75
  decision.update(
75
76
  {
76
77
  "experimentId": campaign.get_id(),
77
- "experimentKey": campaign.get_key(),
78
+ "experimentKey": get_experiment_key(campaign, feature.get_key()),
78
79
  "experimentVariationId": whitelisted_object["variationId"],
79
80
  }
80
81
  )
@@ -87,6 +87,7 @@ class WingifyClient:
87
87
  LogManager.get_instance().debug(
88
88
  debug_messages.get("API_CALLED").format(apiName=api_name)
89
89
  )
90
+ self._validate_context(context, api_name)
90
91
  # get uuid from context
91
92
  uuid = self._get_uuid_from_context(context, api_name)
92
93
  except Exception as err:
@@ -118,13 +119,6 @@ class WingifyClient:
118
119
  )
119
120
  raise ValueError("Invalid Settings")
120
121
 
121
- # Validate user ID is present in context
122
- if not context or "id" not in context:
123
- LogManager.get_instance().error(
124
- error_messages.get("INVALID_CONTEXT_PASSED")
125
- )
126
- raise ValueError("Invalid context")
127
-
128
122
  context_copy = context.copy()
129
123
  context_copy["uuid"] = uuid
130
124
  if "bucketingSeed" in context:
@@ -207,13 +201,8 @@ class WingifyClient:
207
201
  )
208
202
  raise ValueError("Invalid Settings")
209
203
 
210
- # Validate user ID is present in context
211
- if not context or "id" not in context:
212
- LogManager.get_instance().error(
213
- error_messages.get("INVALID_CONTEXT_PASSED")
214
- )
215
- raise ValueError("Invalid context")
216
-
204
+ self._validate_context(context, api_name)
205
+
217
206
  context_copy = context.copy()
218
207
  context_copy["uuid"] = self._get_uuid_from_context(context, api_name)
219
208
  context_model = ContextModel(context_copy)
@@ -343,12 +332,8 @@ class WingifyClient:
343
332
  )
344
333
  raise ValueError("Invalid Settings")
345
334
 
346
- if not user_context or "id" not in user_context:
347
- LogManager.get_instance().error(
348
- error_messages.get("INVALID_CONTEXT_PASSED")
349
- )
350
- raise ValueError("Invalid context")
351
-
335
+ self._validate_context(user_context, api_name)
336
+
352
337
  context_copy = user_context.copy()
353
338
  context_copy["uuid"] = self._get_uuid_from_context(user_context, api_name)
354
339
  context_model = ContextModel(context_copy)
@@ -491,6 +476,25 @@ class WingifyClient:
491
476
  LogManager.get_instance().error_log("EXECUTION_FAILED", data={"apiName": api_name, "err": str(err)}, debug_data={"an": ApiEnum.SET_ALIAS.value})
492
477
  return False
493
478
 
479
+ def _validate_context(self, context: Dict, api_name: str) -> None:
480
+ """
481
+ Validates that context contains a string user ID.
482
+
483
+ :param context: The context object passed to an API.
484
+ :param api_name: The name of the API calling this method.
485
+ """
486
+ if not context or not is_object(context) or "id" not in context:
487
+ LogManager.get_instance().error(
488
+ error_messages.get("INVALID_CONTEXT_PASSED")
489
+ )
490
+ raise ValueError("Invalid context")
491
+
492
+ if not isinstance(context.get("id"), str):
493
+ LogManager.get_instance().error(
494
+ error_messages.get("INVALID_CONTEXT_USER_ID")
495
+ )
496
+ raise ValueError("user_id under context must be a string value")
497
+
494
498
  def _get_uuid_from_context(self, context: Dict, api_name: str) -> str:
495
499
  """
496
500
  Gets the UUID from the context.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wingify-fme-python-sdk
3
- Version: 1.60.0
3
+ Version: 1.61.0
4
4
  Summary: Wingify Feature Management and Experimentation SDK for Python
5
5
  Home-page: https://github.com/wingify/vwo-fme-python-sdk
6
6
  Author: Wingify