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.
Files changed (107) hide show
  1. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/PKG-INFO +2 -4
  2. kameleoon-client-python-3.2.0/kameleoon/configuration/__init__.py +9 -0
  3. kameleoon-client-python-3.2.0/kameleoon/configuration/custom_data_info.py +51 -0
  4. kameleoon-client-python-3.2.0/kameleoon/configuration/data_file.py +111 -0
  5. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/rule.py +2 -0
  6. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/variable.py +4 -0
  7. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/__init__.py +7 -0
  8. kameleoon-client-python-3.2.0/kameleoon/data/cookie.py +32 -0
  9. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/custom_data.py +3 -0
  10. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/data.py +5 -0
  11. kameleoon-client-python-3.2.0/kameleoon/data/geolocation.py +100 -0
  12. kameleoon-client-python-3.2.0/kameleoon/data/operating_system.py +52 -0
  13. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/page_view.py +6 -5
  14. kameleoon-client-python-3.2.0/kameleoon/data/visitor_visits.py +29 -0
  15. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/functions.py +17 -0
  16. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/kameleoon_client.py +196 -141
  17. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/sdk_version.py +1 -1
  18. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/cookie_condition.py +53 -0
  19. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/exclusive_feature_flag_condition.py +42 -0
  20. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/geolocation_condition.py +30 -0
  21. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/number_condition.py +34 -0
  22. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/operating_system_condition.py +22 -0
  23. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/page_title_condition.py +2 -1
  24. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/page_view_number_condition.py +18 -0
  25. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/previous_page_condition.py +27 -0
  26. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/segment_condition.py +45 -0
  27. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/target_feature_flag_condition.py +67 -0
  28. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/targeting_condition.py +25 -3
  29. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.py +27 -0
  30. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/visit_number_today_condition.py +28 -0
  31. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/visit_number_total_condition.py +18 -0
  32. kameleoon-client-python-3.2.0/kameleoon/targeting/conditions/visitor_new_return_condition.py +31 -0
  33. kameleoon-client-python-3.2.0/kameleoon/targeting/targeting_manager.py +102 -0
  34. kameleoon-client-python-3.2.0/kameleoon/targeting/tree_condition_factory.py +102 -0
  35. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon_client_python.egg-info/PKG-INFO +2 -4
  36. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon_client_python.egg-info/SOURCES.txt +19 -2
  37. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/setup.py +1 -3
  38. kameleoon-client-python-3.1.0/kameleoon/configuration/data_file.py +0 -63
  39. kameleoon-client-python-3.1.0/kameleoon/targeting/conditions/exclusive_experiment.py +0 -26
  40. kameleoon-client-python-3.1.0/kameleoon/targeting/conditions/target_experiment.py +0 -33
  41. kameleoon-client-python-3.1.0/kameleoon/targeting/tree_condition_factory.py +0 -58
  42. kameleoon-client-python-3.1.0/tests/integration/proj/proj/__init__.py +0 -0
  43. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/MANIFEST.in +0 -0
  44. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/README.md +0 -0
  45. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/__init__.py +0 -0
  46. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/feature_flag.py +0 -0
  47. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/rule_type.py +0 -0
  48. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/settings.py +0 -0
  49. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/variation.py +0 -0
  50. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/configuration/variation_by_exposition.py +0 -0
  51. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/browser.py +0 -0
  52. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/conversion.py +0 -0
  53. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/device.py +0 -0
  54. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/data/user_agent.py +0 -0
  55. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/defaults.py +0 -0
  56. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/exceptions.py +0 -0
  57. {kameleoon-client-python-3.1.0/kameleoon/configuration → kameleoon-client-python-3.2.0/kameleoon/helpers}/__init__.py +0 -0
  58. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/logger.py +0 -0
  59. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/multi_threading.py +0 -0
  60. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/nonce.py +0 -0
  61. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/repeat_timer.py +0 -0
  62. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/scheduler.py +0 -0
  63. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/helpers/visitor_code.py +0 -0
  64. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/kameleoon_client_config.py +0 -0
  65. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/kameleoon_client_factory.py +0 -0
  66. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/middleware.py +0 -0
  67. {kameleoon-client-python-3.1.0/kameleoon/helpers → kameleoon-client-python-3.2.0/kameleoon/real_time}/__init__.py +0 -0
  68. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/real_time/real_time_configuration_service.py +0 -0
  69. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/real_time/real_time_event.py +0 -0
  70. {kameleoon-client-python-3.1.0/kameleoon/real_time → kameleoon-client-python-3.2.0/kameleoon/storage}/__init__.py +0 -0
  71. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/storage/cache.py +0 -0
  72. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/storage/cache_factory.py +0 -0
  73. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/storage/cache_factory_impl.py +0 -0
  74. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/storage/cache_impl.py +0 -0
  75. {kameleoon-client-python-3.1.0/kameleoon/storage → kameleoon-client-python-3.2.0/kameleoon/targeting}/__init__.py +0 -0
  76. {kameleoon-client-python-3.1.0/kameleoon/targeting → kameleoon-client-python-3.2.0/kameleoon/targeting/conditions}/__init__.py +0 -0
  77. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/browser_condition.py +0 -0
  78. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/constants.py +0 -0
  79. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/conversion_condition.py +0 -0
  80. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/custom_datum.py +0 -0
  81. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/device_condition.py +0 -0
  82. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/page_url_condition.py +0 -0
  83. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/sdk_language_condition.py +0 -0
  84. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/string_value_condition.py +0 -0
  85. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/unknown_condition.py +0 -0
  86. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/conditions/visitor_code_condition.py +0 -0
  87. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/models.py +0 -0
  88. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon/targeting/tree_builder.py +0 -0
  89. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon_client_python.egg-info/dependency_links.txt +0 -0
  90. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon_client_python.egg-info/requires.txt +13 -13
  91. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/kameleoon_client_python.egg-info/top_level.txt +0 -0
  92. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/setup.cfg +0 -0
  93. {kameleoon-client-python-3.1.0/kameleoon/targeting/conditions → kameleoon-client-python-3.2.0/tests/integration/proj}/__init__.py +0 -0
  94. {kameleoon-client-python-3.1.0/tests/integration/proj → kameleoon-client-python-3.2.0/tests/integration/proj/kameleoon_app}/__init__.py +0 -0
  95. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/kameleoon_app/admin.py +0 -0
  96. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/kameleoon_app/apps.py +0 -0
  97. {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
  98. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/kameleoon_app/models.py +0 -0
  99. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/kameleoon_app/tests.py +0 -0
  100. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/kameleoon_app/views.py +0 -0
  101. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/manage.py +0 -0
  102. {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
  103. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/proj/asgi.py +0 -0
  104. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/proj/settings.py +0 -0
  105. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/proj/urls.py +0 -0
  106. {kameleoon-client-python-3.1.0 → kameleoon-client-python-3.2.0}/tests/integration/proj/proj/wsgi.py +0 -0
  107. {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.1.0
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.6.0
17
+ Requires-Python: >=3.8.0
20
18
  Description-Content-Type: text/markdown
21
19
  Provides-Extra: test
22
20
 
@@ -0,0 +1,9 @@
1
+ """ Imports kameleoon configurations objects """
2
+
3
+ from .variable import Variable
4
+ from .variation import Variation
5
+
6
+ __all__ = [
7
+ "Variable",
8
+ "Variation",
9
+ ]
@@ -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
@@ -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"""
@@ -39,3 +39,7 @@ class Variable:
39
39
  if self.__type == Variable.Type.JSON.value and isinstance(self.__value, str):
40
40
  return json.loads(self.__value)
41
41
  return None
42
+
43
+ def get_type(self) -> str:
44
+ """Returns type value of variable"""
45
+ return self.__type
@@ -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
@@ -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"))
@@ -13,6 +13,11 @@ class DataType(IntEnum):
13
13
  PAGE_VIEW = 4
14
14
  USER_AGENT = 5
15
15
  ASSIGNED_VARIATION = 6
16
+ COOKIE = 7
17
+ OPERATING_SYSTEM = 8
18
+ GEOLOCATION = 9
19
+ PAGE_VIEW_VISIT = 10
20
+ VISITOR_VISITS = 11
16
21
 
17
22
 
18
23
  class BaseData:
@@ -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 []
@@ -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()))