kameleoon-client-python 3.1.0__tar.gz → 3.2.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-3.1.0 → kameleoon-client-python-3.2.0}/PKG-INFO +2 -4
- kameleoon-client-python-3.2.0/kameleoon/configuration/__init__.py +9 -0
- kameleoon-client-python-3.2.0/kameleoon/configuration/custom_data_info.py +51 -0
- kameleoon-client-python-3.2.0/kameleoon/configuration/data_file.py +111 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/rule.py +2 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/variable.py +4 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/__init__.py +7 -0
- kameleoon-client-python-3.2.0/kameleoon/data/cookie.py +32 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/custom_data.py +3 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/data.py +5 -0
- kameleoon-client-python-3.2.0/kameleoon/data/geolocation.py +100 -0
- kameleoon-client-python-3.2.0/kameleoon/data/operating_system.py +52 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/page_view.py +6 -5
- kameleoon-client-python-3.2.0/kameleoon/data/visitor_visits.py +29 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/functions.py +17 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/kameleoon_client.py +196 -141
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/sdk_version.py +1 -1
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/cookie_condition.py +53 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/exclusive_feature_flag_condition.py +42 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/geolocation_condition.py +30 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/number_condition.py +34 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/operating_system_condition.py +22 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/page_title_condition.py +2 -1
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/page_view_number_condition.py +18 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/previous_page_condition.py +27 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/segment_condition.py +45 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/target_feature_flag_condition.py +67 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/targeting_condition.py +25 -3
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.py +27 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/visit_number_today_condition.py +28 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/visit_number_total_condition.py +18 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/visitor_new_return_condition.py +31 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/targeting_manager.py +102 -0
- kameleoon-client-python-3.2.0/kameleoon/targeting/tree_condition_factory.py +102 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon_client_python.egg-info/PKG-INFO +2 -4
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon_client_python.egg-info/SOURCES.txt +19 -2
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/setup.py +1 -3
- kameleoon-client-python-3.1.0/kameleoon/configuration/data_file.py +0 -63
- kameleoon-client-python-3.1.0/kameleoon/targeting/conditions/exclusive_experiment.py +0 -26
- kameleoon-client-python-3.1.0/kameleoon/targeting/conditions/target_experiment.py +0 -33
- kameleoon-client-python-3.1.0/kameleoon/targeting/tree_condition_factory.py +0 -58
- kameleoon-client-python-3.1.0/tests/integration/proj/proj/__init__.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/MANIFEST.in +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/README.md +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/__init__.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/feature_flag.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/rule_type.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/settings.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/variation.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/variation_by_exposition.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/browser.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/conversion.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/device.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/user_agent.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/defaults.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/exceptions.py +0 -0
- {kameleoon-client-python-3.1.0/kameleoon/configuration → kameleoon-client-python-3.2.0/kameleoon/helpers}/__init__.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/logger.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/multi_threading.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/nonce.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/repeat_timer.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/scheduler.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/visitor_code.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/kameleoon_client_config.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/kameleoon_client_factory.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/middleware.py +0 -0
- {kameleoon-client-python-3.1.0/kameleoon/helpers → kameleoon-client-python-3.2.0/kameleoon/real_time}/__init__.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/real_time/real_time_configuration_service.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/real_time/real_time_event.py +0 -0
- {kameleoon-client-python-3.1.0/kameleoon/real_time → kameleoon-client-python-3.2.0/kameleoon/storage}/__init__.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/storage/cache.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/storage/cache_factory.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/storage/cache_factory_impl.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/storage/cache_impl.py +0 -0
- {kameleoon-client-python-3.1.0/kameleoon/storage → kameleoon-client-python-3.2.0/kameleoon/targeting}/__init__.py +0 -0
- {kameleoon-client-python-3.1.0/kameleoon/targeting → kameleoon-client-python-3.2.0/kameleoon/targeting/conditions}/__init__.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/browser_condition.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/constants.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/conversion_condition.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/custom_datum.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/device_condition.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/page_url_condition.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/sdk_language_condition.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/string_value_condition.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/unknown_condition.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/models.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/tree_builder.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon_client_python.egg-info/requires.txt +13 -13
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/setup.cfg +0 -0
- {kameleoon-client-python-3.1.0/kameleoon/targeting/conditions → kameleoon-client-python-3.2.0/tests/integration/proj}/__init__.py +0 -0
- {kameleoon-client-python-3.1.0/tests/integration/proj → kameleoon-client-python-3.2.0/tests/integration/proj/kameleoon_app}/__init__.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/kameleoon_app/apps.py +0 -0
- {kameleoon-client-python-3.1.0/tests/integration/proj/kameleoon_app → kameleoon-client-python-3.2.0/tests/integration/proj/kameleoon_app/migrations}/__init__.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/kameleoon_app/views.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/manage.py +0 -0
- {kameleoon-client-python-3.1.0/tests/integration/proj/kameleoon_app/migrations → kameleoon-client-python-3.2.0/tests/integration/proj/proj}/__init__.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/proj/asgi.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/proj/settings.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/proj/urls.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/proj/wsgi.py +0 -0
- {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/resources/config.yml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: kameleoon-client-python
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.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
|
|
@@ -9,14 +9,12 @@ License: GPLv3
|
|
|
9
9
|
Platform: UNKNOWN
|
|
10
10
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
11
11
|
Classifier: Programming Language :: Python
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.8
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
16
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
15
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
16
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
19
|
-
Requires-Python: >=3.
|
|
17
|
+
Requires-Python: >=3.8.0
|
|
20
18
|
Description-Content-Type: text/markdown
|
|
21
19
|
Provides-Extra: test
|
|
22
20
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Custom data info"""
|
|
2
|
+
|
|
3
|
+
from logging import Logger
|
|
4
|
+
from typing import Optional, Dict, Union, Any, List
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CustomDataInfo:
|
|
8
|
+
"""Custom data info"""
|
|
9
|
+
|
|
10
|
+
SCOPE_VISITOR = "VISITOR"
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self, custom_data: Optional[List[Dict[str, Union[str, int, Any]]]], logger: Optional[Logger] = None
|
|
14
|
+
) -> None:
|
|
15
|
+
super().__init__()
|
|
16
|
+
self.__mapping_identifier_index = None
|
|
17
|
+
self.__local_only = set()
|
|
18
|
+
self.__visitor_scope = set()
|
|
19
|
+
if custom_data is not None:
|
|
20
|
+
for data in custom_data:
|
|
21
|
+
index = data.get("index")
|
|
22
|
+
if index is not None:
|
|
23
|
+
index = int(index)
|
|
24
|
+
if data.get("localOnly"):
|
|
25
|
+
self.__local_only.add(index)
|
|
26
|
+
if data.get("scope") == self.SCOPE_VISITOR:
|
|
27
|
+
self.__visitor_scope.add(index)
|
|
28
|
+
if data.get("isMappingIdentifier"):
|
|
29
|
+
if bool(self.__mapping_identifier_index is not None) and logger is not None:
|
|
30
|
+
logger.info(
|
|
31
|
+
"More than one mapping identifier is set. Undefined behavior may occur" +
|
|
32
|
+
" on cross-device reconciliation."
|
|
33
|
+
)
|
|
34
|
+
self.__mapping_identifier_index = index
|
|
35
|
+
|
|
36
|
+
def is_local_only(self, index: int) -> bool:
|
|
37
|
+
"""Check for local only"""
|
|
38
|
+
return index in self.__local_only
|
|
39
|
+
|
|
40
|
+
def is_mapping_identifier(self, index: int) -> bool:
|
|
41
|
+
"""Check for mapping identifier"""
|
|
42
|
+
return self.__mapping_identifier_index == index
|
|
43
|
+
|
|
44
|
+
def is_visitor_scope(self, index: int) -> bool:
|
|
45
|
+
"""Check for visitor scope"""
|
|
46
|
+
return index in self.__visitor_scope
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def mapping_identifier_index(self) -> Optional[int]:
|
|
50
|
+
"""Take mapping identifier index"""
|
|
51
|
+
return self.__mapping_identifier_index
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""Kameleoon Configuration"""
|
|
2
|
+
from logging import Logger
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
from kameleoon.configuration.custom_data_info import CustomDataInfo
|
|
5
|
+
from kameleoon.configuration.variation_by_exposition import VariationByExposition
|
|
6
|
+
from kameleoon.configuration.feature_flag import FeatureFlag
|
|
7
|
+
from kameleoon.configuration.rule import Rule
|
|
8
|
+
from kameleoon.configuration.settings import Settings
|
|
9
|
+
from kameleoon.exceptions import FeatureNotFound, FeatureEnvironmentDisabled
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DataFile:
|
|
13
|
+
"""`DataFile` is a container for an actual client-configuration data"""
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def default(environment: Optional[str]) -> "DataFile":
|
|
17
|
+
"""Creates new instance of `DataFile` initialized with default values"""
|
|
18
|
+
return DataFile(environment, Settings(), {}, CustomDataInfo(None))
|
|
19
|
+
|
|
20
|
+
@staticmethod
|
|
21
|
+
def from_json(
|
|
22
|
+
environment: Optional[str], configuration: Dict[str, Any], logger: Optional[Logger] = None
|
|
23
|
+
) -> "DataFile":
|
|
24
|
+
"""Creates new instance of `DataFile` initialized from the specified configuration JSON"""
|
|
25
|
+
settings = Settings(configuration.get("configuration"))
|
|
26
|
+
feature_flags = {
|
|
27
|
+
(feature_flag := FeatureFlag(jobj)).feature_key: feature_flag
|
|
28
|
+
for jobj in configuration.get("featureFlags") or []
|
|
29
|
+
}
|
|
30
|
+
custom_data_info = CustomDataInfo(configuration.get("customData"), logger=logger)
|
|
31
|
+
return DataFile(environment, settings, feature_flags, custom_data_info)
|
|
32
|
+
|
|
33
|
+
# pylint: disable=R0913
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
environment: Optional[str],
|
|
37
|
+
settings: Settings,
|
|
38
|
+
feature_flags: Dict[str, FeatureFlag],
|
|
39
|
+
custom_data_info: CustomDataInfo,
|
|
40
|
+
) -> None:
|
|
41
|
+
self.__environment = environment # pylint: disable=W0238
|
|
42
|
+
self.__settings = settings
|
|
43
|
+
self.__feature_flags: Dict[str, FeatureFlag] = feature_flags
|
|
44
|
+
self.__has_any_targeted_delivery_rule = any(
|
|
45
|
+
rule.is_targeted_delivery
|
|
46
|
+
for ff in self.__feature_flags.values()
|
|
47
|
+
if ff.environment_enabled
|
|
48
|
+
for rule in ff.rules
|
|
49
|
+
)
|
|
50
|
+
self.__variation_by_id: Dict[int, VariationByExposition] = {}
|
|
51
|
+
self.__rule_by_segment_id: Dict[int, Rule] = {}
|
|
52
|
+
self.__feature_flag_by_id: Dict[int, FeatureFlag] = {}
|
|
53
|
+
self.__collect_indices()
|
|
54
|
+
self.__custom_data_info = custom_data_info
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def settings(self) -> Settings:
|
|
58
|
+
"""Returns settings"""
|
|
59
|
+
return self.__settings
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def feature_flags(self) -> Dict[str, FeatureFlag]:
|
|
63
|
+
"""Returns dictionary of all feature flags stored by feature keys"""
|
|
64
|
+
return self.__feature_flags
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def feature_flag_by_id(self) -> Dict[int, FeatureFlag]:
|
|
68
|
+
"""Returns dictionary of all feature flags stored by id"""
|
|
69
|
+
return self.__feature_flag_by_id
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def rule_by_segment_id(self) -> Dict[int, Rule]:
|
|
73
|
+
"""Returns dictionary of all rule stored by segment id"""
|
|
74
|
+
return self.__rule_by_segment_id
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def variation_by_id(self) -> Dict[int, VariationByExposition]:
|
|
78
|
+
"""Returns dictionary of all variations stored by id"""
|
|
79
|
+
return self.__variation_by_id
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def has_any_targeted_delivery_rule(self) -> bool:
|
|
83
|
+
"""Returns `True` if has a feature flag with a rule of the targeted delivery type, otherwise returns `False`"""
|
|
84
|
+
return self.__has_any_targeted_delivery_rule
|
|
85
|
+
|
|
86
|
+
def get_feature_flag(self, feature_key: str) -> FeatureFlag:
|
|
87
|
+
"""
|
|
88
|
+
Returns feature flag with the specified feature key if it exists,
|
|
89
|
+
otherwise raises `FeatureNotFound` exception.
|
|
90
|
+
"""
|
|
91
|
+
feature_flag = self.__feature_flags.get(feature_key)
|
|
92
|
+
if feature_flag is None:
|
|
93
|
+
raise FeatureNotFound(feature_key)
|
|
94
|
+
if not feature_flag.environment_enabled:
|
|
95
|
+
raise FeatureEnvironmentDisabled(feature_key, self.__environment)
|
|
96
|
+
return feature_flag
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def custom_data_info(self) -> CustomDataInfo:
|
|
100
|
+
"""Returns custom data info for mapping device`"""
|
|
101
|
+
return self.__custom_data_info
|
|
102
|
+
|
|
103
|
+
def __collect_indices(self) -> None:
|
|
104
|
+
for _, feature_flag in self.__feature_flags.items():
|
|
105
|
+
self.__feature_flag_by_id[feature_flag.id_] = feature_flag
|
|
106
|
+
if feature_flag.rules is not None:
|
|
107
|
+
for rule in feature_flag.rules:
|
|
108
|
+
self.__rule_by_segment_id[rule.segment_id] = rule
|
|
109
|
+
for variation in rule.variation_by_exposition:
|
|
110
|
+
if variation.variation_id is not None:
|
|
111
|
+
self.__variation_by_id[variation.variation_id] = variation
|
{kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/rule.py
RENAMED
|
@@ -28,8 +28,10 @@ class Rule:
|
|
|
28
28
|
self.variation_by_exposition: List[VariationByExposition] = VariationByExposition.from_array(
|
|
29
29
|
dict_json.get("variationByExposition", [])
|
|
30
30
|
)
|
|
31
|
+
self.first_variation = self.variation_by_exposition[0] if len(self.variation_by_exposition) > 0 else None
|
|
31
32
|
segment = dict_json.get("segment")
|
|
32
33
|
self.targeting_segment: Optional[Segment] = Segment(segment) if segment else None
|
|
34
|
+
self.segment_id: int = self.targeting_segment.id_ if self.targeting_segment else -1
|
|
33
35
|
|
|
34
36
|
def get_variation(self, hash_double: float) -> Optional[VariationByExposition]:
|
|
35
37
|
"""Calculates the variation key for the given hash of visitor"""
|
|
@@ -7,6 +7,9 @@ from .device import Device, DeviceType
|
|
|
7
7
|
from .page_view import PageView
|
|
8
8
|
from .user_agent import UserAgent
|
|
9
9
|
from .data import Data, DataType
|
|
10
|
+
from .cookie import Cookie
|
|
11
|
+
from .geolocation import Geolocation
|
|
12
|
+
from .operating_system import OperatingSystem, OperatingSystemType
|
|
10
13
|
|
|
11
14
|
__all__ = [
|
|
12
15
|
"CustomData",
|
|
@@ -19,4 +22,8 @@ __all__ = [
|
|
|
19
22
|
"UserAgent",
|
|
20
23
|
"Data",
|
|
21
24
|
"DataType",
|
|
25
|
+
"Cookie",
|
|
26
|
+
"Geolocation",
|
|
27
|
+
"OperatingSystemType",
|
|
28
|
+
"OperatingSystem",
|
|
22
29
|
]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Cookie data"""
|
|
2
|
+
|
|
3
|
+
from typing import Dict
|
|
4
|
+
from kameleoon.data.data import Data, DataType
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Cookie(Data):
|
|
8
|
+
"""Cookie data"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, cookies: Dict[str, str]) -> None:
|
|
11
|
+
"""
|
|
12
|
+
:param cookies: values cookie from visitor
|
|
13
|
+
:type cookies: Dict[str, str]
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
.. code-block:: python3
|
|
17
|
+
kameleoon_client.add_data(visitor_code, Cookie({'key1' : 'value1'}))
|
|
18
|
+
"""
|
|
19
|
+
super().__init__()
|
|
20
|
+
self.__cookies = cookies
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def cookies(self) -> Dict[str, str]:
|
|
24
|
+
"""
|
|
25
|
+
:return: cookie values
|
|
26
|
+
:rtype: Dict[str, str]
|
|
27
|
+
"""
|
|
28
|
+
return self.__cookies
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def data_type(self) -> DataType:
|
|
32
|
+
return DataType.COOKIE
|
{kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/custom_data.py
RENAMED
|
@@ -30,6 +30,7 @@ class CustomData(Data, DuplicationUnsafeSendableBase):
|
|
|
30
30
|
# pylint: disable=W0511
|
|
31
31
|
self.__id = id
|
|
32
32
|
self.__values = args
|
|
33
|
+
self.is_mapping_identifier: bool = False
|
|
33
34
|
|
|
34
35
|
@property
|
|
35
36
|
def id(self) -> int: # pylint: disable=C0103
|
|
@@ -56,3 +57,5 @@ class CustomData(Data, DuplicationUnsafeSendableBase):
|
|
|
56
57
|
QueryParam(QueryParams.VALUES_COUNT_MAP, str_values),
|
|
57
58
|
QueryParam(QueryParams.OVERWRITE, "true"),
|
|
58
59
|
)
|
|
60
|
+
if self.is_mapping_identifier:
|
|
61
|
+
qb.append(QueryParam(QueryParams.MAPPING_IDENTIFIER, "true"))
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# pylint: disable=duplicate-code
|
|
2
|
+
"""Geolocation data"""
|
|
3
|
+
|
|
4
|
+
from typing import Optional
|
|
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 Geolocation(Data, DuplicationUnsafeSendableBase):
|
|
11
|
+
"""Geolocation data"""
|
|
12
|
+
|
|
13
|
+
EVENT_TYPE = "staticData"
|
|
14
|
+
|
|
15
|
+
# pylint: disable=R0913
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
country: str,
|
|
19
|
+
region: Optional[str] = None,
|
|
20
|
+
city: Optional[str] = None,
|
|
21
|
+
postal_code: Optional[str] = None,
|
|
22
|
+
latitude: Optional[float] = None,
|
|
23
|
+
longitude: Optional[float] = None,
|
|
24
|
+
) -> None:
|
|
25
|
+
"""
|
|
26
|
+
:param country: required
|
|
27
|
+
:type country: str
|
|
28
|
+
:param region:
|
|
29
|
+
:type region: Optional[str]
|
|
30
|
+
:param city:
|
|
31
|
+
:type city: Optional[str]
|
|
32
|
+
:param postal_code:
|
|
33
|
+
:type postal_code: Optional[str]
|
|
34
|
+
:param latitude:
|
|
35
|
+
:type latitude: Optional[float]
|
|
36
|
+
:param longitude:
|
|
37
|
+
:type longitude: Optional[float]
|
|
38
|
+
|
|
39
|
+
Example:
|
|
40
|
+
.. code-block:: python3
|
|
41
|
+
kameleoon_client.add_data(visitor_code, Geolocation("France"))
|
|
42
|
+
"""
|
|
43
|
+
super().__init__()
|
|
44
|
+
self.__country = country
|
|
45
|
+
self.__region = region
|
|
46
|
+
self.__city = city
|
|
47
|
+
self.__postal_code = postal_code
|
|
48
|
+
self.__latitude = latitude
|
|
49
|
+
self.__longitude = longitude
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def country(self) -> Optional[str]:
|
|
53
|
+
"""Returns country"""
|
|
54
|
+
return self.__country
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def region(self) -> Optional[str]:
|
|
58
|
+
"""Returns region"""
|
|
59
|
+
return self.__region
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def city(self) -> Optional[str]:
|
|
63
|
+
"""Returns city"""
|
|
64
|
+
return self.__city
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def postal_code(self) -> Optional[str]:
|
|
68
|
+
"""Returns postal_code"""
|
|
69
|
+
return self.__postal_code
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def latitude(self) -> Optional[float]:
|
|
73
|
+
"""Returns latitude"""
|
|
74
|
+
return self.__latitude
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def longitude(self) -> Optional[float]:
|
|
78
|
+
"""Returns longitude"""
|
|
79
|
+
return self.__longitude
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def data_type(self) -> DataType:
|
|
83
|
+
return DataType.GEOLOCATION
|
|
84
|
+
|
|
85
|
+
def _add_query_params(self, qb: QueryBuilder) -> None:
|
|
86
|
+
qb.extend(
|
|
87
|
+
QueryParam(QueryParams.EVENT_TYPE, self.EVENT_TYPE),
|
|
88
|
+
)
|
|
89
|
+
if self.country:
|
|
90
|
+
qb.append(QueryParam(QueryParams.COUNTRY, self.country))
|
|
91
|
+
if self.region:
|
|
92
|
+
qb.append(QueryParam(QueryParams.REGION, self.region))
|
|
93
|
+
if self.city:
|
|
94
|
+
qb.append(QueryParam(QueryParams.CITY, self.city))
|
|
95
|
+
if self.postal_code:
|
|
96
|
+
qb.append(QueryParam(QueryParams.POSTAL_CODE, self.postal_code))
|
|
97
|
+
if self.latitude is not None:
|
|
98
|
+
qb.append(QueryParam(QueryParams.LATITUDE, str(self.latitude)))
|
|
99
|
+
if self.longitude is not None:
|
|
100
|
+
qb.append(QueryParam(QueryParams.LONGITUDE, str(self.longitude)))
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# pylint: disable=duplicate-code
|
|
2
|
+
"""Operating system data"""
|
|
3
|
+
|
|
4
|
+
from enum import IntEnum
|
|
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 OperatingSystemType(IntEnum):
|
|
11
|
+
"""Operating system types"""
|
|
12
|
+
|
|
13
|
+
WINDOWS: int = 0
|
|
14
|
+
MAC: int = 1
|
|
15
|
+
IOS: int = 2
|
|
16
|
+
LINUX: int = 3
|
|
17
|
+
ANDROID: int = 4
|
|
18
|
+
WINDOWS_PHONE: int = 5
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class OperatingSystem(Data, DuplicationUnsafeSendableBase):
|
|
22
|
+
"""Operating system data"""
|
|
23
|
+
|
|
24
|
+
EVENT_TYPE = "staticData"
|
|
25
|
+
|
|
26
|
+
def __init__(self, os_type: OperatingSystemType) -> None:
|
|
27
|
+
"""
|
|
28
|
+
:param os_type: OperatingSystemType, can be: WINDOWS, MAC, IOS, LINUX, ANDROID, WINDOWS_PHONE
|
|
29
|
+
:type os_type: OperatingSystemType
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
.. code-block:: python3
|
|
33
|
+
kameleoon_client.add_data(visitor_code, OperatingSystem(OperatingSystemType.ANDROID))
|
|
34
|
+
"""
|
|
35
|
+
super().__init__()
|
|
36
|
+
self.__os_type = os_type
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def os_type(self) -> OperatingSystemType:
|
|
40
|
+
"""Returns operating system type"""
|
|
41
|
+
return self.__os_type
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def data_type(self) -> DataType:
|
|
45
|
+
return DataType.OPERATING_SYSTEM
|
|
46
|
+
|
|
47
|
+
def _add_query_params(self, qb: QueryBuilder) -> None:
|
|
48
|
+
qb.extend(
|
|
49
|
+
QueryParam(QueryParams.EVENT_TYPE, self.EVENT_TYPE),
|
|
50
|
+
QueryParam(QueryParams.OPERATING_SYSTEM, self.os_type.name),
|
|
51
|
+
QueryParam(QueryParams.OPERATING_SYSTEM_INDEX, str(self.os_type.value)),
|
|
52
|
+
)
|
|
@@ -12,12 +12,12 @@ class PageView(Data, DuplicationSafeSendableBase):
|
|
|
12
12
|
|
|
13
13
|
EVENT_TYPE = "page"
|
|
14
14
|
|
|
15
|
-
def __init__(self, url: str, title: str, referrers: Optional[List[int]] = None) -> None:
|
|
15
|
+
def __init__(self, url: str, title: Optional[str], referrers: Optional[List[int]] = None) -> None:
|
|
16
16
|
"""
|
|
17
17
|
:param url: Url of the page
|
|
18
18
|
:type url: str
|
|
19
|
-
:param title: Title of the page
|
|
20
|
-
:type title: str
|
|
19
|
+
:param title: Optional field - Title of the page
|
|
20
|
+
:type title: Optional[str]
|
|
21
21
|
:param referrers: Optional field - Referrer ids
|
|
22
22
|
:type referrers: Optional[List[int]]
|
|
23
23
|
|
|
@@ -38,7 +38,7 @@ class PageView(Data, DuplicationSafeSendableBase):
|
|
|
38
38
|
return self.__url
|
|
39
39
|
|
|
40
40
|
@property
|
|
41
|
-
def title(self) -> str:
|
|
41
|
+
def title(self) -> Optional[str]:
|
|
42
42
|
"""Returns title"""
|
|
43
43
|
return self.__title
|
|
44
44
|
|
|
@@ -58,8 +58,9 @@ class PageView(Data, DuplicationSafeSendableBase):
|
|
|
58
58
|
qb.extend(
|
|
59
59
|
QueryParam(QueryParams.EVENT_TYPE, self.EVENT_TYPE),
|
|
60
60
|
QueryParam(QueryParams.HREF, self.url),
|
|
61
|
-
QueryParam(QueryParams.TITLE, self.title),
|
|
62
61
|
)
|
|
62
|
+
if self.title:
|
|
63
|
+
qb.append(QueryParam(QueryParams.TITLE, self.title))
|
|
63
64
|
if self.referrers:
|
|
64
65
|
str_referrers = json.dumps(self.referrers, separators=(",", ":"))
|
|
65
66
|
qb.append(QueryParam(QueryParams.REFERRERS_INDICES, str_referrers))
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Visitor visits"""
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
from kameleoon.data import DataType
|
|
6
|
+
|
|
7
|
+
from kameleoon.data.data import BaseData
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class VisitorVisits(BaseData):
|
|
11
|
+
"""Visitor visits"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, previous_visit_timestamps: List[int]) -> None:
|
|
14
|
+
super().__init__()
|
|
15
|
+
self.__previous_visit_timestamps = previous_visit_timestamps
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def previous_visit_timestamps(self) -> List[int]:
|
|
19
|
+
"""Return timestamps for visit"""
|
|
20
|
+
return self.__previous_visit_timestamps
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def data_type(self) -> DataType:
|
|
24
|
+
return DataType.VISITOR_VISITS
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def get_previous_visit_timestamps(visitor_visits: Optional["VisitorVisits"]) -> List[int]:
|
|
28
|
+
"""Return timestamps for visit"""
|
|
29
|
+
return visitor_visits.previous_visit_timestamps if visitor_visits is not None else []
|
{kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/functions.py
RENAMED
|
@@ -66,3 +66,20 @@ def enum_from_literal(literal: str, enum_type: Type[E], default_value: E) -> E:
|
|
|
66
66
|
return enum_type(literal)
|
|
67
67
|
except ValueError:
|
|
68
68
|
return default_value
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def enum_from_name_literal(literal: str, enum_type: Type[E], default_value: Optional[E]) -> Optional[E]:
|
|
72
|
+
"""
|
|
73
|
+
Converts enum name literal to enum value.
|
|
74
|
+
Returns default enum value if literal does not correspond any enum name.
|
|
75
|
+
"""
|
|
76
|
+
try:
|
|
77
|
+
return enum_type[literal]
|
|
78
|
+
except ValueError:
|
|
79
|
+
return default_value
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def compare_str_ignore_case(value_1: Optional[str], value_2: Optional[str]) -> bool:
|
|
83
|
+
"""Comparing two strings ignoring case."""
|
|
84
|
+
return (value_1 == value_2 or
|
|
85
|
+
((value_1 is not None and value_2 is not None) and value_1.lower() == value_2.lower()))
|