kameleoon-client-python 2.3.0__tar.gz → 3.0.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 (103) hide show
  1. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/PKG-INFO +7 -5
  2. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/README.md +6 -4
  3. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/__init__.py +2 -1
  4. kameleoon-client-python-3.0.0/kameleoon/configuration/data_file.py +63 -0
  5. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/feature_flag.py +1 -0
  6. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/rule.py +5 -10
  7. kameleoon-client-python-3.0.0/kameleoon/configuration/rule_type.py +17 -0
  8. kameleoon-client-python-3.0.0/kameleoon/configuration/settings.py +28 -0
  9. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/variation_by_exposition.py +2 -2
  10. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/browser.py +22 -13
  11. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/conversion.py +27 -10
  12. kameleoon-client-python-3.0.0/kameleoon/data/custom_data.py +58 -0
  13. kameleoon-client-python-3.0.0/kameleoon/data/data.py +32 -0
  14. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/device.py +17 -11
  15. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/page_view.py +29 -9
  16. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/user_agent.py +10 -4
  17. kameleoon-client-python-3.0.0/kameleoon/defaults.py +9 -0
  18. kameleoon-client-python-3.0.0/kameleoon/exceptions.py +87 -0
  19. kameleoon-client-python-3.0.0/kameleoon/helpers/functions.py +68 -0
  20. kameleoon-client-python-3.0.0/kameleoon/helpers/multi_threading.py +118 -0
  21. kameleoon-client-python-3.0.0/kameleoon/helpers/nonce.py +12 -0
  22. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/helpers/repeat_timer.py +3 -1
  23. kameleoon-client-python-3.0.0/kameleoon/helpers/scheduler.py +67 -0
  24. kameleoon-client-python-3.0.0/kameleoon/helpers/visitor_code.py +26 -0
  25. kameleoon-client-python-3.0.0/kameleoon/kameleoon_client.py +1011 -0
  26. kameleoon-client-python-3.0.0/kameleoon/kameleoon_client_config.py +178 -0
  27. kameleoon-client-python-3.0.0/kameleoon/kameleoon_client_factory.py +57 -0
  28. kameleoon-client-python-3.0.0/kameleoon/middleware.py +40 -0
  29. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/real_time/real_time_configuration_service.py +3 -8
  30. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/sdk_version.py +1 -1
  31. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/browser_condition.py +5 -8
  32. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/conversion_condition.py +9 -9
  33. kameleoon-client-python-3.0.0/kameleoon/targeting/conditions/custom_datum.py +92 -0
  34. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/device_condition.py +6 -6
  35. kameleoon-client-python-3.0.0/kameleoon/targeting/conditions/exclusive_experiment.py +26 -0
  36. kameleoon-client-python-3.0.0/kameleoon/targeting/conditions/page_title_condition.py +20 -0
  37. kameleoon-client-python-3.0.0/kameleoon/targeting/conditions/page_url_condition.py +23 -0
  38. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/sdk_language_condition.py +1 -2
  39. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/string_value_condition.py +16 -17
  40. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/target_experiment.py +10 -11
  41. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/targeting_condition.py +3 -11
  42. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/unknown_condition.py +2 -1
  43. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon_client_python.egg-info/PKG-INFO +7 -5
  44. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon_client_python.egg-info/SOURCES.txt +8 -5
  45. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon_client_python.egg-info/requires.txt +18 -18
  46. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/apps.py +5 -5
  47. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/views.py +21 -20
  48. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/proj/wsgi.py +6 -2
  49. kameleoon-client-python-3.0.0/tests/resources/config.yml +4 -0
  50. kameleoon-client-python-2.3.0/kameleoon/client.py +0 -1374
  51. kameleoon-client-python-2.3.0/kameleoon/client_configuration.py +0 -26
  52. kameleoon-client-python-2.3.0/kameleoon/configuration/settings.py +0 -16
  53. kameleoon-client-python-2.3.0/kameleoon/data/custom_data.py +0 -60
  54. kameleoon-client-python-2.3.0/kameleoon/data/data.py +0 -35
  55. kameleoon-client-python-2.3.0/kameleoon/defaults.py +0 -41
  56. kameleoon-client-python-2.3.0/kameleoon/exceptions.py +0 -112
  57. kameleoon-client-python-2.3.0/kameleoon/helpers/config.py +0 -28
  58. kameleoon-client-python-2.3.0/kameleoon/helpers/functions.py +0 -102
  59. kameleoon-client-python-2.3.0/kameleoon/helpers/multi_threading.py +0 -78
  60. kameleoon-client-python-2.3.0/kameleoon/middleware.py +0 -43
  61. kameleoon-client-python-2.3.0/kameleoon/storage/varation_storage.py +0 -61
  62. kameleoon-client-python-2.3.0/kameleoon/storage/visitor_variation.py +0 -22
  63. kameleoon-client-python-2.3.0/kameleoon/targeting/conditions/custom_datum.py +0 -83
  64. kameleoon-client-python-2.3.0/kameleoon/targeting/conditions/exclusive_experiment.py +0 -27
  65. kameleoon-client-python-2.3.0/kameleoon/targeting/conditions/page_title_condition.py +0 -16
  66. kameleoon-client-python-2.3.0/kameleoon/targeting/conditions/page_url_condition.py +0 -16
  67. kameleoon-client-python-2.3.0/tests/resources/config.yml +0 -4
  68. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/MANIFEST.in +0 -0
  69. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/__init__.py +0 -0
  70. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/variable.py +0 -0
  71. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/variation.py +0 -0
  72. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/__init__.py +0 -0
  73. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/helpers/__init__.py +0 -0
  74. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/helpers/logger.py +0 -0
  75. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/real_time/__init__.py +0 -0
  76. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/real_time/real_time_event.py +0 -0
  77. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/storage/__init__.py +0 -0
  78. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/storage/cache.py +0 -0
  79. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/storage/cache_factory.py +0 -0
  80. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/storage/cache_factory_impl.py +0 -0
  81. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/storage/cache_impl.py +0 -0
  82. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/__init__.py +0 -0
  83. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/__init__.py +0 -0
  84. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/constants.py +0 -0
  85. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
  86. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/models.py +0 -0
  87. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/tree_builder.py +0 -0
  88. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/tree_condition_factory.py +0 -0
  89. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
  90. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
  91. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/setup.cfg +0 -0
  92. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/setup.py +0 -0
  93. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/__init__.py +0 -0
  94. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/__init__.py +0 -0
  95. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
  96. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/migrations/__init__.py +0 -0
  97. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
  98. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
  99. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/manage.py +0 -0
  100. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/proj/__init__.py +0 -0
  101. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/proj/asgi.py +0 -0
  102. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/proj/settings.py +0 -0
  103. {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/proj/urls.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kameleoon-client-python
3
- Version: 2.3.0
3
+ Version: 3.0.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
@@ -92,7 +92,7 @@ variation (most likely a returning visitor that has already been exposed to the
92
92
  then it will return the previous variation assigned for the given experiment.
93
93
 
94
94
  ```python
95
- visitor_code = kameleoon_client.get_visitor_code(request.COOKIES)
95
+ visitor_code = kameleoon_client.get_visitor_code(cookies_readonly=request.COOKIES)
96
96
  variation_id = 0
97
97
  try:
98
98
  variation_id = kameleoon_client.trigger_experiment(visitor_code, 135471)
@@ -168,9 +168,11 @@ The following example shows a sample django application wrapped by the Kameleoon
168
168
  import uuid
169
169
 
170
170
  from django.core.wsgi import get_wsgi_application
171
+ from django.apps import apps
172
+ kameleoon_app = apps.get_app_config("kameleoon_app")
171
173
 
172
174
  from kameleoon import KameleoonWSGIMiddleware
173
- application = KameleoonWSGIMiddleware(get_wsgi_application(), 'example.com', uuid.uuid4().hex)
175
+ application = KameleoonWSGIMiddleware(get_wsgi_application(), kameleoon_app.kameleoon_client, uuid.uuid4().hex)
174
176
  ```
175
177
 
176
178
  You can then access the Kameleoon client in your views:
@@ -196,7 +198,7 @@ kameleoon_app = apps.get_app_config('your_app')
196
198
  client = kameleoon_app.kameleoon_client
197
199
 
198
200
  def view(request):
199
- visitor_code = client.get_visitor_code(request.COOKIES)
201
+ visitor_code = client.get_visitor_code(cookies_readonly=request.COOKIES)
200
202
  variation_id = 0
201
203
  try:
202
204
  variation_id = client.trigger_experiment(visitor_code, 135471)
@@ -248,7 +250,7 @@ You need to pass the visitor_code and goal_id parameters so we can correctly
248
250
  track conversions for this particular visitor.
249
251
 
250
252
  ```python
251
- visitor_code = client.get_visitor_code(request.COOKIES)
253
+ visitor_code = client.get_visitor_code(cookies_readonly=request.COOKIES)
252
254
  goal_id = 83023
253
255
  client.track_conversion(visitor_code, goal_id )
254
256
  ```
@@ -69,7 +69,7 @@ variation (most likely a returning visitor that has already been exposed to the
69
69
  then it will return the previous variation assigned for the given experiment.
70
70
 
71
71
  ```python
72
- visitor_code = kameleoon_client.get_visitor_code(request.COOKIES)
72
+ visitor_code = kameleoon_client.get_visitor_code(cookies_readonly=request.COOKIES)
73
73
  variation_id = 0
74
74
  try:
75
75
  variation_id = kameleoon_client.trigger_experiment(visitor_code, 135471)
@@ -145,9 +145,11 @@ The following example shows a sample django application wrapped by the Kameleoon
145
145
  import uuid
146
146
 
147
147
  from django.core.wsgi import get_wsgi_application
148
+ from django.apps import apps
149
+ kameleoon_app = apps.get_app_config("kameleoon_app")
148
150
 
149
151
  from kameleoon import KameleoonWSGIMiddleware
150
- application = KameleoonWSGIMiddleware(get_wsgi_application(), 'example.com', uuid.uuid4().hex)
152
+ application = KameleoonWSGIMiddleware(get_wsgi_application(), kameleoon_app.kameleoon_client, uuid.uuid4().hex)
151
153
  ```
152
154
 
153
155
  You can then access the Kameleoon client in your views:
@@ -173,7 +175,7 @@ kameleoon_app = apps.get_app_config('your_app')
173
175
  client = kameleoon_app.kameleoon_client
174
176
 
175
177
  def view(request):
176
- visitor_code = client.get_visitor_code(request.COOKIES)
178
+ visitor_code = client.get_visitor_code(cookies_readonly=request.COOKIES)
177
179
  variation_id = 0
178
180
  try:
179
181
  variation_id = client.trigger_experiment(visitor_code, 135471)
@@ -225,7 +227,7 @@ You need to pass the visitor_code and goal_id parameters so we can correctly
225
227
  track conversions for this particular visitor.
226
228
 
227
229
  ```python
228
- visitor_code = client.get_visitor_code(request.COOKIES)
230
+ visitor_code = client.get_visitor_code(cookies_readonly=request.COOKIES)
229
231
  goal_id = 83023
230
232
  client.track_conversion(visitor_code, goal_id )
231
233
  ```
@@ -1,5 +1,6 @@
1
1
  """Kameleoon PYTHON SDK"""
2
2
 
3
3
  from .sdk_version import __version__ # noqa: F401
4
- from .client import KameleoonClient # noqa: F401
4
+ from .kameleoon_client import KameleoonClient # noqa: F401
5
+ from .kameleoon_client_config import KameleoonClientConfig # noqa: F401
5
6
  from .middleware import KameleoonWSGIMiddleware # noqa: F401
@@ -0,0 +1,63 @@
1
+ """Kameleoon Configuration"""
2
+
3
+ from typing import Any, Dict, Optional
4
+ from kameleoon.configuration.feature_flag import FeatureFlag
5
+ from kameleoon.configuration.settings import Settings
6
+ from kameleoon.exceptions import FeatureNotFound, FeatureEnvironmentDisabled
7
+
8
+
9
+ class DataFile:
10
+ """`DataFile` is a container for an actual client-configuration data"""
11
+
12
+ @staticmethod
13
+ def default(environment: Optional[str]) -> "DataFile":
14
+ """Creates new instance of `DataFile` initialized with default values"""
15
+ return DataFile(environment, Settings(), {})
16
+
17
+ @staticmethod
18
+ def from_json(environment: Optional[str], configuration: Dict[str, Any]) -> "DataFile":
19
+ """Creates new instance of `DataFile` initialized from the specified configuration JSON"""
20
+ settings = Settings(configuration.get("configuration"))
21
+ feature_flags = {
22
+ (feature_flag := FeatureFlag(jobj)).feature_key: feature_flag
23
+ for jobj in configuration.get("featureFlags") or []
24
+ }
25
+ return DataFile(environment, settings, feature_flags)
26
+
27
+ def __init__(self, environment: Optional[str], settings: Settings, feature_flags: Dict[str, FeatureFlag]) -> None:
28
+ self.__environment = environment # pylint: disable=W0238
29
+ self.__settings = settings
30
+ self.__feature_flags: Dict[str, FeatureFlag] = feature_flags
31
+ self.__has_any_targeted_delivery_rule = any(
32
+ rule.is_targeted_delivery
33
+ for ff in self.__feature_flags.values()
34
+ if ff.environment_enabled
35
+ for rule in ff.rules
36
+ )
37
+
38
+ @property
39
+ def settings(self) -> Settings:
40
+ """Returns settings"""
41
+ return self.__settings
42
+
43
+ @property
44
+ def feature_flags(self) -> Dict[str, FeatureFlag]:
45
+ """Returns dictionary of all feature flags stored by feature keys"""
46
+ return self.__feature_flags
47
+
48
+ @property
49
+ def has_any_targeted_delivery_rule(self) -> bool:
50
+ """Returns `True` if has a feature flag with a rule of the targeted delivery type, otherwise returns `False`"""
51
+ return self.__has_any_targeted_delivery_rule
52
+
53
+ def get_feature_flag(self, feature_key: str) -> FeatureFlag:
54
+ """
55
+ Returns feature flag with the specified feature key if it exists,
56
+ otherwise raises `FeatureNotFound` exception.
57
+ """
58
+ feature_flag = self.__feature_flags.get(feature_key)
59
+ if feature_flag is None:
60
+ raise FeatureNotFound(feature_key)
61
+ if not feature_flag.environment_enabled:
62
+ raise FeatureEnvironmentDisabled(feature_key, self.__environment)
63
+ return feature_flag
@@ -23,6 +23,7 @@ class FeatureFlag:
23
23
  self.variations: List[Variation] = Variation.from_array(
24
24
  dict_json.get("variations", [])
25
25
  )
26
+ self.environment_enabled = dict_json.get("environmentEnabled", False)
26
27
  self.rules: List[Rule] = Rule.from_array(dict_json.get("rules", []))
27
28
 
28
29
  def get_variation(self, key: str) -> Optional[Variation]:
@@ -1,7 +1,7 @@
1
1
  """Kameleoon Configuration"""
2
2
 
3
- from enum import Enum
4
3
  from typing import Any, List, Dict, Optional
4
+ from kameleoon.configuration.rule_type import RuleType, rule_type_from_literal
5
5
  from kameleoon.configuration.variation_by_exposition import VariationByExposition
6
6
  from kameleoon.targeting.models import Segment
7
7
 
@@ -11,12 +11,6 @@ class Rule:
11
11
  Rule is used for saving rule of feature flags (v2) with rules
12
12
  """
13
13
 
14
- class Type(Enum):
15
- """Possible types of rules"""
16
-
17
- EXPERIMENTATION = "EXPERIMENTATION"
18
- TARGETED_DELIVERY = "TARGETED_DELIVERY"
19
-
20
14
  @staticmethod
21
15
  def from_array(array: List[Dict[str, Any]]) -> List["Rule"]:
22
16
  """Create a list of Rules from the json array"""
@@ -26,7 +20,8 @@ class Rule:
26
20
  def __init__(self, dict_json: Dict[str, Any]):
27
21
  self.id_: int = dict_json["id"]
28
22
  self.order: int = dict_json.get("order", 0)
29
- self.type: str = dict_json.get("type", "")
23
+ type_literal: str = dict_json.get("type", "")
24
+ self.type = rule_type_from_literal(type_literal)
30
25
  self.exposition: float = dict_json.get("exposition", 0.0)
31
26
  self.experiment_id: int = dict_json.get("experimentId", 0)
32
27
  self.respool_time: Optional[int] = dict_json.get("respoolTime", None)
@@ -50,10 +45,10 @@ class Rule:
50
45
  def is_experimentation(self) -> bool:
51
46
  """Return `true` if rule is `experimentation` type"""
52
47
 
53
- return self.type == Rule.Type.EXPERIMENTATION.value
48
+ return self.type == RuleType.EXPERIMENTATION
54
49
 
55
50
  @property
56
51
  def is_targeted_delivery(self) -> bool:
57
52
  """Return `true` if rule is `targeted delivery` type"""
58
53
 
59
- return self.type == Rule.Type.TARGETED_DELIVERY.value
54
+ return self.type == RuleType.TARGETED_DELIVERY
@@ -0,0 +1,17 @@
1
+ """Kameleoon Configuration"""
2
+
3
+ from enum import Enum
4
+ from kameleoon.helpers.functions import enum_from_literal
5
+
6
+
7
+ class RuleType(Enum):
8
+ """Possible types of rules"""
9
+
10
+ UNKNOWN: None = None
11
+ EXPERIMENTATION = "EXPERIMENTATION"
12
+ TARGETED_DELIVERY = "TARGETED_DELIVERY"
13
+
14
+
15
+ def rule_type_from_literal(literal: str) -> RuleType:
16
+ """Converts rule type literal to RuleType value"""
17
+ return enum_from_literal(literal, RuleType, RuleType.UNKNOWN)
@@ -0,0 +1,28 @@
1
+ """Kameleoon Configuration"""
2
+
3
+ from typing import Any, Dict, Optional
4
+
5
+
6
+ class Settings:
7
+ """
8
+ KameleoonConfigurationSettings is used for saving setting's parameters, e.g
9
+ state of real time update for site code and etc
10
+ """
11
+
12
+ _CONSENT_TYPE_REQUIRED = "REQUIRED"
13
+
14
+ # pylint: disable=R0903
15
+ def __init__(self, configuration: Optional[Dict[str, Any]] = None):
16
+ self.__real_time_update: bool = bool(configuration and configuration.get("realTimeUpdate"))
17
+ self.__is_consent_required = (configuration is not None) and \
18
+ (configuration.get("consentType") == self._CONSENT_TYPE_REQUIRED)
19
+
20
+ @property
21
+ def real_time_update(self) -> bool:
22
+ """Returns streaming mode flag state"""
23
+ return self.__real_time_update
24
+
25
+ @property
26
+ def is_consent_required(self) -> bool:
27
+ """Returns consent required flag state"""
28
+ return self.__is_consent_required
@@ -15,5 +15,5 @@ class VariationByExposition:
15
15
 
16
16
  def __init__(self, dict_json: Dict[str, Any]):
17
17
  self.variation_key: str = dict_json.get("variationKey", "")
18
- self.variation_id: Optional[int] = dict_json.get("variationId", "")
19
- self.exposition: int = dict_json.get("exposition", "")
18
+ self.variation_id: Optional[int] = dict_json.get("variationId")
19
+ self.exposition: float = dict_json.get("exposition", 0.0)
@@ -3,7 +3,7 @@
3
3
  from enum import IntEnum
4
4
  from typing import Optional
5
5
  from kameleoon.data.data import Data, DataType
6
- from kameleoon.exceptions import KameleoonException
6
+ from kameleoon.network.sendable import DuplicationUnsafeSendableBase
7
7
  from kameleoon.network.query_builder import QueryBuilder, QueryParam, QueryParams
8
8
 
9
9
 
@@ -18,7 +18,7 @@ class BrowserType(IntEnum):
18
18
  OTHER: int = 5
19
19
 
20
20
 
21
- class Browser(Data):
21
+ class Browser(Data, DuplicationUnsafeSendableBase):
22
22
  """Browser data"""
23
23
 
24
24
  EVENT_TYPE = "staticData"
@@ -34,18 +34,27 @@ class Browser(Data):
34
34
  kameleoon_client.add_data(visitor_code, Browser(BrowserType.CHROME))
35
35
  """
36
36
  super().__init__()
37
- self.browser_type = browser_type
38
- self.version = version
39
- self._instance: DataType = DataType.BROWSER
40
-
41
- def obtain_full_post_text_line(self) -> str:
42
- if self.browser_type < 0:
43
- raise KameleoonException("Browser not recognized")
44
- query_builder = QueryBuilder(
37
+ self.__browser_type = browser_type
38
+ self.__version = version
39
+
40
+ @property
41
+ def browser_type(self) -> BrowserType:
42
+ """Returns browser type"""
43
+ return self.__browser_type
44
+
45
+ @property
46
+ def version(self) -> Optional[float]:
47
+ """Returns version"""
48
+ return self.__version
49
+
50
+ @property
51
+ def data_type(self) -> DataType:
52
+ return DataType.BROWSER
53
+
54
+ def _add_query_params(self, qb: QueryBuilder) -> None:
55
+ qb.extend(
45
56
  QueryParam(QueryParams.EVENT_TYPE, self.EVENT_TYPE),
46
57
  QueryParam(QueryParams.BROWSER_INDEX, str(self.browser_type.value)),
47
- QueryParam(QueryParams.NONCE, self._nonce),
48
58
  )
49
59
  if self.version:
50
- query_builder.append(QueryParam(QueryParams.BROWSER_VERSION, str(self.version)))
51
- return str(query_builder)
60
+ qb.append(QueryParam(QueryParams.BROWSER_VERSION, str(self.version)))
@@ -1,11 +1,12 @@
1
1
  # pylint: disable=duplicate-code
2
2
  """Conversion data"""
3
3
  from kameleoon.data.data import Data, DataType
4
+ from kameleoon.network.sendable import DuplicationSafeSendableBase
4
5
  from kameleoon.network.query_builder import QueryBuilder, QueryParam, QueryParams
5
6
 
6
7
 
7
8
  # pylint: disable=R0801
8
- class Conversion(Data):
9
+ class Conversion(Data, DuplicationSafeSendableBase):
9
10
  """Conversion is used for tracking visitors conversions"""
10
11
 
11
12
  EVENT_TYPE = "conversion"
@@ -27,19 +28,35 @@ class Conversion(Data):
27
28
 
28
29
  """
29
30
  super().__init__()
30
- self.goal_id = goal_id
31
- self.revenue = revenue
32
- self.negative = negative
33
- self._instance: DataType = DataType.CONVERSION
34
-
35
- def obtain_full_post_text_line(self) -> str:
31
+ self.__goal_id = goal_id
32
+ self.__revenue = revenue
33
+ self.__negative = negative
34
+
35
+ @property
36
+ def goal_id(self) -> int:
37
+ """Returns goal ID"""
38
+ return self.__goal_id
39
+
40
+ @property
41
+ def revenue(self) -> float:
42
+ """Returns revenue"""
43
+ return self.__revenue
44
+
45
+ @property
46
+ def negative(self) -> bool:
47
+ """Returns negative flag state"""
48
+ return self.__negative
49
+
50
+ @property
51
+ def data_type(self) -> DataType:
52
+ return DataType.CONVERSION
53
+
54
+ def _add_query_params(self, qb: QueryBuilder) -> None:
36
55
  # remove query_builder, it's done due due pylint issue with R0801 - duplicate_code,
37
56
  # need to update pylint and return str(QueryBuilder) straightaway
38
- query_builder = QueryBuilder(
57
+ qb.extend(
39
58
  QueryParam(QueryParams.EVENT_TYPE, self.EVENT_TYPE),
40
59
  QueryParam(QueryParams.GOAL_ID, str(self.goal_id)),
41
60
  QueryParam(QueryParams.REVENUE, str(self.revenue)),
42
61
  QueryParam(QueryParams.NEGATIVE, "true" if self.negative else "false"),
43
- QueryParam(QueryParams.NONCE, self._nonce),
44
62
  )
45
- return str(query_builder)
@@ -0,0 +1,58 @@
1
+ """Custom data"""
2
+
3
+ import json
4
+ from typing import Tuple
5
+ from kameleoon.data.data import Data, DataType
6
+ from kameleoon.network.sendable import DuplicationUnsafeSendableBase
7
+ from kameleoon.network.query_builder import QueryBuilder, QueryParam, QueryParams
8
+
9
+
10
+ class CustomData(Data, DuplicationUnsafeSendableBase):
11
+ """Custom data"""
12
+
13
+ EVENT_TYPE = "customData"
14
+
15
+ def __init__(self, id: int, *args: str) -> None:
16
+ """
17
+ :param id: Index / ID of the custom data to be stored. This field is mandatory.
18
+ :type id: int
19
+ :param `*args`: Values of the custom data to be stored. This field is optional.
20
+ :type `*args`: str
21
+
22
+ Example:
23
+
24
+ .. code-block:: python3
25
+
26
+ kameleoon_client.add_data(visitor_code, CustomData(123, "some-value"))
27
+ """
28
+ # pylint: disable=invalid-name,redefined-builtin
29
+ super().__init__()
30
+ # pylint: disable=W0511
31
+ self.__id = id
32
+ self.__values = args
33
+
34
+ @property
35
+ def id(self) -> int: # pylint: disable=C0103
36
+ """Returns ID"""
37
+ return self.__id
38
+
39
+ @property
40
+ def values(self) -> Tuple[str, ...]:
41
+ """Stored values."""
42
+ return self.__values
43
+
44
+ @property
45
+ def data_type(self) -> DataType:
46
+ return DataType.CUSTOM_DATA
47
+
48
+ def encode_query(self) -> str:
49
+ return super().encode_query() if len(self.__values) > 0 else ""
50
+
51
+ def _add_query_params(self, qb: QueryBuilder) -> None:
52
+ str_values = json.dumps({v: 1 for v in self.__values}, separators=(",", ":"))
53
+ qb.extend(
54
+ QueryParam(QueryParams.EVENT_TYPE, self.EVENT_TYPE),
55
+ QueryParam(QueryParams.INDEX, str(self.id)),
56
+ QueryParam(QueryParams.VALUES_COUNT_MAP, str_values),
57
+ QueryParam(QueryParams.OVERWRITE, "true"),
58
+ )
@@ -0,0 +1,32 @@
1
+ """ Kameleoon data module"""
2
+ from enum import IntEnum
3
+ from typing import Any, Dict
4
+
5
+
6
+ class DataType(IntEnum):
7
+ """Data types"""
8
+
9
+ CUSTOM_DATA = 0
10
+ BROWSER = 1
11
+ CONVERSION = 2
12
+ DEVICE = 3
13
+ PAGE_VIEW = 4
14
+ USER_AGENT = 5
15
+ ASSIGNED_VARIATION = 6
16
+
17
+
18
+ class BaseData:
19
+ """Base data class"""
20
+
21
+ @property
22
+ def data_type(self) -> DataType:
23
+ """Returns data type of the instance"""
24
+ raise NotImplementedError
25
+
26
+ def to_dict(self) -> Dict[str, Any]:
27
+ """Convert class instance to dict"""
28
+ return self.__dict__
29
+
30
+
31
+ class Data(BaseData): # pylint: disable=W0223
32
+ """Base external data class"""
@@ -3,6 +3,7 @@
3
3
 
4
4
  from enum import Enum
5
5
  from kameleoon.data.data import Data, DataType
6
+ from kameleoon.network.sendable import DuplicationUnsafeSendableBase
6
7
  from kameleoon.network.query_builder import QueryBuilder, QueryParam, QueryParams
7
8
 
8
9
 
@@ -14,7 +15,7 @@ class DeviceType(Enum):
14
15
  DESKTOP: str = "DESKTOP"
15
16
 
16
17
 
17
- class Device(Data):
18
+ class Device(Data, DuplicationUnsafeSendableBase):
18
19
  """Device data"""
19
20
 
20
21
  EVENT_TYPE = "staticData"
@@ -28,14 +29,19 @@ class Device(Data):
28
29
  kameleoon_client.add_data(visitor_code, Device(DeviceType.PHONE))
29
30
  """
30
31
  super().__init__()
31
- self.device_type = device_type
32
- self._instance: DataType = DataType.DEVICE
33
-
34
- def obtain_full_post_text_line(self) -> str:
35
- return str(
36
- QueryBuilder(
37
- QueryParam(QueryParams.EVENT_TYPE, self.EVENT_TYPE),
38
- QueryParam(QueryParams.DEVICE_TYPE, self.device_type.value),
39
- QueryParam(QueryParams.NONCE, self._nonce),
40
- )
32
+ self.__device_type = device_type
33
+
34
+ @property
35
+ def device_type(self) -> DeviceType:
36
+ """Returns device type"""
37
+ return self.__device_type
38
+
39
+ @property
40
+ def data_type(self) -> DataType:
41
+ return DataType.DEVICE
42
+
43
+ def _add_query_params(self, qb: QueryBuilder) -> None:
44
+ qb.extend(
45
+ QueryParam(QueryParams.EVENT_TYPE, self.EVENT_TYPE),
46
+ QueryParam(QueryParams.DEVICE_TYPE, self.device_type.value),
41
47
  )
@@ -3,10 +3,11 @@
3
3
  import json
4
4
  from typing import List, Optional
5
5
  from kameleoon.data.data import Data, DataType
6
+ from kameleoon.network.sendable import DuplicationSafeSendableBase
6
7
  from kameleoon.network.query_builder import QueryBuilder, QueryParam, QueryParams
7
8
 
8
9
 
9
- class PageView(Data):
10
+ class PageView(Data, DuplicationSafeSendableBase):
10
11
  """Page view"""
11
12
 
12
13
  EVENT_TYPE = "page"
@@ -27,19 +28,38 @@ class PageView(Data):
27
28
  kameleoon_client.add_data(visitor_code, PageView("www.test.com", "test-title"))
28
29
  """
29
30
  super().__init__()
30
- self.url = url
31
- self.title = title
32
- self.referrers = referrers
33
- self._instance: DataType = DataType.PAGE_VIEW
31
+ self.__url = url
32
+ self.__title = title
33
+ self.__referrers = referrers
34
34
 
35
- def obtain_full_post_text_line(self) -> str:
36
- qb = QueryBuilder( # pylint: disable=C0103
35
+ @property
36
+ def url(self) -> str:
37
+ """Returns URL"""
38
+ return self.__url
39
+
40
+ @property
41
+ def title(self) -> str:
42
+ """Returns title"""
43
+ return self.__title
44
+
45
+ @property
46
+ def referrers(self) -> Optional[List[int]]:
47
+ """Returns referrer list"""
48
+ return self.__referrers
49
+
50
+ @property
51
+ def data_type(self) -> DataType:
52
+ return DataType.PAGE_VIEW
53
+
54
+ def encode_query(self) -> str:
55
+ return super().encode_query() if len(self.__url) > 0 else ""
56
+
57
+ def _add_query_params(self, qb: QueryBuilder) -> None:
58
+ qb.extend(
37
59
  QueryParam(QueryParams.EVENT_TYPE, self.EVENT_TYPE),
38
60
  QueryParam(QueryParams.HREF, self.url),
39
61
  QueryParam(QueryParams.TITLE, self.title),
40
- QueryParam(QueryParams.NONCE, self._nonce),
41
62
  )
42
63
  if self.referrers:
43
64
  str_referrers = json.dumps(self.referrers, separators=(",", ":"))
44
65
  qb.append(QueryParam(QueryParams.REFERRERS_INDICES, str_referrers))
45
- return str(qb)
@@ -1,6 +1,6 @@
1
1
  """User Agent data"""
2
2
 
3
- from kameleoon.data.data import Data
3
+ from kameleoon.data.data import Data, DataType
4
4
 
5
5
 
6
6
  # pylint: disable=W0223,W0231
@@ -15,11 +15,17 @@ class UserAgent(Data):
15
15
  .. code-block:: python3
16
16
  kameleoon_client.add_data(visitor_code, UserAgent('TestUserAgent'))
17
17
  """
18
- self.value = value
18
+ super().__init__()
19
+ self.__value = value
19
20
 
20
- def get_value(self) -> str:
21
+ @property
22
+ def value(self) -> str:
21
23
  """
22
24
  return user agent value
23
25
  :return:
24
26
  """
25
- return self.value
27
+ return self.__value
28
+
29
+ @property
30
+ def data_type(self) -> DataType:
31
+ return DataType.USER_AGENT
@@ -0,0 +1,9 @@
1
+ """Default constants"""
2
+
3
+ import os
4
+
5
+ BASE_DIR: str = os.path.dirname((os.path.dirname(__file__)))
6
+
7
+ DEBUG: bool = True
8
+
9
+ MILLISECONDS_IN_SECOND: int = 1000