devcycle-python-server-sdk 3.12.0__tar.gz → 3.13.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.
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/PKG-INFO +2 -2
- devcycle_python_server_sdk-3.13.0/devcycle_python_sdk/VERSION.txt +1 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/api/local_bucketing.py +19 -4
- devcycle_python_server_sdk-3.13.0/devcycle_python_sdk/bucketing-lib.release.wasm +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/cloud_client.py +3 -3
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/local_client.py +13 -5
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/managers/config_manager.py +4 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/managers/eval_hooks_manager.py +15 -4
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/managers/event_queue_manager.py +0 -1
- devcycle_python_server_sdk-3.13.0/devcycle_python_sdk/models/config_metadata.py +40 -0
- devcycle_python_server_sdk-3.13.0/devcycle_python_sdk/models/environment_metadata.py +26 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/models/eval_hook.py +5 -2
- devcycle_python_server_sdk-3.13.0/devcycle_python_sdk/models/eval_hook_context.py +28 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/models/eval_reason.py +0 -1
- devcycle_python_server_sdk-3.13.0/devcycle_python_sdk/models/project_metadata.py +24 -0
- devcycle_python_server_sdk-3.13.0/devcycle_python_sdk/models/variable_metadata.py +22 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/options.py +1 -1
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/protobuf/utils.py +9 -3
- devcycle_python_server_sdk-3.13.0/devcycle_python_sdk/protobuf/variableForUserParams_pb2.py +51 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/protobuf/variableForUserParams_pb2.pyi +11 -11
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_server_sdk.egg-info/PKG-INFO +2 -2
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_server_sdk.egg-info/SOURCES.txt +4 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_server_sdk.egg-info/requires.txt +1 -1
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/api/test_local_bucketing.py +6 -3
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/models/test_user.py +0 -1
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/openfeature_test/test_provider.py +0 -1
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/test_cloud_client.py +41 -6
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/test_local_client.py +53 -4
- devcycle_python_server_sdk-3.12.0/devcycle_python_sdk/VERSION.txt +0 -1
- devcycle_python_server_sdk-3.12.0/devcycle_python_sdk/bucketing-lib.release.wasm +0 -0
- devcycle_python_server_sdk-3.12.0/devcycle_python_sdk/models/eval_hook_context.py +0 -10
- devcycle_python_server_sdk-3.12.0/devcycle_python_sdk/protobuf/variableForUserParams_pb2.py +0 -59
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/LICENSE +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/README.md +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/api/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/api/backoff.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/api/bucketing_client.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/api/config_client.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/api/event_client.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/devcycle_client.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/exceptions.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/managers/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/managers/sse_manager.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/models/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/models/bucketed_config.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/models/error_response.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/models/event.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/models/feature.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/models/platform_data.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/models/user.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/models/variable.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/open_feature_provider/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/open_feature_provider/provider.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/protobuf/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/py.typed +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/util/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/util/strings.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/util/version.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_server_sdk.egg-info/dependency_links.txt +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_server_sdk.egg-info/top_level.txt +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/example/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/example/cloud_client_example.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/example/local_bucketing_client_example.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/example/openfeature_example.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/pyproject.toml +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/setup.cfg +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/setup.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/api/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/api/test_bucketing_client.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/api/test_config_client.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/api/test_event_client.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/fixture/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/fixture/data.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/managers/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/managers/test_config_manager.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/managers/test_event_queue_manager.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/models/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/models/test_bucketed_config.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/openfeature_test/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/openfeature_test/test_provider_local_sdk.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/util/__init__.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/util/test_strings.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/util/test_utils.py +0 -0
- {devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/util/test_version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devcycle-python-server-sdk
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.13.0
|
|
4
4
|
Summary: DevCycle Python SDK
|
|
5
5
|
Home-page: https://github.com/devcycleHQ/python-server-sdk
|
|
6
6
|
Author-email:
|
|
@@ -12,7 +12,7 @@ Requires-Dist: urllib3>=1.15.1
|
|
|
12
12
|
Requires-Dist: requests>=2.32
|
|
13
13
|
Requires-Dist: wasmtime~=30.0.0
|
|
14
14
|
Requires-Dist: protobuf>=4.23.3
|
|
15
|
-
Requires-Dist: openfeature-sdk
|
|
15
|
+
Requires-Dist: openfeature-sdk==0.8.0
|
|
16
16
|
Requires-Dist: launchdarkly-eventsource>=1.2.1
|
|
17
17
|
Requires-Dist: responses>=0.23.1
|
|
18
18
|
Dynamic: description
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13.0
|
|
@@ -5,7 +5,7 @@ import json
|
|
|
5
5
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from threading import Lock
|
|
8
|
-
from typing import Any, cast, Optional, List
|
|
8
|
+
from typing import Any, cast, Optional, List, Tuple
|
|
9
9
|
|
|
10
10
|
import wasmtime
|
|
11
11
|
from wasmtime import (
|
|
@@ -28,6 +28,7 @@ from devcycle_python_sdk.models.bucketed_config import BucketedConfig
|
|
|
28
28
|
from devcycle_python_sdk.models.user import DevCycleUser
|
|
29
29
|
from devcycle_python_sdk.models.variable import Variable, determine_variable_type
|
|
30
30
|
from devcycle_python_sdk.models.event import FlushPayload
|
|
31
|
+
from devcycle_python_sdk.models.config_metadata import ConfigMetadata
|
|
31
32
|
|
|
32
33
|
logger = logging.getLogger(__name__)
|
|
33
34
|
|
|
@@ -140,6 +141,7 @@ class LocalBucketing:
|
|
|
140
141
|
"generateBucketedConfigForUserUTF8"
|
|
141
142
|
)
|
|
142
143
|
self.VariableForUserProtobuf = self._get_export("variableForUser_PB")
|
|
144
|
+
self.getConfigMetadata = self._get_export("getConfigMetadata")
|
|
143
145
|
|
|
144
146
|
# Extract variable type enum values from WASM
|
|
145
147
|
self.variable_type_map = {
|
|
@@ -298,7 +300,7 @@ class LocalBucketing:
|
|
|
298
300
|
|
|
299
301
|
def get_variable_for_user_protobuf(
|
|
300
302
|
self, user: DevCycleUser, key: str, default_value: Any
|
|
301
|
-
) -> Optional[Variable]:
|
|
303
|
+
) -> Tuple[Optional[Variable], Optional[str]]:
|
|
302
304
|
var_type = determine_variable_type(default_value)
|
|
303
305
|
pb_variable_type = pb_utils.convert_type_enum_to_variable_type(var_type)
|
|
304
306
|
|
|
@@ -317,13 +319,18 @@ class LocalBucketing:
|
|
|
317
319
|
variable_addr = self.VariableForUserProtobuf(self.wasm_store, params_addr)
|
|
318
320
|
|
|
319
321
|
if variable_addr == 0:
|
|
320
|
-
return None
|
|
322
|
+
return None, None
|
|
321
323
|
else:
|
|
322
324
|
var_bytes = self._read_assembly_script_byte_array(variable_addr)
|
|
323
325
|
sdk_variable = pb2.SDKVariable_PB()
|
|
324
326
|
sdk_variable.ParseFromString(var_bytes)
|
|
327
|
+
feature_id = (
|
|
328
|
+
sdk_variable._feature.value
|
|
329
|
+
if sdk_variable._feature.value is not None
|
|
330
|
+
else None
|
|
331
|
+
)
|
|
325
332
|
|
|
326
|
-
return pb_utils.create_variable(sdk_variable, default_value)
|
|
333
|
+
return pb_utils.create_variable(sdk_variable, default_value), feature_id
|
|
327
334
|
|
|
328
335
|
def generate_bucketed_config(self, user: DevCycleUser) -> BucketedConfig:
|
|
329
336
|
user_json = json.dumps(user.to_json())
|
|
@@ -357,6 +364,14 @@ class LocalBucketing:
|
|
|
357
364
|
config_addr = self._new_assembly_script_byte_array(data)
|
|
358
365
|
self.setConfigDataUTF8(self.wasm_store, self.sdk_key_addr, config_addr)
|
|
359
366
|
|
|
367
|
+
def get_config_metadata(self) -> Optional[ConfigMetadata]:
|
|
368
|
+
with self.wasm_lock:
|
|
369
|
+
config_addr = self.getConfigMetadata(self.wasm_store, self.sdk_key_addr)
|
|
370
|
+
config_bytes = self._read_assembly_script_string(config_addr)
|
|
371
|
+
config_data = json.loads(config_bytes.encode("utf-8"))
|
|
372
|
+
|
|
373
|
+
return ConfigMetadata.from_json(config_data)
|
|
374
|
+
|
|
360
375
|
def set_platform_data(self, platform_json: str) -> None:
|
|
361
376
|
with self.wasm_lock:
|
|
362
377
|
data = platform_json.encode("utf-8")
|
|
@@ -115,7 +115,7 @@ class DevCycleCloudClient(AbstractDevCycleClient):
|
|
|
115
115
|
before_hook_error = e
|
|
116
116
|
variable = self.bucketing_api.variable(key, context.user)
|
|
117
117
|
if before_hook_error is None:
|
|
118
|
-
self.eval_hooks_manager.run_after(context, variable)
|
|
118
|
+
self.eval_hooks_manager.run_after(context, variable, None)
|
|
119
119
|
else:
|
|
120
120
|
raise before_hook_error
|
|
121
121
|
except CloudClientUnauthorizedError as e:
|
|
@@ -126,7 +126,7 @@ class DevCycleCloudClient(AbstractDevCycleClient):
|
|
|
126
126
|
return Variable.create_default_variable(
|
|
127
127
|
key=key,
|
|
128
128
|
default_value=default_value,
|
|
129
|
-
default_reason_detail=DefaultReasonDetails.
|
|
129
|
+
default_reason_detail=DefaultReasonDetails.ERROR,
|
|
130
130
|
)
|
|
131
131
|
except BeforeHookError as e:
|
|
132
132
|
self.eval_hooks_manager.run_error(context, e)
|
|
@@ -140,7 +140,7 @@ class DevCycleCloudClient(AbstractDevCycleClient):
|
|
|
140
140
|
default_reason_detail=DefaultReasonDetails.ERROR,
|
|
141
141
|
)
|
|
142
142
|
finally:
|
|
143
|
-
self.eval_hooks_manager.run_finally(context, variable)
|
|
143
|
+
self.eval_hooks_manager.run_finally(context, variable, None)
|
|
144
144
|
|
|
145
145
|
variable.defaultValue = default_value
|
|
146
146
|
|
|
@@ -26,6 +26,7 @@ from devcycle_python_sdk.models.feature import Feature
|
|
|
26
26
|
from devcycle_python_sdk.models.platform_data import default_platform_data
|
|
27
27
|
from devcycle_python_sdk.models.user import DevCycleUser
|
|
28
28
|
from devcycle_python_sdk.models.variable import Variable
|
|
29
|
+
from devcycle_python_sdk.models.variable_metadata import VariableMetadata
|
|
29
30
|
from devcycle_python_sdk.open_feature_provider.provider import DevCycleProvider
|
|
30
31
|
from openfeature.provider import AbstractProvider
|
|
31
32
|
|
|
@@ -150,7 +151,10 @@ class DevCycleLocalClient(AbstractDevCycleClient):
|
|
|
150
151
|
key, default_value, DefaultReasonDetails.MISSING_CONFIG
|
|
151
152
|
)
|
|
152
153
|
|
|
153
|
-
|
|
154
|
+
config_metadata = self.local_bucketing.get_config_metadata()
|
|
155
|
+
variable_metadata = None
|
|
156
|
+
|
|
157
|
+
context = HookContext(key, user, default_value, config_metadata)
|
|
154
158
|
variable = Variable.create_default_variable(
|
|
155
159
|
key=key, default_value=default_value
|
|
156
160
|
)
|
|
@@ -163,9 +167,13 @@ class DevCycleLocalClient(AbstractDevCycleClient):
|
|
|
163
167
|
context = changed_context
|
|
164
168
|
except BeforeHookError as e:
|
|
165
169
|
before_hook_error = e
|
|
166
|
-
bucketed_variable =
|
|
167
|
-
|
|
170
|
+
bucketed_variable, feature_id = (
|
|
171
|
+
self.local_bucketing.get_variable_for_user_protobuf(
|
|
172
|
+
user, key, default_value
|
|
173
|
+
)
|
|
168
174
|
)
|
|
175
|
+
if feature_id is not None:
|
|
176
|
+
variable_metadata = VariableMetadata(feature_id=feature_id)
|
|
169
177
|
if bucketed_variable is not None:
|
|
170
178
|
variable = bucketed_variable
|
|
171
179
|
else:
|
|
@@ -175,7 +183,7 @@ class DevCycleLocalClient(AbstractDevCycleClient):
|
|
|
175
183
|
)
|
|
176
184
|
|
|
177
185
|
if before_hook_error is None:
|
|
178
|
-
self.eval_hooks_manager.run_after(context, variable)
|
|
186
|
+
self.eval_hooks_manager.run_after(context, variable, variable_metadata)
|
|
179
187
|
else:
|
|
180
188
|
raise before_hook_error
|
|
181
189
|
except Exception as e:
|
|
@@ -192,7 +200,7 @@ class DevCycleLocalClient(AbstractDevCycleClient):
|
|
|
192
200
|
|
|
193
201
|
return variable
|
|
194
202
|
finally:
|
|
195
|
-
self.eval_hooks_manager.run_finally(context, variable)
|
|
203
|
+
self.eval_hooks_manager.run_finally(context, variable, variable_metadata)
|
|
196
204
|
return variable
|
|
197
205
|
|
|
198
206
|
def _generate_bucketed_config(self, user: DevCycleUser) -> BucketedConfig:
|
|
@@ -16,6 +16,7 @@ from devcycle_python_sdk.exceptions import (
|
|
|
16
16
|
from wsgiref.handlers import format_date_time
|
|
17
17
|
from devcycle_python_sdk.options import DevCycleLocalOptions
|
|
18
18
|
from devcycle_python_sdk.managers.sse_manager import SSEManager
|
|
19
|
+
from devcycle_python_sdk.models.config_metadata import ConfigMetadata
|
|
19
20
|
|
|
20
21
|
logger = logging.getLogger(__name__)
|
|
21
22
|
|
|
@@ -108,6 +109,9 @@ class EnvironmentConfigManager(threading.Thread):
|
|
|
108
109
|
)
|
|
109
110
|
self._polling_enabled = False
|
|
110
111
|
|
|
112
|
+
def get_config_metadata(self) -> Optional[ConfigMetadata]:
|
|
113
|
+
return self._local_bucketing.get_config_metadata()
|
|
114
|
+
|
|
111
115
|
def run(self):
|
|
112
116
|
while self._polling_enabled:
|
|
113
117
|
try:
|
|
@@ -3,6 +3,7 @@ from typing import List, Optional
|
|
|
3
3
|
from devcycle_python_sdk.models.eval_hook import EvalHook
|
|
4
4
|
from devcycle_python_sdk.models.eval_hook_context import HookContext
|
|
5
5
|
from devcycle_python_sdk.models.variable import Variable
|
|
6
|
+
from devcycle_python_sdk.models.variable_metadata import VariableMetadata
|
|
6
7
|
from devcycle_python_sdk.options import logger
|
|
7
8
|
|
|
8
9
|
|
|
@@ -48,19 +49,29 @@ class EvalHooksManager:
|
|
|
48
49
|
raise BeforeHookError(f"Before hook failed: {e}", e)
|
|
49
50
|
return modified_context
|
|
50
51
|
|
|
51
|
-
def run_after(
|
|
52
|
+
def run_after(
|
|
53
|
+
self,
|
|
54
|
+
context: HookContext,
|
|
55
|
+
variable: Variable,
|
|
56
|
+
variable_metadata: Optional[VariableMetadata],
|
|
57
|
+
) -> None:
|
|
52
58
|
"""Run after hooks with the evaluation result"""
|
|
53
59
|
for hook in self.hooks:
|
|
54
60
|
try:
|
|
55
|
-
hook.after(context, variable)
|
|
61
|
+
hook.after(context, variable, variable_metadata)
|
|
56
62
|
except Exception as e:
|
|
57
63
|
raise AfterHookError(f"After hook failed: {e}", e)
|
|
58
64
|
|
|
59
|
-
def run_finally(
|
|
65
|
+
def run_finally(
|
|
66
|
+
self,
|
|
67
|
+
context: HookContext,
|
|
68
|
+
variable: Optional[Variable],
|
|
69
|
+
variable_metadata: Optional[VariableMetadata],
|
|
70
|
+
) -> None:
|
|
60
71
|
"""Run finally hooks after evaluation completes"""
|
|
61
72
|
for hook in self.hooks:
|
|
62
73
|
try:
|
|
63
|
-
hook.on_finally(context, variable)
|
|
74
|
+
hook.on_finally(context, variable, variable_metadata)
|
|
64
75
|
except Exception as e:
|
|
65
76
|
logger.error(f"Error running finally hook: {e}")
|
|
66
77
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from devcycle_python_sdk.models.environment_metadata import EnvironmentMetadata
|
|
2
|
+
from devcycle_python_sdk.models.project_metadata import ProjectMetadata
|
|
3
|
+
from typing import Dict, Any, Optional
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ConfigMetadata:
|
|
9
|
+
project: ProjectMetadata
|
|
10
|
+
environment: EnvironmentMetadata
|
|
11
|
+
|
|
12
|
+
def to_json(self):
|
|
13
|
+
result = {}
|
|
14
|
+
for field_name in self.__dataclass_fields__:
|
|
15
|
+
value = getattr(self, field_name)
|
|
16
|
+
if value is not None:
|
|
17
|
+
if field_name == "project" and isinstance(value, ProjectMetadata):
|
|
18
|
+
result[field_name] = value.to_json()
|
|
19
|
+
elif field_name == "environment" and isinstance(
|
|
20
|
+
value, EnvironmentMetadata
|
|
21
|
+
):
|
|
22
|
+
result[field_name] = value.to_json()
|
|
23
|
+
else:
|
|
24
|
+
result[field_name] = value
|
|
25
|
+
return result
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def from_json(json_obj: Optional[Dict[str, Any]]) -> Optional["ConfigMetadata"]:
|
|
29
|
+
if json_obj is None:
|
|
30
|
+
return None
|
|
31
|
+
project = ProjectMetadata.from_json(json_obj.get("project"))
|
|
32
|
+
environment = EnvironmentMetadata.from_json(json_obj.get("environment"))
|
|
33
|
+
|
|
34
|
+
if project is None or environment is None:
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
return ConfigMetadata(
|
|
38
|
+
project=project,
|
|
39
|
+
environment=environment,
|
|
40
|
+
)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import Dict, Any, Optional
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class EnvironmentMetadata:
|
|
7
|
+
id: str
|
|
8
|
+
key: str
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def from_json(
|
|
12
|
+
json_obj: Optional[Dict[str, Any]],
|
|
13
|
+
) -> Optional["EnvironmentMetadata"]:
|
|
14
|
+
if json_obj is None:
|
|
15
|
+
return None
|
|
16
|
+
return EnvironmentMetadata(
|
|
17
|
+
id=json_obj["id"],
|
|
18
|
+
key=json_obj["key"],
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def to_json(self):
|
|
22
|
+
result = {}
|
|
23
|
+
for field_name in self.__dataclass_fields__:
|
|
24
|
+
value = getattr(self, field_name)
|
|
25
|
+
result[field_name] = value
|
|
26
|
+
return result
|
|
@@ -2,14 +2,17 @@ from typing import Callable, Optional
|
|
|
2
2
|
|
|
3
3
|
from devcycle_python_sdk.models.eval_hook_context import HookContext
|
|
4
4
|
from devcycle_python_sdk.models.variable import Variable
|
|
5
|
+
from devcycle_python_sdk.models.variable_metadata import VariableMetadata
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class EvalHook:
|
|
8
9
|
def __init__(
|
|
9
10
|
self,
|
|
10
11
|
before: Callable[[HookContext], Optional[HookContext]],
|
|
11
|
-
after: Callable[[HookContext, Variable], None],
|
|
12
|
-
on_finally: Callable[
|
|
12
|
+
after: Callable[[HookContext, Variable, Optional[VariableMetadata]], None],
|
|
13
|
+
on_finally: Callable[
|
|
14
|
+
[HookContext, Optional[Variable], Optional[VariableMetadata]], None
|
|
15
|
+
],
|
|
13
16
|
error: Callable[[HookContext, Exception], None],
|
|
14
17
|
):
|
|
15
18
|
self.before = before
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
from devcycle_python_sdk.models.user import DevCycleUser
|
|
5
|
+
from devcycle_python_sdk.models.config_metadata import ConfigMetadata
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class HookContext:
|
|
10
|
+
key: str
|
|
11
|
+
user: DevCycleUser
|
|
12
|
+
default_value: Any
|
|
13
|
+
config_metadata: Optional[ConfigMetadata] = None
|
|
14
|
+
|
|
15
|
+
def to_json(self):
|
|
16
|
+
result = {}
|
|
17
|
+
for field_name in self.__dataclass_fields__:
|
|
18
|
+
value = getattr(self, field_name)
|
|
19
|
+
if value is not None:
|
|
20
|
+
if field_name == "config_metadata" and isinstance(
|
|
21
|
+
value, ConfigMetadata
|
|
22
|
+
):
|
|
23
|
+
result[field_name] = value.to_json()
|
|
24
|
+
elif field_name == "user" and isinstance(value, DevCycleUser):
|
|
25
|
+
result[field_name] = value.to_json()
|
|
26
|
+
else:
|
|
27
|
+
result[field_name] = value
|
|
28
|
+
return result
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from typing import Dict, Any, Optional
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class ProjectMetadata:
|
|
7
|
+
id: str
|
|
8
|
+
key: str
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def from_json(json_obj: Optional[Dict[str, Any]]) -> Optional["ProjectMetadata"]:
|
|
12
|
+
if json_obj is None:
|
|
13
|
+
return None
|
|
14
|
+
return ProjectMetadata(
|
|
15
|
+
id=json_obj["id"],
|
|
16
|
+
key=json_obj["key"],
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
def to_json(self):
|
|
20
|
+
result = {}
|
|
21
|
+
for field_name in self.__dataclass_fields__:
|
|
22
|
+
value = getattr(self, field_name)
|
|
23
|
+
result[field_name] = value
|
|
24
|
+
return result
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from typing import Dict, Any, Optional
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class VariableMetadata:
|
|
7
|
+
feature_id: str
|
|
8
|
+
|
|
9
|
+
@staticmethod
|
|
10
|
+
def from_json(json_obj: Optional[Dict[str, Any]]) -> Optional["VariableMetadata"]:
|
|
11
|
+
if json_obj is None:
|
|
12
|
+
return None
|
|
13
|
+
return VariableMetadata(
|
|
14
|
+
feature_id=json_obj["feature_id"],
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
def to_json(self):
|
|
18
|
+
result = {}
|
|
19
|
+
for field_name in self.__dataclass_fields__:
|
|
20
|
+
value = getattr(self, field_name)
|
|
21
|
+
result[field_name] = value
|
|
22
|
+
return result
|
|
@@ -90,7 +90,7 @@ class DevCycleLocalOptions:
|
|
|
90
90
|
|
|
91
91
|
if self.event_request_chunk_size > self.max_event_queue_size:
|
|
92
92
|
logger.warning(
|
|
93
|
-
f"DevCycle: event_request_chunk_size: {self.event_request_chunk_size} must be smaller than max_event_queue_size: {
|
|
93
|
+
f"DevCycle: event_request_chunk_size: {self.event_request_chunk_size} must be smaller than max_event_queue_size: {self.max_event_queue_size}"
|
|
94
94
|
)
|
|
95
95
|
self.event_request_chunk_size = 100
|
|
96
96
|
|
|
@@ -34,11 +34,17 @@ def create_nullable_custom_data(val: Optional[dict]) -> pb2.NullableCustomData:
|
|
|
34
34
|
if value is None:
|
|
35
35
|
values[key] = pb2.CustomDataValue(type=pb2.CustomDataType.Null) # type: ignore
|
|
36
36
|
elif isinstance(value, bool):
|
|
37
|
-
values[key] = pb2.CustomDataValue(
|
|
37
|
+
values[key] = pb2.CustomDataValue(
|
|
38
|
+
type=pb2.CustomDataType.Bool, boolValue=value
|
|
39
|
+
) # type: ignore
|
|
38
40
|
elif isinstance(value, str):
|
|
39
|
-
values[key] = pb2.CustomDataValue(
|
|
41
|
+
values[key] = pb2.CustomDataValue(
|
|
42
|
+
type=pb2.CustomDataType.Str, stringValue=value
|
|
43
|
+
) # type: ignore
|
|
40
44
|
elif isinstance(value, (int, float)):
|
|
41
|
-
values[key] = pb2.CustomDataValue(
|
|
45
|
+
values[key] = pb2.CustomDataValue(
|
|
46
|
+
type=pb2.CustomDataType.Num, doubleValue=value
|
|
47
|
+
) # type: ignore
|
|
42
48
|
else:
|
|
43
49
|
logger.warning(
|
|
44
50
|
f"Custom Data contains data type that can't be written, will be ignored. Key: {key}, Type: {str(type(value))}"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# source: variableForUserParams.proto
|
|
4
|
+
"""Generated protocol buffer code."""
|
|
5
|
+
|
|
6
|
+
from google.protobuf import descriptor as _descriptor
|
|
7
|
+
from google.protobuf import descriptor_pool as _descriptor_pool
|
|
8
|
+
from google.protobuf import symbol_database as _symbol_database
|
|
9
|
+
from google.protobuf.internal import builder as _builder
|
|
10
|
+
# @@protoc_insertion_point(imports)
|
|
11
|
+
|
|
12
|
+
_sym_db = _symbol_database.Default()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
|
16
|
+
b'\n\x1bvariableForUserParams.proto"/\n\x0eNullableString\x12\r\n\x05value\x18\x01 \x01(\t\x12\x0e\n\x06isNull\x18\x02 \x01(\x08"/\n\x0eNullableDouble\x12\r\n\x05value\x18\x01 \x01(\x01\x12\x0e\n\x06isNull\x18\x02 \x01(\x08"m\n\x0f\x43ustomDataValue\x12\x1d\n\x04type\x18\x01 \x01(\x0e\x32\x0f.CustomDataType\x12\x11\n\tboolValue\x18\x02 \x01(\x08\x12\x13\n\x0b\x64oubleValue\x18\x03 \x01(\x01\x12\x13\n\x0bstringValue\x18\x04 \x01(\t"\x93\x01\n\x12NullableCustomData\x12-\n\x05value\x18\x01 \x03(\x0b\x32\x1e.NullableCustomData.ValueEntry\x12\x0e\n\x06isNull\x18\x02 \x01(\x08\x1a>\n\nValueEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1f\n\x05value\x18\x02 \x01(\x0b\x32\x10.CustomDataValue:\x02\x38\x01"\x9c\x01\n\x18VariableForUserParams_PB\x12\x0e\n\x06sdkKey\x18\x01 \x01(\t\x12\x13\n\x0bvariableKey\x18\x02 \x01(\t\x12&\n\x0cvariableType\x18\x03 \x01(\x0e\x32\x10.VariableType_PB\x12\x19\n\x04user\x18\x04 \x01(\x0b\x32\x0b.DVCUser_PB\x12\x18\n\x10shouldTrackEvent\x18\x05 \x01(\x08"\xe8\x02\n\nDVCUser_PB\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x1e\n\x05\x65mail\x18\x02 \x01(\x0b\x32\x0f.NullableString\x12\x1d\n\x04name\x18\x03 \x01(\x0b\x32\x0f.NullableString\x12!\n\x08language\x18\x04 \x01(\x0b\x32\x0f.NullableString\x12 \n\x07\x63ountry\x18\x05 \x01(\x0b\x32\x0f.NullableString\x12!\n\x08\x61ppBuild\x18\x06 \x01(\x0b\x32\x0f.NullableDouble\x12#\n\nappVersion\x18\x07 \x01(\x0b\x32\x0f.NullableString\x12$\n\x0b\x64\x65viceModel\x18\x08 \x01(\x0b\x32\x0f.NullableString\x12\'\n\ncustomData\x18\t \x01(\x0b\x32\x13.NullableCustomData\x12.\n\x11privateCustomData\x18\n \x01(\x0b\x32\x13.NullableCustomData"\xed\x01\n\x0eSDKVariable_PB\x12\x0b\n\x03_id\x18\x01 \x01(\t\x12\x1e\n\x04type\x18\x02 \x01(\x0e\x32\x10.VariableType_PB\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\x11\n\tboolValue\x18\x04 \x01(\x08\x12\x13\n\x0b\x64oubleValue\x18\x05 \x01(\x01\x12\x13\n\x0bstringValue\x18\x06 \x01(\t\x12#\n\nevalReason\x18\x07 \x01(\x0b\x32\x0f.NullableString\x12!\n\x08_feature\x18\x08 \x01(\x0b\x32\x0f.NullableString\x12\x1c\n\x04\x65val\x18\t \x01(\x0b\x32\x0e.EvalReason_PB"C\n\rEvalReason_PB\x12\x0e\n\x06reason\x18\x01 \x01(\t\x12\x0f\n\x07\x64\x65tails\x18\x02 \x01(\t\x12\x11\n\ttarget_id\x18\x03 \x01(\t*@\n\x0fVariableType_PB\x12\x0b\n\x07\x42oolean\x10\x00\x12\n\n\x06Number\x10\x01\x12\n\n\x06String\x10\x02\x12\x08\n\x04JSON\x10\x03*6\n\x0e\x43ustomDataType\x12\x08\n\x04\x42ool\x10\x00\x12\x07\n\x03Num\x10\x01\x12\x07\n\x03Str\x10\x02\x12\x08\n\x04Null\x10\x03\x42X\n&com.devcycle.sdk.server.local.protobufP\x01Z\x07./proto\xaa\x02"DevCycle.SDK.Server.Local.Protobufb\x06proto3'
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
_globals = globals()
|
|
20
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
21
|
+
_builder.BuildTopDescriptorsAndMessages(
|
|
22
|
+
DESCRIPTOR, "variableForUserParams_pb2", _globals
|
|
23
|
+
)
|
|
24
|
+
if _descriptor._USE_C_DESCRIPTORS == False:
|
|
25
|
+
DESCRIPTOR._options = None
|
|
26
|
+
DESCRIPTOR._serialized_options = b'\n&com.devcycle.sdk.server.local.protobufP\001Z\007./proto\252\002"DevCycle.SDK.Server.Local.Protobuf'
|
|
27
|
+
_NULLABLECUSTOMDATA_VALUEENTRY._options = None
|
|
28
|
+
_NULLABLECUSTOMDATA_VALUEENTRY._serialized_options = b"8\001"
|
|
29
|
+
_globals["_VARIABLETYPE_PB"]._serialized_start = 1221
|
|
30
|
+
_globals["_VARIABLETYPE_PB"]._serialized_end = 1285
|
|
31
|
+
_globals["_CUSTOMDATATYPE"]._serialized_start = 1287
|
|
32
|
+
_globals["_CUSTOMDATATYPE"]._serialized_end = 1341
|
|
33
|
+
_globals["_NULLABLESTRING"]._serialized_start = 31
|
|
34
|
+
_globals["_NULLABLESTRING"]._serialized_end = 78
|
|
35
|
+
_globals["_NULLABLEDOUBLE"]._serialized_start = 80
|
|
36
|
+
_globals["_NULLABLEDOUBLE"]._serialized_end = 127
|
|
37
|
+
_globals["_CUSTOMDATAVALUE"]._serialized_start = 129
|
|
38
|
+
_globals["_CUSTOMDATAVALUE"]._serialized_end = 238
|
|
39
|
+
_globals["_NULLABLECUSTOMDATA"]._serialized_start = 241
|
|
40
|
+
_globals["_NULLABLECUSTOMDATA"]._serialized_end = 388
|
|
41
|
+
_globals["_NULLABLECUSTOMDATA_VALUEENTRY"]._serialized_start = 326
|
|
42
|
+
_globals["_NULLABLECUSTOMDATA_VALUEENTRY"]._serialized_end = 388
|
|
43
|
+
_globals["_VARIABLEFORUSERPARAMS_PB"]._serialized_start = 391
|
|
44
|
+
_globals["_VARIABLEFORUSERPARAMS_PB"]._serialized_end = 547
|
|
45
|
+
_globals["_DVCUSER_PB"]._serialized_start = 550
|
|
46
|
+
_globals["_DVCUSER_PB"]._serialized_end = 910
|
|
47
|
+
_globals["_SDKVARIABLE_PB"]._serialized_start = 913
|
|
48
|
+
_globals["_SDKVARIABLE_PB"]._serialized_end = 1150
|
|
49
|
+
_globals["_EVALREASON_PB"]._serialized_start = 1152
|
|
50
|
+
_globals["_EVALREASON_PB"]._serialized_end = 1219
|
|
51
|
+
# @@protoc_insertion_point(module_scope)
|
|
@@ -7,14 +7,14 @@ from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Opti
|
|
|
7
7
|
DESCRIPTOR: _descriptor.FileDescriptor
|
|
8
8
|
|
|
9
9
|
class VariableType_PB(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
|
10
|
-
__slots__ =
|
|
10
|
+
__slots__ = []
|
|
11
11
|
Boolean: _ClassVar[VariableType_PB]
|
|
12
12
|
Number: _ClassVar[VariableType_PB]
|
|
13
13
|
String: _ClassVar[VariableType_PB]
|
|
14
14
|
JSON: _ClassVar[VariableType_PB]
|
|
15
15
|
|
|
16
16
|
class CustomDataType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
|
17
|
-
__slots__ =
|
|
17
|
+
__slots__ = []
|
|
18
18
|
Bool: _ClassVar[CustomDataType]
|
|
19
19
|
Num: _ClassVar[CustomDataType]
|
|
20
20
|
Str: _ClassVar[CustomDataType]
|
|
@@ -29,7 +29,7 @@ Str: CustomDataType
|
|
|
29
29
|
Null: CustomDataType
|
|
30
30
|
|
|
31
31
|
class NullableString(_message.Message):
|
|
32
|
-
__slots__ =
|
|
32
|
+
__slots__ = ["value", "isNull"]
|
|
33
33
|
VALUE_FIELD_NUMBER: _ClassVar[int]
|
|
34
34
|
ISNULL_FIELD_NUMBER: _ClassVar[int]
|
|
35
35
|
value: str
|
|
@@ -37,7 +37,7 @@ class NullableString(_message.Message):
|
|
|
37
37
|
def __init__(self, value: _Optional[str] = ..., isNull: bool = ...) -> None: ...
|
|
38
38
|
|
|
39
39
|
class NullableDouble(_message.Message):
|
|
40
|
-
__slots__ =
|
|
40
|
+
__slots__ = ["value", "isNull"]
|
|
41
41
|
VALUE_FIELD_NUMBER: _ClassVar[int]
|
|
42
42
|
ISNULL_FIELD_NUMBER: _ClassVar[int]
|
|
43
43
|
value: float
|
|
@@ -45,7 +45,7 @@ class NullableDouble(_message.Message):
|
|
|
45
45
|
def __init__(self, value: _Optional[float] = ..., isNull: bool = ...) -> None: ...
|
|
46
46
|
|
|
47
47
|
class CustomDataValue(_message.Message):
|
|
48
|
-
__slots__ =
|
|
48
|
+
__slots__ = ["type", "boolValue", "doubleValue", "stringValue"]
|
|
49
49
|
TYPE_FIELD_NUMBER: _ClassVar[int]
|
|
50
50
|
BOOLVALUE_FIELD_NUMBER: _ClassVar[int]
|
|
51
51
|
DOUBLEVALUE_FIELD_NUMBER: _ClassVar[int]
|
|
@@ -57,9 +57,9 @@ class CustomDataValue(_message.Message):
|
|
|
57
57
|
def __init__(self, type: _Optional[_Union[CustomDataType, str]] = ..., boolValue: bool = ..., doubleValue: _Optional[float] = ..., stringValue: _Optional[str] = ...) -> None: ...
|
|
58
58
|
|
|
59
59
|
class NullableCustomData(_message.Message):
|
|
60
|
-
__slots__ =
|
|
60
|
+
__slots__ = ["value", "isNull"]
|
|
61
61
|
class ValueEntry(_message.Message):
|
|
62
|
-
__slots__ =
|
|
62
|
+
__slots__ = ["key", "value"]
|
|
63
63
|
KEY_FIELD_NUMBER: _ClassVar[int]
|
|
64
64
|
VALUE_FIELD_NUMBER: _ClassVar[int]
|
|
65
65
|
key: str
|
|
@@ -72,7 +72,7 @@ class NullableCustomData(_message.Message):
|
|
|
72
72
|
def __init__(self, value: _Optional[_Mapping[str, CustomDataValue]] = ..., isNull: bool = ...) -> None: ...
|
|
73
73
|
|
|
74
74
|
class VariableForUserParams_PB(_message.Message):
|
|
75
|
-
__slots__ =
|
|
75
|
+
__slots__ = ["sdkKey", "variableKey", "variableType", "user", "shouldTrackEvent"]
|
|
76
76
|
SDKKEY_FIELD_NUMBER: _ClassVar[int]
|
|
77
77
|
VARIABLEKEY_FIELD_NUMBER: _ClassVar[int]
|
|
78
78
|
VARIABLETYPE_FIELD_NUMBER: _ClassVar[int]
|
|
@@ -86,7 +86,7 @@ class VariableForUserParams_PB(_message.Message):
|
|
|
86
86
|
def __init__(self, sdkKey: _Optional[str] = ..., variableKey: _Optional[str] = ..., variableType: _Optional[_Union[VariableType_PB, str]] = ..., user: _Optional[_Union[DVCUser_PB, _Mapping]] = ..., shouldTrackEvent: bool = ...) -> None: ...
|
|
87
87
|
|
|
88
88
|
class DVCUser_PB(_message.Message):
|
|
89
|
-
__slots__ =
|
|
89
|
+
__slots__ = ["user_id", "email", "name", "language", "country", "appBuild", "appVersion", "deviceModel", "customData", "privateCustomData"]
|
|
90
90
|
USER_ID_FIELD_NUMBER: _ClassVar[int]
|
|
91
91
|
EMAIL_FIELD_NUMBER: _ClassVar[int]
|
|
92
92
|
NAME_FIELD_NUMBER: _ClassVar[int]
|
|
@@ -110,7 +110,7 @@ class DVCUser_PB(_message.Message):
|
|
|
110
110
|
def __init__(self, user_id: _Optional[str] = ..., email: _Optional[_Union[NullableString, _Mapping]] = ..., name: _Optional[_Union[NullableString, _Mapping]] = ..., language: _Optional[_Union[NullableString, _Mapping]] = ..., country: _Optional[_Union[NullableString, _Mapping]] = ..., appBuild: _Optional[_Union[NullableDouble, _Mapping]] = ..., appVersion: _Optional[_Union[NullableString, _Mapping]] = ..., deviceModel: _Optional[_Union[NullableString, _Mapping]] = ..., customData: _Optional[_Union[NullableCustomData, _Mapping]] = ..., privateCustomData: _Optional[_Union[NullableCustomData, _Mapping]] = ...) -> None: ...
|
|
111
111
|
|
|
112
112
|
class SDKVariable_PB(_message.Message):
|
|
113
|
-
__slots__ =
|
|
113
|
+
__slots__ = ["_id", "type", "key", "boolValue", "doubleValue", "stringValue", "evalReason", "_feature", "eval"]
|
|
114
114
|
_ID_FIELD_NUMBER: _ClassVar[int]
|
|
115
115
|
TYPE_FIELD_NUMBER: _ClassVar[int]
|
|
116
116
|
KEY_FIELD_NUMBER: _ClassVar[int]
|
|
@@ -132,7 +132,7 @@ class SDKVariable_PB(_message.Message):
|
|
|
132
132
|
def __init__(self, _id: _Optional[str] = ..., type: _Optional[_Union[VariableType_PB, str]] = ..., key: _Optional[str] = ..., boolValue: bool = ..., doubleValue: _Optional[float] = ..., stringValue: _Optional[str] = ..., evalReason: _Optional[_Union[NullableString, _Mapping]] = ..., _feature: _Optional[_Union[NullableString, _Mapping]] = ..., eval: _Optional[_Union[EvalReason_PB, _Mapping]] = ...) -> None: ...
|
|
133
133
|
|
|
134
134
|
class EvalReason_PB(_message.Message):
|
|
135
|
-
__slots__ =
|
|
135
|
+
__slots__ = ["reason", "details", "target_id"]
|
|
136
136
|
REASON_FIELD_NUMBER: _ClassVar[int]
|
|
137
137
|
DETAILS_FIELD_NUMBER: _ClassVar[int]
|
|
138
138
|
TARGET_ID_FIELD_NUMBER: _ClassVar[int]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devcycle-python-server-sdk
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.13.0
|
|
4
4
|
Summary: DevCycle Python SDK
|
|
5
5
|
Home-page: https://github.com/devcycleHQ/python-server-sdk
|
|
6
6
|
Author-email:
|
|
@@ -12,7 +12,7 @@ Requires-Dist: urllib3>=1.15.1
|
|
|
12
12
|
Requires-Dist: requests>=2.32
|
|
13
13
|
Requires-Dist: wasmtime~=30.0.0
|
|
14
14
|
Requires-Dist: protobuf>=4.23.3
|
|
15
|
-
Requires-Dist: openfeature-sdk
|
|
15
|
+
Requires-Dist: openfeature-sdk==0.8.0
|
|
16
16
|
Requires-Dist: launchdarkly-eventsource>=1.2.1
|
|
17
17
|
Requires-Dist: responses>=0.23.1
|
|
18
18
|
Dynamic: description
|
|
@@ -25,6 +25,8 @@ devcycle_python_sdk/managers/event_queue_manager.py
|
|
|
25
25
|
devcycle_python_sdk/managers/sse_manager.py
|
|
26
26
|
devcycle_python_sdk/models/__init__.py
|
|
27
27
|
devcycle_python_sdk/models/bucketed_config.py
|
|
28
|
+
devcycle_python_sdk/models/config_metadata.py
|
|
29
|
+
devcycle_python_sdk/models/environment_metadata.py
|
|
28
30
|
devcycle_python_sdk/models/error_response.py
|
|
29
31
|
devcycle_python_sdk/models/eval_hook.py
|
|
30
32
|
devcycle_python_sdk/models/eval_hook_context.py
|
|
@@ -32,8 +34,10 @@ devcycle_python_sdk/models/eval_reason.py
|
|
|
32
34
|
devcycle_python_sdk/models/event.py
|
|
33
35
|
devcycle_python_sdk/models/feature.py
|
|
34
36
|
devcycle_python_sdk/models/platform_data.py
|
|
37
|
+
devcycle_python_sdk/models/project_metadata.py
|
|
35
38
|
devcycle_python_sdk/models/user.py
|
|
36
39
|
devcycle_python_sdk/models/variable.py
|
|
40
|
+
devcycle_python_sdk/models/variable_metadata.py
|
|
37
41
|
devcycle_python_sdk/open_feature_provider/__init__.py
|
|
38
42
|
devcycle_python_sdk/open_feature_provider/provider.py
|
|
39
43
|
devcycle_python_sdk/protobuf/__init__.py
|
|
@@ -98,7 +98,7 @@ class LocalBucketingTest(unittest.TestCase):
|
|
|
98
98
|
self.local_bucketing.set_platform_data(platform_json)
|
|
99
99
|
self.local_bucketing.init_event_queue(self.client_uuid, "{}")
|
|
100
100
|
user = DevCycleUser(user_id="test_user_id")
|
|
101
|
-
result = self.local_bucketing.get_variable_for_user_protobuf(
|
|
101
|
+
result, feature_id = self.local_bucketing.get_variable_for_user_protobuf(
|
|
102
102
|
user=user, key="string-var", default_value="default value"
|
|
103
103
|
)
|
|
104
104
|
self.assertIsNotNone(result)
|
|
@@ -106,6 +106,7 @@ class LocalBucketingTest(unittest.TestCase):
|
|
|
106
106
|
self.assertEqual(result.type, TypeEnum.STRING)
|
|
107
107
|
self.assertEqual(result.value, "variationOn")
|
|
108
108
|
self.assertFalse(result.isDefaulted)
|
|
109
|
+
self.assertIsNotNone(feature_id)
|
|
109
110
|
|
|
110
111
|
def test_get_variable_for_user_protobuf_special_characters(self):
|
|
111
112
|
self.local_bucketing.store_config(special_character_config())
|
|
@@ -113,7 +114,7 @@ class LocalBucketingTest(unittest.TestCase):
|
|
|
113
114
|
self.local_bucketing.set_platform_data(platform_json)
|
|
114
115
|
self.local_bucketing.init_event_queue(self.client_uuid, "{}")
|
|
115
116
|
user = DevCycleUser(user_id="test_user_id")
|
|
116
|
-
result = self.local_bucketing.get_variable_for_user_protobuf(
|
|
117
|
+
result, feature_id = self.local_bucketing.get_variable_for_user_protobuf(
|
|
117
118
|
user=user, key="string-var", default_value="default value"
|
|
118
119
|
)
|
|
119
120
|
self.assertIsNotNone(result)
|
|
@@ -121,6 +122,7 @@ class LocalBucketingTest(unittest.TestCase):
|
|
|
121
122
|
self.assertEqual(result.type, TypeEnum.STRING)
|
|
122
123
|
self.assertEqual(result.value, "öé 🐍 ¥ variationOn")
|
|
123
124
|
self.assertFalse(result.isDefaulted)
|
|
125
|
+
self.assertIsNotNone(feature_id)
|
|
124
126
|
|
|
125
127
|
def test_get_variable_for_user_protobuf_type_mismatch(self):
|
|
126
128
|
self.local_bucketing.store_config(small_config())
|
|
@@ -131,10 +133,11 @@ class LocalBucketingTest(unittest.TestCase):
|
|
|
131
133
|
|
|
132
134
|
# type mismatch is handled inside the WASM and will return
|
|
133
135
|
# no data if the type is not correct
|
|
134
|
-
result = self.local_bucketing.get_variable_for_user_protobuf(
|
|
136
|
+
result, feature_id = self.local_bucketing.get_variable_for_user_protobuf(
|
|
135
137
|
user=user, key="string-var", default_value=9999
|
|
136
138
|
)
|
|
137
139
|
self.assertIsNone(result)
|
|
140
|
+
self.assertIsNone(feature_id)
|
|
138
141
|
|
|
139
142
|
def test_generate_bucketed_config(self):
|
|
140
143
|
self.local_bucketing.store_config(small_config())
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/test_cloud_client.py
RENAMED
|
@@ -5,7 +5,6 @@ import uuid
|
|
|
5
5
|
from time import time
|
|
6
6
|
from unittest.mock import patch
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
from devcycle_python_sdk import DevCycleCloudClient, DevCycleCloudOptions
|
|
10
9
|
from devcycle_python_sdk.models.eval_hook import EvalHook
|
|
11
10
|
from devcycle_python_sdk.models.user import DevCycleUser
|
|
@@ -99,7 +98,7 @@ class DevCycleCloudClientTest(unittest.TestCase):
|
|
|
99
98
|
self.assertEqual(result.value, "default_value")
|
|
100
99
|
self.assertTrue(result.isDefaulted)
|
|
101
100
|
self.assertEqual(result.eval.reason, "DEFAULT")
|
|
102
|
-
self.assertEqual(result.eval.details, "
|
|
101
|
+
self.assertEqual(result.eval.details, "Error")
|
|
103
102
|
|
|
104
103
|
# other exception - return default
|
|
105
104
|
mock_variable_call.reset_mock()
|
|
@@ -307,10 +306,10 @@ class DevCycleCloudClientTest(unittest.TestCase):
|
|
|
307
306
|
hook_called["before"] = True
|
|
308
307
|
return context
|
|
309
308
|
|
|
310
|
-
def after_hook(context, variable):
|
|
309
|
+
def after_hook(context, variable, variable_metadata):
|
|
311
310
|
hook_called["after"] = True
|
|
312
311
|
|
|
313
|
-
def finally_hook(context, variable):
|
|
312
|
+
def finally_hook(context, variable, variable_metadata):
|
|
314
313
|
hook_called["finally"] = True
|
|
315
314
|
|
|
316
315
|
def error_hook(context, error):
|
|
@@ -347,10 +346,10 @@ class DevCycleCloudClientTest(unittest.TestCase):
|
|
|
347
346
|
hook_called["before"] = True
|
|
348
347
|
raise Exception("Before hook failed")
|
|
349
348
|
|
|
350
|
-
def after_hook(context, variable):
|
|
349
|
+
def after_hook(context, variable, variable_metadata):
|
|
351
350
|
hook_called["after"] = True
|
|
352
351
|
|
|
353
|
-
def finally_hook(context, variable):
|
|
352
|
+
def finally_hook(context, variable, variable_metadata):
|
|
354
353
|
hook_called["finally"] = True
|
|
355
354
|
|
|
356
355
|
def error_hook(context, error):
|
|
@@ -370,6 +369,42 @@ class DevCycleCloudClientTest(unittest.TestCase):
|
|
|
370
369
|
self.assertTrue(hook_called["finally"])
|
|
371
370
|
self.assertTrue(hook_called["error"])
|
|
372
371
|
|
|
372
|
+
@patch("devcycle_python_sdk.api.bucketing_client.BucketingAPIClient.variable")
|
|
373
|
+
def test_context_has_null_config_metadata(self, mock_variable_call):
|
|
374
|
+
mock_variable_call.return_value = Variable(
|
|
375
|
+
_id="123", key="strKey", value=999, type=TypeEnum.NUMBER
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
context_received = None
|
|
379
|
+
|
|
380
|
+
def before_hook(context):
|
|
381
|
+
nonlocal context_received
|
|
382
|
+
context_received = context
|
|
383
|
+
return context
|
|
384
|
+
|
|
385
|
+
def after_hook(context, variable, variable_metadata):
|
|
386
|
+
pass
|
|
387
|
+
|
|
388
|
+
def finally_hook(context, variable, variable_metadata):
|
|
389
|
+
pass
|
|
390
|
+
|
|
391
|
+
def error_hook(context, error):
|
|
392
|
+
pass
|
|
393
|
+
|
|
394
|
+
self.test_client.add_hook(
|
|
395
|
+
EvalHook(before_hook, after_hook, finally_hook, error_hook)
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
# Test that context has config_metadata field but it's null for cloud client
|
|
399
|
+
variable = self.test_client.variable(self.test_user, "strKey", 42)
|
|
400
|
+
|
|
401
|
+
# Verify the variable evaluation worked
|
|
402
|
+
self.assertIsNotNone(variable)
|
|
403
|
+
self.assertIsNotNone(context_received)
|
|
404
|
+
self.assertTrue(hasattr(context_received, "config_metadata"))
|
|
405
|
+
# Cloud client should have null config_metadata since it's not implemented
|
|
406
|
+
self.assertIsNone(context_received.config_metadata)
|
|
407
|
+
|
|
373
408
|
|
|
374
409
|
if __name__ == "__main__":
|
|
375
410
|
unittest.main()
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/test_local_client.py
RENAMED
|
@@ -392,10 +392,10 @@ class DevCycleLocalClientTest(unittest.TestCase):
|
|
|
392
392
|
hook_called["before"] = True
|
|
393
393
|
return context
|
|
394
394
|
|
|
395
|
-
def after_hook(context, variable):
|
|
395
|
+
def after_hook(context, variable, variable_metadata):
|
|
396
396
|
hook_called["after"] = True
|
|
397
397
|
|
|
398
|
-
def finally_hook(context, variable):
|
|
398
|
+
def finally_hook(context, variable, variable_metadata):
|
|
399
399
|
hook_called["finally"] = True
|
|
400
400
|
|
|
401
401
|
def error_hook(context, error):
|
|
@@ -432,10 +432,10 @@ class DevCycleLocalClientTest(unittest.TestCase):
|
|
|
432
432
|
hook_called["before"] = True
|
|
433
433
|
raise Exception("Before hook failed")
|
|
434
434
|
|
|
435
|
-
def after_hook(context, variable):
|
|
435
|
+
def after_hook(context, variable, variable_metadata):
|
|
436
436
|
hook_called["after"] = True
|
|
437
437
|
|
|
438
|
-
def finally_hook(context, variable):
|
|
438
|
+
def finally_hook(context, variable, variable_metadata):
|
|
439
439
|
hook_called["finally"] = True
|
|
440
440
|
|
|
441
441
|
def error_hook(context, error):
|
|
@@ -457,6 +457,55 @@ class DevCycleLocalClientTest(unittest.TestCase):
|
|
|
457
457
|
self.assertTrue(hook_called["finally"])
|
|
458
458
|
self.assertTrue(hook_called["error"])
|
|
459
459
|
|
|
460
|
+
@responses.activate
|
|
461
|
+
def test_context_has_config_metadata(self):
|
|
462
|
+
self.setup_client()
|
|
463
|
+
|
|
464
|
+
context_received = None
|
|
465
|
+
|
|
466
|
+
def before_hook(context):
|
|
467
|
+
nonlocal context_received
|
|
468
|
+
context_received = context
|
|
469
|
+
return context
|
|
470
|
+
|
|
471
|
+
def after_hook(context, variable, variable_metadata):
|
|
472
|
+
pass
|
|
473
|
+
|
|
474
|
+
def finally_hook(context, variable, variable_metadata):
|
|
475
|
+
pass
|
|
476
|
+
|
|
477
|
+
def error_hook(context, error):
|
|
478
|
+
pass
|
|
479
|
+
|
|
480
|
+
self.client.add_hook(
|
|
481
|
+
EvalHook(before_hook, after_hook, finally_hook, error_hook)
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
user = DevCycleUser(user_id="1234")
|
|
485
|
+
|
|
486
|
+
# Test that context has config_metadata field
|
|
487
|
+
variable = self.client.variable(user, "num-var", 42)
|
|
488
|
+
|
|
489
|
+
# Verify the variable evaluation worked
|
|
490
|
+
self.assertIsNotNone(variable)
|
|
491
|
+
self.assertIsNotNone(context_received)
|
|
492
|
+
self.assertTrue(hasattr(context_received, "config_metadata"))
|
|
493
|
+
# For local client, config_metadata should be populated
|
|
494
|
+
self.assertIsNotNone(context_received.config_metadata)
|
|
495
|
+
self.assertTrue(hasattr(context_received.config_metadata, "project"))
|
|
496
|
+
self.assertTrue(hasattr(context_received.config_metadata, "environment"))
|
|
497
|
+
# Verify the project and environment data
|
|
498
|
+
self.assertEqual(
|
|
499
|
+
context_received.config_metadata.project.id, "61f97628ff4afcb6d057dbf0"
|
|
500
|
+
)
|
|
501
|
+
self.assertEqual(context_received.config_metadata.project.key, "emma-project")
|
|
502
|
+
self.assertEqual(
|
|
503
|
+
context_received.config_metadata.environment.id, "61f97628ff4afcb6d057dbf2"
|
|
504
|
+
)
|
|
505
|
+
self.assertEqual(
|
|
506
|
+
context_received.config_metadata.environment.key, "development"
|
|
507
|
+
)
|
|
508
|
+
|
|
460
509
|
|
|
461
510
|
def _benchmark_variable_call(client: DevCycleLocalClient, user: DevCycleUser, key: str):
|
|
462
511
|
return client.variable(user, key, "default_value")
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.12.0
|
|
Binary file
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
-
# NO CHECKED-IN PROTOBUF GENCODE
|
|
4
|
-
# source: variableForUserParams.proto
|
|
5
|
-
# Protobuf Python Version: 5.29.3
|
|
6
|
-
"""Generated protocol buffer code."""
|
|
7
|
-
from google.protobuf import descriptor as _descriptor
|
|
8
|
-
from google.protobuf import descriptor_pool as _descriptor_pool
|
|
9
|
-
from google.protobuf import runtime_version as _runtime_version
|
|
10
|
-
from google.protobuf import symbol_database as _symbol_database
|
|
11
|
-
from google.protobuf.internal import builder as _builder
|
|
12
|
-
_runtime_version.ValidateProtobufRuntimeVersion(
|
|
13
|
-
_runtime_version.Domain.PUBLIC,
|
|
14
|
-
5,
|
|
15
|
-
29,
|
|
16
|
-
3,
|
|
17
|
-
'',
|
|
18
|
-
'variableForUserParams.proto'
|
|
19
|
-
)
|
|
20
|
-
# @@protoc_insertion_point(imports)
|
|
21
|
-
|
|
22
|
-
_sym_db = _symbol_database.Default()
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bvariableForUserParams.proto\"/\n\x0eNullableString\x12\r\n\x05value\x18\x01 \x01(\t\x12\x0e\n\x06isNull\x18\x02 \x01(\x08\"/\n\x0eNullableDouble\x12\r\n\x05value\x18\x01 \x01(\x01\x12\x0e\n\x06isNull\x18\x02 \x01(\x08\"m\n\x0f\x43ustomDataValue\x12\x1d\n\x04type\x18\x01 \x01(\x0e\x32\x0f.CustomDataType\x12\x11\n\tboolValue\x18\x02 \x01(\x08\x12\x13\n\x0b\x64oubleValue\x18\x03 \x01(\x01\x12\x13\n\x0bstringValue\x18\x04 \x01(\t\"\x93\x01\n\x12NullableCustomData\x12-\n\x05value\x18\x01 \x03(\x0b\x32\x1e.NullableCustomData.ValueEntry\x12\x0e\n\x06isNull\x18\x02 \x01(\x08\x1a>\n\nValueEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1f\n\x05value\x18\x02 \x01(\x0b\x32\x10.CustomDataValue:\x02\x38\x01\"\x9c\x01\n\x18VariableForUserParams_PB\x12\x0e\n\x06sdkKey\x18\x01 \x01(\t\x12\x13\n\x0bvariableKey\x18\x02 \x01(\t\x12&\n\x0cvariableType\x18\x03 \x01(\x0e\x32\x10.VariableType_PB\x12\x19\n\x04user\x18\x04 \x01(\x0b\x32\x0b.DVCUser_PB\x12\x18\n\x10shouldTrackEvent\x18\x05 \x01(\x08\"\xe8\x02\n\nDVCUser_PB\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x1e\n\x05\x65mail\x18\x02 \x01(\x0b\x32\x0f.NullableString\x12\x1d\n\x04name\x18\x03 \x01(\x0b\x32\x0f.NullableString\x12!\n\x08language\x18\x04 \x01(\x0b\x32\x0f.NullableString\x12 \n\x07\x63ountry\x18\x05 \x01(\x0b\x32\x0f.NullableString\x12!\n\x08\x61ppBuild\x18\x06 \x01(\x0b\x32\x0f.NullableDouble\x12#\n\nappVersion\x18\x07 \x01(\x0b\x32\x0f.NullableString\x12$\n\x0b\x64\x65viceModel\x18\x08 \x01(\x0b\x32\x0f.NullableString\x12\'\n\ncustomData\x18\t \x01(\x0b\x32\x13.NullableCustomData\x12.\n\x11privateCustomData\x18\n \x01(\x0b\x32\x13.NullableCustomData\"\xed\x01\n\x0eSDKVariable_PB\x12\x0b\n\x03_id\x18\x01 \x01(\t\x12\x1e\n\x04type\x18\x02 \x01(\x0e\x32\x10.VariableType_PB\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\x11\n\tboolValue\x18\x04 \x01(\x08\x12\x13\n\x0b\x64oubleValue\x18\x05 \x01(\x01\x12\x13\n\x0bstringValue\x18\x06 \x01(\t\x12#\n\nevalReason\x18\x07 \x01(\x0b\x32\x0f.NullableString\x12!\n\x08_feature\x18\x08 \x01(\x0b\x32\x0f.NullableString\x12\x1c\n\x04\x65val\x18\t \x01(\x0b\x32\x0e.EvalReason_PB\"C\n\rEvalReason_PB\x12\x0e\n\x06reason\x18\x01 \x01(\t\x12\x0f\n\x07\x64\x65tails\x18\x02 \x01(\t\x12\x11\n\ttarget_id\x18\x03 \x01(\t*@\n\x0fVariableType_PB\x12\x0b\n\x07\x42oolean\x10\x00\x12\n\n\x06Number\x10\x01\x12\n\n\x06String\x10\x02\x12\x08\n\x04JSON\x10\x03*6\n\x0e\x43ustomDataType\x12\x08\n\x04\x42ool\x10\x00\x12\x07\n\x03Num\x10\x01\x12\x07\n\x03Str\x10\x02\x12\x08\n\x04Null\x10\x03\x42X\n&com.devcycle.sdk.server.local.protobufP\x01Z\x07./proto\xaa\x02\"DevCycle.SDK.Server.Local.Protobufb\x06proto3')
|
|
28
|
-
|
|
29
|
-
_globals = globals()
|
|
30
|
-
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
31
|
-
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'variableForUserParams_pb2', _globals)
|
|
32
|
-
if not _descriptor._USE_C_DESCRIPTORS:
|
|
33
|
-
_globals['DESCRIPTOR']._loaded_options = None
|
|
34
|
-
_globals['DESCRIPTOR']._serialized_options = b'\n&com.devcycle.sdk.server.local.protobufP\001Z\007./proto\252\002\"DevCycle.SDK.Server.Local.Protobuf'
|
|
35
|
-
_globals['_NULLABLECUSTOMDATA_VALUEENTRY']._loaded_options = None
|
|
36
|
-
_globals['_NULLABLECUSTOMDATA_VALUEENTRY']._serialized_options = b'8\001'
|
|
37
|
-
_globals['_VARIABLETYPE_PB']._serialized_start=1221
|
|
38
|
-
_globals['_VARIABLETYPE_PB']._serialized_end=1285
|
|
39
|
-
_globals['_CUSTOMDATATYPE']._serialized_start=1287
|
|
40
|
-
_globals['_CUSTOMDATATYPE']._serialized_end=1341
|
|
41
|
-
_globals['_NULLABLESTRING']._serialized_start=31
|
|
42
|
-
_globals['_NULLABLESTRING']._serialized_end=78
|
|
43
|
-
_globals['_NULLABLEDOUBLE']._serialized_start=80
|
|
44
|
-
_globals['_NULLABLEDOUBLE']._serialized_end=127
|
|
45
|
-
_globals['_CUSTOMDATAVALUE']._serialized_start=129
|
|
46
|
-
_globals['_CUSTOMDATAVALUE']._serialized_end=238
|
|
47
|
-
_globals['_NULLABLECUSTOMDATA']._serialized_start=241
|
|
48
|
-
_globals['_NULLABLECUSTOMDATA']._serialized_end=388
|
|
49
|
-
_globals['_NULLABLECUSTOMDATA_VALUEENTRY']._serialized_start=326
|
|
50
|
-
_globals['_NULLABLECUSTOMDATA_VALUEENTRY']._serialized_end=388
|
|
51
|
-
_globals['_VARIABLEFORUSERPARAMS_PB']._serialized_start=391
|
|
52
|
-
_globals['_VARIABLEFORUSERPARAMS_PB']._serialized_end=547
|
|
53
|
-
_globals['_DVCUSER_PB']._serialized_start=550
|
|
54
|
-
_globals['_DVCUSER_PB']._serialized_end=910
|
|
55
|
-
_globals['_SDKVARIABLE_PB']._serialized_start=913
|
|
56
|
-
_globals['_SDKVARIABLE_PB']._serialized_end=1150
|
|
57
|
-
_globals['_EVALREASON_PB']._serialized_start=1152
|
|
58
|
-
_globals['_EVALREASON_PB']._serialized_end=1219
|
|
59
|
-
# @@protoc_insertion_point(module_scope)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/devcycle_python_sdk/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/api/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/fixture/__init__.py
RENAMED
|
File without changes
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/fixture/data.py
RENAMED
|
File without changes
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/managers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/models/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/util/__init__.py
RENAMED
|
File without changes
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/util/test_strings.py
RENAMED
|
File without changes
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/util/test_utils.py
RENAMED
|
File without changes
|
{devcycle_python_server_sdk-3.12.0 → devcycle_python_server_sdk-3.13.0}/test/util/test_version.py
RENAMED
|
File without changes
|