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.
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/PKG-INFO +7 -5
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/README.md +6 -4
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/__init__.py +2 -1
- kameleoon-client-python-3.0.0/kameleoon/configuration/data_file.py +63 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/feature_flag.py +1 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/rule.py +5 -10
- kameleoon-client-python-3.0.0/kameleoon/configuration/rule_type.py +17 -0
- kameleoon-client-python-3.0.0/kameleoon/configuration/settings.py +28 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/variation_by_exposition.py +2 -2
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/browser.py +22 -13
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/conversion.py +27 -10
- kameleoon-client-python-3.0.0/kameleoon/data/custom_data.py +58 -0
- kameleoon-client-python-3.0.0/kameleoon/data/data.py +32 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/device.py +17 -11
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/page_view.py +29 -9
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/user_agent.py +10 -4
- kameleoon-client-python-3.0.0/kameleoon/defaults.py +9 -0
- kameleoon-client-python-3.0.0/kameleoon/exceptions.py +87 -0
- kameleoon-client-python-3.0.0/kameleoon/helpers/functions.py +68 -0
- kameleoon-client-python-3.0.0/kameleoon/helpers/multi_threading.py +118 -0
- kameleoon-client-python-3.0.0/kameleoon/helpers/nonce.py +12 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/helpers/repeat_timer.py +3 -1
- kameleoon-client-python-3.0.0/kameleoon/helpers/scheduler.py +67 -0
- kameleoon-client-python-3.0.0/kameleoon/helpers/visitor_code.py +26 -0
- kameleoon-client-python-3.0.0/kameleoon/kameleoon_client.py +1011 -0
- kameleoon-client-python-3.0.0/kameleoon/kameleoon_client_config.py +178 -0
- kameleoon-client-python-3.0.0/kameleoon/kameleoon_client_factory.py +57 -0
- kameleoon-client-python-3.0.0/kameleoon/middleware.py +40 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/real_time/real_time_configuration_service.py +3 -8
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/sdk_version.py +1 -1
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/browser_condition.py +5 -8
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/conversion_condition.py +9 -9
- kameleoon-client-python-3.0.0/kameleoon/targeting/conditions/custom_datum.py +92 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/device_condition.py +6 -6
- kameleoon-client-python-3.0.0/kameleoon/targeting/conditions/exclusive_experiment.py +26 -0
- kameleoon-client-python-3.0.0/kameleoon/targeting/conditions/page_title_condition.py +20 -0
- kameleoon-client-python-3.0.0/kameleoon/targeting/conditions/page_url_condition.py +23 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/sdk_language_condition.py +1 -2
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/string_value_condition.py +16 -17
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/target_experiment.py +10 -11
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/targeting_condition.py +3 -11
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/unknown_condition.py +2 -1
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon_client_python.egg-info/PKG-INFO +7 -5
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon_client_python.egg-info/SOURCES.txt +8 -5
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon_client_python.egg-info/requires.txt +18 -18
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/apps.py +5 -5
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/views.py +21 -20
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/proj/wsgi.py +6 -2
- kameleoon-client-python-3.0.0/tests/resources/config.yml +4 -0
- kameleoon-client-python-2.3.0/kameleoon/client.py +0 -1374
- kameleoon-client-python-2.3.0/kameleoon/client_configuration.py +0 -26
- kameleoon-client-python-2.3.0/kameleoon/configuration/settings.py +0 -16
- kameleoon-client-python-2.3.0/kameleoon/data/custom_data.py +0 -60
- kameleoon-client-python-2.3.0/kameleoon/data/data.py +0 -35
- kameleoon-client-python-2.3.0/kameleoon/defaults.py +0 -41
- kameleoon-client-python-2.3.0/kameleoon/exceptions.py +0 -112
- kameleoon-client-python-2.3.0/kameleoon/helpers/config.py +0 -28
- kameleoon-client-python-2.3.0/kameleoon/helpers/functions.py +0 -102
- kameleoon-client-python-2.3.0/kameleoon/helpers/multi_threading.py +0 -78
- kameleoon-client-python-2.3.0/kameleoon/middleware.py +0 -43
- kameleoon-client-python-2.3.0/kameleoon/storage/varation_storage.py +0 -61
- kameleoon-client-python-2.3.0/kameleoon/storage/visitor_variation.py +0 -22
- kameleoon-client-python-2.3.0/kameleoon/targeting/conditions/custom_datum.py +0 -83
- kameleoon-client-python-2.3.0/kameleoon/targeting/conditions/exclusive_experiment.py +0 -27
- kameleoon-client-python-2.3.0/kameleoon/targeting/conditions/page_title_condition.py +0 -16
- kameleoon-client-python-2.3.0/kameleoon/targeting/conditions/page_url_condition.py +0 -16
- kameleoon-client-python-2.3.0/tests/resources/config.yml +0 -4
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/MANIFEST.in +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/__init__.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/variable.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/variation.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/__init__.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/helpers/__init__.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/helpers/logger.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/real_time/__init__.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/real_time/real_time_event.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/storage/__init__.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/storage/cache.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/storage/cache_factory.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/storage/cache_factory_impl.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/storage/cache_impl.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/__init__.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/__init__.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/constants.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/models.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/tree_builder.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/targeting/tree_condition_factory.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/setup.cfg +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/setup.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/__init__.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/__init__.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/migrations/__init__.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/manage.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/proj/__init__.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/proj/asgi.py +0 -0
- {kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/tests/integration/proj/proj/settings.py +0 -0
- {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:
|
|
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(),
|
|
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(),
|
|
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 .
|
|
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]:
|
{kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/configuration/rule.py
RENAMED
|
@@ -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
|
-
|
|
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 ==
|
|
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 ==
|
|
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:
|
|
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.
|
|
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.
|
|
38
|
-
self.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
51
|
-
return str(query_builder)
|
|
60
|
+
qb.append(QueryParam(QueryParams.BROWSER_VERSION, str(self.version)))
|
{kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/conversion.py
RENAMED
|
@@ -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.
|
|
31
|
-
self.
|
|
32
|
-
self.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def
|
|
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
|
-
|
|
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.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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.
|
|
31
|
-
self.
|
|
32
|
-
self.
|
|
33
|
-
self._instance: DataType = DataType.PAGE_VIEW
|
|
31
|
+
self.__url = url
|
|
32
|
+
self.__title = title
|
|
33
|
+
self.__referrers = referrers
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
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)
|
{kameleoon-client-python-2.3.0 → kameleoon-client-python-3.0.0}/kameleoon/data/user_agent.py
RENAMED
|
@@ -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
|
-
|
|
18
|
+
super().__init__()
|
|
19
|
+
self.__value = value
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
@property
|
|
22
|
+
def value(self) -> str:
|
|
21
23
|
"""
|
|
22
24
|
return user agent value
|
|
23
25
|
:return:
|
|
24
26
|
"""
|
|
25
|
-
return self.
|
|
27
|
+
return self.__value
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def data_type(self) -> DataType:
|
|
31
|
+
return DataType.USER_AGENT
|