devcycle-python-server-sdk 3.11.3__py3-none-any.whl → 3.12.0__py3-none-any.whl

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 (30) hide show
  1. devcycle_python_sdk/VERSION.txt +1 -1
  2. devcycle_python_sdk/api/bucketing_client.py +12 -0
  3. devcycle_python_sdk/api/local_bucketing.py +0 -8
  4. devcycle_python_sdk/bucketing-lib.release.wasm +0 -0
  5. devcycle_python_sdk/cloud_client.py +51 -4
  6. devcycle_python_sdk/local_client.py +65 -14
  7. devcycle_python_sdk/managers/eval_hooks_manager.py +73 -0
  8. devcycle_python_sdk/managers/sse_manager.py +1 -1
  9. devcycle_python_sdk/models/bucketed_config.py +0 -1
  10. devcycle_python_sdk/models/eval_hook.py +18 -0
  11. devcycle_python_sdk/models/eval_hook_context.py +10 -0
  12. devcycle_python_sdk/models/eval_reason.py +40 -0
  13. devcycle_python_sdk/models/user.py +16 -4
  14. devcycle_python_sdk/models/variable.py +44 -6
  15. devcycle_python_sdk/open_feature_provider/provider.py +10 -5
  16. devcycle_python_sdk/options.py +8 -1
  17. devcycle_python_sdk/protobuf/utils.py +18 -0
  18. devcycle_python_sdk/protobuf/variableForUserParams_pb2.py +43 -30
  19. devcycle_python_sdk/protobuf/variableForUserParams_pb2.pyi +100 -78
  20. {devcycle_python_server_sdk-3.11.3.dist-info → devcycle_python_server_sdk-3.12.0.dist-info}/METADATA +1 -1
  21. {devcycle_python_server_sdk-3.11.3.dist-info → devcycle_python_server_sdk-3.12.0.dist-info}/RECORD +30 -26
  22. test/api/test_local_bucketing.py +11 -0
  23. test/models/test_user.py +90 -0
  24. test/openfeature_test/test_provider.py +79 -2
  25. test/openfeature_test/test_provider_local_sdk.py +25 -0
  26. test/test_cloud_client.py +89 -0
  27. test/test_local_client.py +97 -1
  28. {devcycle_python_server_sdk-3.11.3.dist-info → devcycle_python_server_sdk-3.12.0.dist-info}/WHEEL +0 -0
  29. {devcycle_python_server_sdk-3.11.3.dist-info → devcycle_python_server_sdk-3.12.0.dist-info}/licenses/LICENSE +0 -0
  30. {devcycle_python_server_sdk-3.11.3.dist-info → devcycle_python_server_sdk-3.12.0.dist-info}/top_level.txt +0 -0
@@ -5,6 +5,7 @@ import math
5
5
  from typing import Any, Optional
6
6
 
7
7
  from devcycle_python_sdk.models.variable import TypeEnum, Variable
8
+ from devcycle_python_sdk.models.eval_reason import EvalReason
8
9
  from devcycle_python_sdk.models.user import DevCycleUser
9
10
 
10
11
  import devcycle_python_sdk.protobuf.variableForUserParams_pb2 as pb2
@@ -82,7 +83,20 @@ def create_dvcuser_pb(user: DevCycleUser) -> pb2.DVCUser_PB: # type: ignore
82
83
  )
83
84
 
84
85
 
86
+ def create_eval_reason_from_pb(eval_reason_pb: pb2.EvalReason_PB) -> EvalReason: # type: ignore
87
+ """Convert EvalReason_PB protobuf message to EvalReason object"""
88
+ return EvalReason(
89
+ reason=eval_reason_pb.reason,
90
+ details=eval_reason_pb.details if eval_reason_pb.details else None,
91
+ target_id=eval_reason_pb.target_id if eval_reason_pb.target_id else None,
92
+ )
93
+
94
+
85
95
  def create_variable(sdk_variable: pb2.SDKVariable_PB, default_value: Any) -> Variable: # type: ignore
96
+ eval_reason_obj = None
97
+ if sdk_variable.HasField("eval"):
98
+ eval_reason_obj = create_eval_reason_from_pb(sdk_variable.eval)
99
+
86
100
  if sdk_variable.type == pb2.VariableType_PB.Boolean: # type: ignore
87
101
  return Variable(
88
102
  _id=None,
@@ -91,6 +105,7 @@ def create_variable(sdk_variable: pb2.SDKVariable_PB, default_value: Any) -> Var
91
105
  type=TypeEnum.BOOLEAN,
92
106
  isDefaulted=False,
93
107
  defaultValue=default_value,
108
+ eval=eval_reason_obj,
94
109
  )
95
110
 
96
111
  elif sdk_variable.type == pb2.VariableType_PB.String: # type: ignore
@@ -101,6 +116,7 @@ def create_variable(sdk_variable: pb2.SDKVariable_PB, default_value: Any) -> Var
101
116
  type=TypeEnum.STRING,
102
117
  isDefaulted=False,
103
118
  defaultValue=default_value,
119
+ eval=eval_reason_obj,
104
120
  )
105
121
 
106
122
  elif sdk_variable.type == pb2.VariableType_PB.Number: # type: ignore
@@ -111,6 +127,7 @@ def create_variable(sdk_variable: pb2.SDKVariable_PB, default_value: Any) -> Var
111
127
  type=TypeEnum.NUMBER,
112
128
  isDefaulted=False,
113
129
  defaultValue=default_value,
130
+ eval=eval_reason_obj,
114
131
  )
115
132
 
116
133
  elif sdk_variable.type == pb2.VariableType_PB.JSON: # type: ignore
@@ -123,6 +140,7 @@ def create_variable(sdk_variable: pb2.SDKVariable_PB, default_value: Any) -> Var
123
140
  type=TypeEnum.JSON,
124
141
  isDefaulted=False,
125
142
  defaultValue=default_value,
143
+ eval=eval_reason_obj,
126
144
  )
127
145
 
128
146
  else:
@@ -1,11 +1,22 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
3
4
  # source: variableForUserParams.proto
5
+ # Protobuf Python Version: 5.29.3
4
6
  """Generated protocol buffer code."""
5
- from google.protobuf.internal import builder as _builder
6
7
  from google.protobuf import descriptor as _descriptor
7
8
  from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
8
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
+ )
9
20
  # @@protoc_insertion_point(imports)
10
21
 
11
22
  _sym_db = _symbol_database.Default()
@@ -13,34 +24,36 @@ _sym_db = _symbol_database.Default()
13
24
 
14
25
 
15
26
 
16
- 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\"\xac\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*@\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
- _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
19
- _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'variableForUserParams_pb2', globals())
20
- if _descriptor._USE_C_DESCRIPTORS == False:
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')
21
28
 
22
- DESCRIPTOR._options = None
23
- DESCRIPTOR._serialized_options = b'\n&com.devcycle.sdk.server.local.protobufP\001Z\007./proto\252\002\"DevCycle.SDK.Server.Local.Protobuf'
24
- _NULLABLECUSTOMDATA_VALUEENTRY._options = None
25
- _NULLABLECUSTOMDATA_VALUEENTRY._serialized_options = b'8\001'
26
- _VARIABLETYPE_PB._serialized_start=1087
27
- _VARIABLETYPE_PB._serialized_end=1151
28
- _CUSTOMDATATYPE._serialized_start=1153
29
- _CUSTOMDATATYPE._serialized_end=1207
30
- _NULLABLESTRING._serialized_start=31
31
- _NULLABLESTRING._serialized_end=78
32
- _NULLABLEDOUBLE._serialized_start=80
33
- _NULLABLEDOUBLE._serialized_end=127
34
- _CUSTOMDATAVALUE._serialized_start=129
35
- _CUSTOMDATAVALUE._serialized_end=238
36
- _NULLABLECUSTOMDATA._serialized_start=241
37
- _NULLABLECUSTOMDATA._serialized_end=388
38
- _NULLABLECUSTOMDATA_VALUEENTRY._serialized_start=326
39
- _NULLABLECUSTOMDATA_VALUEENTRY._serialized_end=388
40
- _VARIABLEFORUSERPARAMS_PB._serialized_start=391
41
- _VARIABLEFORUSERPARAMS_PB._serialized_end=547
42
- _DVCUSER_PB._serialized_start=550
43
- _DVCUSER_PB._serialized_end=910
44
- _SDKVARIABLE_PB._serialized_start=913
45
- _SDKVARIABLE_PB._serialized_end=1085
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
46
59
  # @@protoc_insertion_point(module_scope)
@@ -4,117 +4,139 @@ from google.protobuf import descriptor as _descriptor
4
4
  from google.protobuf import message as _message
5
5
  from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
6
6
 
7
- Bool: CustomDataType
8
- Boolean: VariableType_PB
9
7
  DESCRIPTOR: _descriptor.FileDescriptor
8
+
9
+ class VariableType_PB(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
10
+ __slots__ = ()
11
+ Boolean: _ClassVar[VariableType_PB]
12
+ Number: _ClassVar[VariableType_PB]
13
+ String: _ClassVar[VariableType_PB]
14
+ JSON: _ClassVar[VariableType_PB]
15
+
16
+ class CustomDataType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
17
+ __slots__ = ()
18
+ Bool: _ClassVar[CustomDataType]
19
+ Num: _ClassVar[CustomDataType]
20
+ Str: _ClassVar[CustomDataType]
21
+ Null: _ClassVar[CustomDataType]
22
+ Boolean: VariableType_PB
23
+ Number: VariableType_PB
24
+ String: VariableType_PB
10
25
  JSON: VariableType_PB
11
- Null: CustomDataType
26
+ Bool: CustomDataType
12
27
  Num: CustomDataType
13
- Number: VariableType_PB
14
28
  Str: CustomDataType
15
- String: VariableType_PB
29
+ Null: CustomDataType
30
+
31
+ class NullableString(_message.Message):
32
+ __slots__ = ("value", "isNull")
33
+ VALUE_FIELD_NUMBER: _ClassVar[int]
34
+ ISNULL_FIELD_NUMBER: _ClassVar[int]
35
+ value: str
36
+ isNull: bool
37
+ def __init__(self, value: _Optional[str] = ..., isNull: bool = ...) -> None: ...
38
+
39
+ class NullableDouble(_message.Message):
40
+ __slots__ = ("value", "isNull")
41
+ VALUE_FIELD_NUMBER: _ClassVar[int]
42
+ ISNULL_FIELD_NUMBER: _ClassVar[int]
43
+ value: float
44
+ isNull: bool
45
+ def __init__(self, value: _Optional[float] = ..., isNull: bool = ...) -> None: ...
16
46
 
17
47
  class CustomDataValue(_message.Message):
18
- __slots__ = ["boolValue", "doubleValue", "stringValue", "type"]
48
+ __slots__ = ("type", "boolValue", "doubleValue", "stringValue")
49
+ TYPE_FIELD_NUMBER: _ClassVar[int]
19
50
  BOOLVALUE_FIELD_NUMBER: _ClassVar[int]
20
51
  DOUBLEVALUE_FIELD_NUMBER: _ClassVar[int]
21
52
  STRINGVALUE_FIELD_NUMBER: _ClassVar[int]
22
- TYPE_FIELD_NUMBER: _ClassVar[int]
53
+ type: CustomDataType
23
54
  boolValue: bool
24
55
  doubleValue: float
25
56
  stringValue: str
26
- type: CustomDataType
27
57
  def __init__(self, type: _Optional[_Union[CustomDataType, str]] = ..., boolValue: bool = ..., doubleValue: _Optional[float] = ..., stringValue: _Optional[str] = ...) -> None: ...
28
58
 
29
- class DVCUser_PB(_message.Message):
30
- __slots__ = ["appBuild", "appVersion", "country", "customData", "deviceModel", "email", "language", "name", "privateCustomData", "user_id"]
31
- APPBUILD_FIELD_NUMBER: _ClassVar[int]
32
- APPVERSION_FIELD_NUMBER: _ClassVar[int]
33
- COUNTRY_FIELD_NUMBER: _ClassVar[int]
34
- CUSTOMDATA_FIELD_NUMBER: _ClassVar[int]
35
- DEVICEMODEL_FIELD_NUMBER: _ClassVar[int]
36
- EMAIL_FIELD_NUMBER: _ClassVar[int]
37
- LANGUAGE_FIELD_NUMBER: _ClassVar[int]
38
- NAME_FIELD_NUMBER: _ClassVar[int]
39
- PRIVATECUSTOMDATA_FIELD_NUMBER: _ClassVar[int]
40
- USER_ID_FIELD_NUMBER: _ClassVar[int]
41
- appBuild: NullableDouble
42
- appVersion: NullableString
43
- country: NullableString
44
- customData: NullableCustomData
45
- deviceModel: NullableString
46
- email: NullableString
47
- language: NullableString
48
- name: NullableString
49
- privateCustomData: NullableCustomData
50
- user_id: str
51
- 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: ...
52
-
53
59
  class NullableCustomData(_message.Message):
54
- __slots__ = ["isNull", "value"]
60
+ __slots__ = ("value", "isNull")
55
61
  class ValueEntry(_message.Message):
56
- __slots__ = ["key", "value"]
62
+ __slots__ = ("key", "value")
57
63
  KEY_FIELD_NUMBER: _ClassVar[int]
58
64
  VALUE_FIELD_NUMBER: _ClassVar[int]
59
65
  key: str
60
66
  value: CustomDataValue
61
67
  def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[CustomDataValue, _Mapping]] = ...) -> None: ...
62
- ISNULL_FIELD_NUMBER: _ClassVar[int]
63
68
  VALUE_FIELD_NUMBER: _ClassVar[int]
64
- isNull: bool
69
+ ISNULL_FIELD_NUMBER: _ClassVar[int]
65
70
  value: _containers.MessageMap[str, CustomDataValue]
71
+ isNull: bool
66
72
  def __init__(self, value: _Optional[_Mapping[str, CustomDataValue]] = ..., isNull: bool = ...) -> None: ...
67
73
 
68
- class NullableDouble(_message.Message):
69
- __slots__ = ["isNull", "value"]
70
- ISNULL_FIELD_NUMBER: _ClassVar[int]
71
- VALUE_FIELD_NUMBER: _ClassVar[int]
72
- isNull: bool
73
- value: float
74
- def __init__(self, value: _Optional[float] = ..., isNull: bool = ...) -> None: ...
74
+ class VariableForUserParams_PB(_message.Message):
75
+ __slots__ = ("sdkKey", "variableKey", "variableType", "user", "shouldTrackEvent")
76
+ SDKKEY_FIELD_NUMBER: _ClassVar[int]
77
+ VARIABLEKEY_FIELD_NUMBER: _ClassVar[int]
78
+ VARIABLETYPE_FIELD_NUMBER: _ClassVar[int]
79
+ USER_FIELD_NUMBER: _ClassVar[int]
80
+ SHOULDTRACKEVENT_FIELD_NUMBER: _ClassVar[int]
81
+ sdkKey: str
82
+ variableKey: str
83
+ variableType: VariableType_PB
84
+ user: DVCUser_PB
85
+ shouldTrackEvent: bool
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: ...
75
87
 
76
- class NullableString(_message.Message):
77
- __slots__ = ["isNull", "value"]
78
- ISNULL_FIELD_NUMBER: _ClassVar[int]
79
- VALUE_FIELD_NUMBER: _ClassVar[int]
80
- isNull: bool
81
- value: str
82
- def __init__(self, value: _Optional[str] = ..., isNull: bool = ...) -> None: ...
88
+ class DVCUser_PB(_message.Message):
89
+ __slots__ = ("user_id", "email", "name", "language", "country", "appBuild", "appVersion", "deviceModel", "customData", "privateCustomData")
90
+ USER_ID_FIELD_NUMBER: _ClassVar[int]
91
+ EMAIL_FIELD_NUMBER: _ClassVar[int]
92
+ NAME_FIELD_NUMBER: _ClassVar[int]
93
+ LANGUAGE_FIELD_NUMBER: _ClassVar[int]
94
+ COUNTRY_FIELD_NUMBER: _ClassVar[int]
95
+ APPBUILD_FIELD_NUMBER: _ClassVar[int]
96
+ APPVERSION_FIELD_NUMBER: _ClassVar[int]
97
+ DEVICEMODEL_FIELD_NUMBER: _ClassVar[int]
98
+ CUSTOMDATA_FIELD_NUMBER: _ClassVar[int]
99
+ PRIVATECUSTOMDATA_FIELD_NUMBER: _ClassVar[int]
100
+ user_id: str
101
+ email: NullableString
102
+ name: NullableString
103
+ language: NullableString
104
+ country: NullableString
105
+ appBuild: NullableDouble
106
+ appVersion: NullableString
107
+ deviceModel: NullableString
108
+ customData: NullableCustomData
109
+ privateCustomData: NullableCustomData
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: ...
83
111
 
84
112
  class SDKVariable_PB(_message.Message):
85
- __slots__ = ["_id", "boolValue", "doubleValue", "evalReason", "key", "stringValue", "type"]
113
+ __slots__ = ("_id", "type", "key", "boolValue", "doubleValue", "stringValue", "evalReason", "_feature", "eval")
114
+ _ID_FIELD_NUMBER: _ClassVar[int]
115
+ TYPE_FIELD_NUMBER: _ClassVar[int]
116
+ KEY_FIELD_NUMBER: _ClassVar[int]
86
117
  BOOLVALUE_FIELD_NUMBER: _ClassVar[int]
87
118
  DOUBLEVALUE_FIELD_NUMBER: _ClassVar[int]
88
- EVALREASON_FIELD_NUMBER: _ClassVar[int]
89
- KEY_FIELD_NUMBER: _ClassVar[int]
90
119
  STRINGVALUE_FIELD_NUMBER: _ClassVar[int]
91
- TYPE_FIELD_NUMBER: _ClassVar[int]
92
- _ID_FIELD_NUMBER: _ClassVar[int]
120
+ EVALREASON_FIELD_NUMBER: _ClassVar[int]
121
+ _FEATURE_FIELD_NUMBER: _ClassVar[int]
122
+ EVAL_FIELD_NUMBER: _ClassVar[int]
93
123
  _id: str
124
+ type: VariableType_PB
125
+ key: str
94
126
  boolValue: bool
95
127
  doubleValue: float
96
- evalReason: NullableString
97
- key: str
98
128
  stringValue: str
99
- type: VariableType_PB
100
- 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]] = ...) -> None: ...
101
-
102
- class VariableForUserParams_PB(_message.Message):
103
- __slots__ = ["sdkKey", "shouldTrackEvent", "user", "variableKey", "variableType"]
104
- SDKKEY_FIELD_NUMBER: _ClassVar[int]
105
- SHOULDTRACKEVENT_FIELD_NUMBER: _ClassVar[int]
106
- USER_FIELD_NUMBER: _ClassVar[int]
107
- VARIABLEKEY_FIELD_NUMBER: _ClassVar[int]
108
- VARIABLETYPE_FIELD_NUMBER: _ClassVar[int]
109
- sdkKey: str
110
- shouldTrackEvent: bool
111
- user: DVCUser_PB
112
- variableKey: str
113
- variableType: VariableType_PB
114
- def __init__(self, sdkKey: _Optional[str] = ..., variableKey: _Optional[str] = ..., variableType: _Optional[_Union[VariableType_PB, str]] = ..., user: _Optional[_Union[DVCUser_PB, _Mapping]] = ..., shouldTrackEvent: bool = ...) -> None: ...
115
-
116
- class VariableType_PB(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
117
- __slots__ = []
129
+ evalReason: NullableString
130
+ _feature: NullableString
131
+ eval: EvalReason_PB
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: ...
118
133
 
119
- class CustomDataType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
120
- __slots__ = []
134
+ class EvalReason_PB(_message.Message):
135
+ __slots__ = ("reason", "details", "target_id")
136
+ REASON_FIELD_NUMBER: _ClassVar[int]
137
+ DETAILS_FIELD_NUMBER: _ClassVar[int]
138
+ TARGET_ID_FIELD_NUMBER: _ClassVar[int]
139
+ reason: str
140
+ details: str
141
+ target_id: str
142
+ def __init__(self, reason: _Optional[str] = ..., details: _Optional[str] = ..., target_id: _Optional[str] = ...) -> None: ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devcycle-python-server-sdk
3
- Version: 3.11.3
3
+ Version: 3.12.0
4
4
  Summary: DevCycle Python SDK
5
5
  Home-page: https://github.com/devcycleHQ/python-server-sdk
6
6
  Author-email:
@@ -1,52 +1,56 @@
1
- devcycle_python_sdk/VERSION.txt,sha256=d1xhx3dr9s7udwqwC9Ror9dezVvaZJs3QrpAoLjlHTs,7
1
+ devcycle_python_sdk/VERSION.txt,sha256=TuPL9BzJKZqNU-jwsDtquUrxVYO4LjhqEL1HqlHKDZU,7
2
2
  devcycle_python_sdk/__init__.py,sha256=30TcYb9PbvVi97gwk16omCGG1UoUI9lmmU7xpvxNMvc,336
3
- devcycle_python_sdk/bucketing-lib.release.wasm,sha256=FGGO3YnZHVs-ZY4XJM6FWpQwnPwHzFhBjQmrKPwWbtU,215612
4
- devcycle_python_sdk/cloud_client.py,sha256=VVV3O8Fbrp3LrhKp0BNCF-pMqOuCA6TEEABBmjpfpOY,7586
3
+ devcycle_python_sdk/bucketing-lib.release.wasm,sha256=wpbXlOj_TVIO2OcOD781sW5ICmGsYe9pvxG6DwYw6FY,223167
4
+ devcycle_python_sdk/cloud_client.py,sha256=LMKB6gEuQNn5YePUPO0t1QIAUXot4OyshSUlUbuu07U,9413
5
5
  devcycle_python_sdk/devcycle_client.py,sha256=OqNza7OXOSRmMQq2kmyivljmH1GyN4dTiz0EhvDvt8w,1069
6
6
  devcycle_python_sdk/exceptions.py,sha256=Et7fS8pEFbHkFY86T2pJoEUstwjh4_rzhJxVH8fzAns,1053
7
- devcycle_python_sdk/local_client.py,sha256=cC9N144DY-WWatcSwVQh-e_07mnncjC3NG88Eo9wX0g,9814
8
- devcycle_python_sdk/options.py,sha256=WOpeI9U_9Gsf3OFWvoRIBRgJVZEqFxuEYTII71r5L24,4939
7
+ devcycle_python_sdk/local_client.py,sha256=obZlHBJ9MS79sntdpPb4JTwC29e58Q5PzzEtei3m9F0,11684
8
+ devcycle_python_sdk/options.py,sha256=W3vNZfV6QNnQyaOuRf6Z5cK6ut6fWtlGqlUfhzWX0_c,5253
9
9
  devcycle_python_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  devcycle_python_sdk/api/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
11
11
  devcycle_python_sdk/api/backoff.py,sha256=F6WYCloaZD9CjNu6mKBMq7K20S8-i2WVU6X05ZRoawE,303
12
- devcycle_python_sdk/api/bucketing_client.py,sha256=-S0y9uAffippCTfjYgxI5j4j7YNfMxQJYUba1219nps,5111
12
+ devcycle_python_sdk/api/bucketing_client.py,sha256=BRQWtTnIyLdWoFT7sPHPGg8kstDtW-jx1N4og3_SEgI,5565
13
13
  devcycle_python_sdk/api/config_client.py,sha256=73aQAq130rTHpQrVDX6n_DwFKz0WuKxRoLDiE3vSoAM,5077
14
14
  devcycle_python_sdk/api/event_client.py,sha256=WxkuV6geEC9MgG4FN36HeEQQa22ilq2mkOVMZkpiEk4,3356
15
- devcycle_python_sdk/api/local_bucketing.py,sha256=_MAMCHviIS1n4GiU-CnnLBeEVX8BUFRqwNbA1IQi84U,16470
15
+ devcycle_python_sdk/api/local_bucketing.py,sha256=IXOP-680OmaO1XoX31YwY8FychAD5aqeyFFGe9SE_u4,15949
16
16
  devcycle_python_sdk/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  devcycle_python_sdk/managers/config_manager.py,sha256=AIGY9jXEhUzhEeaKIA1P5F2q6GaclrezAoGHgYU4dLQ,5634
18
+ devcycle_python_sdk/managers/eval_hooks_manager.py,sha256=skOGK_hyZNpgkdeNXTTa-d1GVRITjoi8T6dO5I_Cqfk,2679
18
19
  devcycle_python_sdk/managers/event_queue_manager.py,sha256=uPy1vO6OAisZjUNAhWELE_g17alTiOcPv42z-WwkGck,8110
19
- devcycle_python_sdk/managers/sse_manager.py,sha256=PElIsmmjUvLDHABikLxUq6CVjIJDnmqkY3psPILCTS8,2590
20
+ devcycle_python_sdk/managers/sse_manager.py,sha256=hSGpnZ6gNbQXGotqNxjogoB82znAyMMFhqdlqeCc5bI,2586
20
21
  devcycle_python_sdk/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- devcycle_python_sdk/models/bucketed_config.py,sha256=NsdT-6RbEuDy5QuK5qlr6UqNKQQnwjoXVYN-uQp0P-E,3999
22
+ devcycle_python_sdk/models/bucketed_config.py,sha256=qTfhIViX7m2WS2oDBBCmKKzPsJG6DEav3zCEXwP27nA,3980
22
23
  devcycle_python_sdk/models/error_response.py,sha256=r_dRUDAbral9UGaMYcnBsZOr9Hmkyi1SQbhGmZilgpA,442
24
+ devcycle_python_sdk/models/eval_hook.py,sha256=_mDoEa8gkzMq-XpFRZrcXu_ldtpUzv5tlh-PghLpMMI,590
25
+ devcycle_python_sdk/models/eval_hook_context.py,sha256=uBa8t0XxbcPBYAewNPFC2902qCjGhVoqUzZOZbGZ3n0,267
26
+ devcycle_python_sdk/models/eval_reason.py,sha256=nMXcbR1DM8eriCQ1NNnIRQKkhJSYAbY8_9GgBfj7P8k,943
23
27
  devcycle_python_sdk/models/event.py,sha256=Sj3eEopuPp8QwQl_Oz8E6Y9Ph6nLG0HxU7eR7xSbA7g,3722
24
28
  devcycle_python_sdk/models/feature.py,sha256=m3wxxIjC5jxhKpPLI4RcsBaNLuy-zsMqoAgc8ySPe0I,852
25
29
  devcycle_python_sdk/models/platform_data.py,sha256=nyQsgI6pcTd1FL3Y2ACmpvTYb08R_UtWul25OWZstps,849
26
- devcycle_python_sdk/models/user.py,sha256=-tt-LQV-sBxNNfAKAlbNkHpsS01Gi0w37ZJQDARtve8,6422
27
- devcycle_python_sdk/models/variable.py,sha256=qp00SyCNyfYiMlTwnDSDJ4ZetRF35JHTbYZQOBxFIqY,1711
30
+ devcycle_python_sdk/models/user.py,sha256=mhEk-mnKJRg_tydpBlAVhGDj9rDCacJ-jNwiGeSpZiE,7027
31
+ devcycle_python_sdk/models/variable.py,sha256=NXubhYWXYRAUEh4kDe2Tu9T5QnZmQ3roYVPbP-u2H3s,3030
28
32
  devcycle_python_sdk/open_feature_provider/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
- devcycle_python_sdk/open_feature_provider/provider.py,sha256=nLqyW4n9_NrJqgaz6cUt3YHDoZQzorjTYPiyT4UjFdc,5255
33
+ devcycle_python_sdk/open_feature_provider/provider.py,sha256=l-psKU5m6jSBE53VwX3fBBas-TztekFDlfYTyTJQm6c,5558
30
34
  devcycle_python_sdk/protobuf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
- devcycle_python_sdk/protobuf/utils.py,sha256=zi-kVx6yvgS2c04cUobLd2IDc_ZqKkWduay9YcpjoGc,4684
32
- devcycle_python_sdk/protobuf/variableForUserParams_pb2.py,sha256=Zf4-8n67UnulC0Sz90aqLYsXCFEgywOqfiSHuXZomLk,4244
33
- devcycle_python_sdk/protobuf/variableForUserParams_pb2.pyi,sha256=gjTD1KkBe5NaXixSq78eNTNbjdDjBQ0h5L4dUKKgDWQ,5659
35
+ devcycle_python_sdk/protobuf/utils.py,sha256=6cBL8GZ5nCZw6JoO7lAdgCj9wM1u0lp6QFQMnGE1fiM,5414
36
+ devcycle_python_sdk/protobuf/variableForUserParams_pb2.py,sha256=yawFsQ7m-6OB7DxrjXo2FLLkHhiTv6lDnjubhjAgw_8,5198
37
+ devcycle_python_sdk/protobuf/variableForUserParams_pb2.pyi,sha256=tfN0zBapUPA9WGqUG5lU5XXgH_BsHTt5mgXKGsyS4-I,6623
34
38
  devcycle_python_sdk/util/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
35
39
  devcycle_python_sdk/util/strings.py,sha256=gH0Xm3gIXNqn6hczKPk10Jn5_9knuD7OB5MrB7bqztw,252
36
40
  devcycle_python_sdk/util/version.py,sha256=Cz7Us_EuXP-T8GI47g2WHYdBJj_zKo-5y545IDHJAjI,253
37
- devcycle_python_server_sdk-3.11.3.dist-info/licenses/LICENSE,sha256=tHQMqu-Jic2UpMGqb-vNFbGygysl8IG4l1clnnh0OFo,1071
41
+ devcycle_python_server_sdk-3.12.0.dist-info/licenses/LICENSE,sha256=tHQMqu-Jic2UpMGqb-vNFbGygysl8IG4l1clnnh0OFo,1071
38
42
  example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
43
  example/cloud_client_example.py,sha256=YD8ZsTv3dPYfbFUKraRpRT0VsJGrPwjm8ZCuA5H54yI,2463
40
44
  example/local_bucketing_client_example.py,sha256=TaIfy3VnW9fXii9NPYs5UOuP4fLKruXMjnZApveqzl4,2796
41
45
  example/openfeature_example.py,sha256=kO6F-Xk20l6CPiMfIxSRreshEGmHMFHRg3zbeLXa3AI,2410
42
46
  test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
- test/test_cloud_client.py,sha256=zjk302m7qKMCQryolkc1WKLFmbGWUxA0VtHlZk0rY-0,11442
44
- test/test_local_client.py,sha256=GpuN9eTYKpacol7BtsB_uiviyPUxiKtxBdRcuI1m9qA,13065
47
+ test/test_cloud_client.py,sha256=oqOWh4aa07ObJOJeEjXMon0O2jPW_lYZMVInbFR-uzI,14586
48
+ test/test_local_client.py,sha256=d0D0h2vqSiZItiqGXrlFXRRmuZG-TNg8MT84dY6w0Ks,16250
45
49
  test/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
50
  test/api/test_bucketing_client.py,sha256=M2mjACowLvbsIjXdP-w8-fwY02xqv1X1r_h9v-pXa7A,7739
47
51
  test/api/test_config_client.py,sha256=3BwMm4y-4NQcdW2DDGppoJLIF-ffgjlUJti2Qjw1D1M,5129
48
52
  test/api/test_event_client.py,sha256=v4Xoum-PdywfczrfMV1llM5vrIJoqHybzxPLVokh09g,3310
49
- test/api/test_local_bucketing.py,sha256=0mReZ4bsFUoJWPAIcQrWXDZ9UoC5mF9MuI-9BVB6qjM,15561
53
+ test/api/test_local_bucketing.py,sha256=0cbD8kiRYCVadvU-ldMES-sr7rV9Ld4H1q62HCx4AHU,15970
50
54
  test/fixture/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
55
  test/fixture/data.py,sha256=6ReLxWPMhCDbJ5Ex24_iR0PJNjKzPFV1I9j_v0FVbBU,1462
52
56
  test/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -54,15 +58,15 @@ test/managers/test_config_manager.py,sha256=2TUnt8501KM7UlJNH7srIhvC-izehD7nOfqZ
54
58
  test/managers/test_event_queue_manager.py,sha256=z850atk8zAlD7sYaA1OJwgCFcfC0ps4NEk4XUnNCq1U,11629
55
59
  test/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
60
  test/models/test_bucketed_config.py,sha256=8wCEyxaHxY21nl7ZbiFzp-IzZQBZIPIVPPzeREjumQk,858
57
- test/models/test_user.py,sha256=W1HaNtpuzfM2Tfm3XVMD7yDcekjtLH-b7_NZG5ovkUY,6738
61
+ test/models/test_user.py,sha256=ZUbFUndYrnefyGl8rxZgG3HdHPZs4BosQWimkT7etJc,10540
58
62
  test/openfeature_test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- test/openfeature_test/test_provider.py,sha256=UPxAD5e7NvpIhmqNFCrTY_yrKrMyYxBc2xuMAgdSGvw,7653
60
- test/openfeature_test/test_provider_local_sdk.py,sha256=ad0QizKSS-lbqlIjiQvwtKHP7PCFfYam3OKHtvsFBkU,4426
63
+ test/openfeature_test/test_provider.py,sha256=hIzdqqBTulGRODeTcRJUP93v76WEolUC2QRe3DccF3U,10932
64
+ test/openfeature_test/test_provider_local_sdk.py,sha256=ExkA1LYLuvW-dD4Bw2BKggzDQ8GpnIp3WyNK4rUZgJQ,5696
61
65
  test/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
66
  test/util/test_strings.py,sha256=T5H5U0af7_ld1yJC8IdDmay_Mx-iJQ5Fi5fbvKcAc7A,862
63
67
  test/util/test_utils.py,sha256=tVBJm_qnqg-4PssLpXIxqlk0JehuiAIPs4zpi2oNVnY,6671
64
68
  test/util/test_version.py,sha256=3Xg0_84m0bdHXz6pxd2Z85Oz9DoUC1T0Ol_WqEH_jac,335
65
- devcycle_python_server_sdk-3.11.3.dist-info/METADATA,sha256=7imNswc1zd_qIiCCAtUY6b6asiSXxrEyz3sEvflHtuU,723
66
- devcycle_python_server_sdk-3.11.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
67
- devcycle_python_server_sdk-3.11.3.dist-info/top_level.txt,sha256=34f8zDzihAHoH7siAFlmscyO_QLNWWq9HApFlwtYL4k,33
68
- devcycle_python_server_sdk-3.11.3.dist-info/RECORD,,
69
+ devcycle_python_server_sdk-3.12.0.dist-info/METADATA,sha256=-bA66ayqIdC5UFrsLx0jZ9m4eNSHzcdTuFvA-sY-IQE,723
70
+ devcycle_python_server_sdk-3.12.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
71
+ devcycle_python_server_sdk-3.12.0.dist-info/top_level.txt,sha256=34f8zDzihAHoH7siAFlmscyO_QLNWWq9HApFlwtYL4k,33
72
+ devcycle_python_server_sdk-3.12.0.dist-info/RECORD,,
@@ -10,6 +10,7 @@ from devcycle_python_sdk.models.bucketed_config import (
10
10
  Project,
11
11
  ProjectSettings,
12
12
  )
13
+ from devcycle_python_sdk.models.eval_reason import EvalReason
13
14
  from devcycle_python_sdk.models.feature import Feature
14
15
  from devcycle_python_sdk.models.variable import Variable
15
16
  from devcycle_python_sdk.models.platform_data import default_platform_data
@@ -155,6 +156,11 @@ class LocalBucketingTest(unittest.TestCase):
155
156
  evalReason=None,
156
157
  )
157
158
  }
159
+ expected_eval = EvalReason(
160
+ reason="TARGETING_MATCH",
161
+ details="All Users",
162
+ target_id="63125321d31c601f992288bc",
163
+ )
158
164
  expected_variables = {
159
165
  "a-cool-new-feature": Variable(
160
166
  _id="62fbf6566f1ba302829f9e34",
@@ -164,6 +170,7 @@ class LocalBucketingTest(unittest.TestCase):
164
170
  isDefaulted=None,
165
171
  defaultValue=None,
166
172
  evalReason=None,
173
+ eval=expected_eval,
167
174
  ),
168
175
  "string-var": Variable(
169
176
  _id="63125320a4719939fd57cb2b",
@@ -173,6 +180,7 @@ class LocalBucketingTest(unittest.TestCase):
173
180
  isDefaulted=None,
174
181
  defaultValue=None,
175
182
  evalReason=None,
183
+ eval=expected_eval,
176
184
  ),
177
185
  "json-var": Variable(
178
186
  _id="64372363125123fca69d3f7b",
@@ -186,6 +194,7 @@ class LocalBucketingTest(unittest.TestCase):
186
194
  isDefaulted=None,
187
195
  defaultValue=None,
188
196
  evalReason=None,
197
+ eval=expected_eval,
189
198
  ),
190
199
  "num-var": Variable(
191
200
  _id="65272363125123fca69d3a7d",
@@ -195,6 +204,7 @@ class LocalBucketingTest(unittest.TestCase):
195
204
  isDefaulted=None,
196
205
  defaultValue=None,
197
206
  evalReason=None,
207
+ eval=expected_eval,
198
208
  ),
199
209
  "float-var": Variable(
200
210
  _id="61200363125123fca69d3a7a",
@@ -204,6 +214,7 @@ class LocalBucketingTest(unittest.TestCase):
204
214
  isDefaulted=None,
205
215
  defaultValue=None,
206
216
  evalReason=None,
217
+ eval=expected_eval,
207
218
  ),
208
219
  }
209
220
 
test/models/test_user.py CHANGED
@@ -53,6 +53,96 @@ class DevCycleUserTest(unittest.TestCase):
53
53
  self.assertIsNotNone(user)
54
54
  self.assertEqual(user.user_id, test_user_id)
55
55
 
56
+ def test_create_user_from_context_with_user_id_attribute(self):
57
+ """Comprehensive test for userId attribute support including priority, functionality, and error cases"""
58
+ targeting_key_id = "targeting-12345"
59
+ user_id = "user_id-12345"
60
+ user_id_attr = "userId-12345"
61
+
62
+ # Test 1: userId as the only user ID source
63
+ context = EvaluationContext(
64
+ targeting_key=None, attributes={"userId": user_id_attr}
65
+ )
66
+ user = DevCycleUser.create_user_from_context(context)
67
+ self.assertIsNotNone(user)
68
+ self.assertEqual(user.user_id, user_id_attr)
69
+
70
+ # Test 2: Priority order - targeting_key > user_id > userId
71
+ context = EvaluationContext(
72
+ targeting_key=targeting_key_id,
73
+ attributes={"user_id": user_id, "userId": user_id_attr},
74
+ )
75
+ user = DevCycleUser.create_user_from_context(context)
76
+ self.assertEqual(user.user_id, targeting_key_id)
77
+
78
+ context = EvaluationContext(
79
+ targeting_key=None, attributes={"user_id": user_id, "userId": user_id_attr}
80
+ )
81
+ user = DevCycleUser.create_user_from_context(context)
82
+ self.assertEqual(user.user_id, user_id)
83
+
84
+ # Test 3: Error cases - invalid userId types
85
+ with self.assertRaises(TargetingKeyMissingError):
86
+ DevCycleUser.create_user_from_context(
87
+ EvaluationContext(targeting_key=None, attributes={"userId": 12345})
88
+ )
89
+
90
+ with self.assertRaises(TargetingKeyMissingError):
91
+ DevCycleUser.create_user_from_context(
92
+ EvaluationContext(targeting_key=None, attributes={"userId": None})
93
+ )
94
+
95
+ def test_create_user_from_context_user_id_exclusion(self):
96
+ """Test that all user ID fields (targeting_key, user_id, userId) are excluded from custom data"""
97
+ targeting_key_id = "targeting-12345"
98
+ user_id = "user_id-12345"
99
+ user_id_attr = "userId-12345"
100
+
101
+ # Test exclusion when targeting_key is used
102
+ context = EvaluationContext(
103
+ targeting_key=targeting_key_id,
104
+ attributes={
105
+ "user_id": user_id,
106
+ "userId": user_id_attr,
107
+ "targeting_key": "should-be-excluded",
108
+ "other_field": "value",
109
+ },
110
+ )
111
+ user = DevCycleUser.create_user_from_context(context)
112
+ self.assertEqual(user.user_id, targeting_key_id)
113
+ self.assertIsNotNone(user.customData)
114
+ self.assertNotIn("user_id", user.customData)
115
+ self.assertNotIn("userId", user.customData)
116
+ self.assertNotIn("targeting_key", user.customData)
117
+ self.assertEqual(user.customData["other_field"], "value")
118
+
119
+ # Test exclusion when user_id is used
120
+ context = EvaluationContext(
121
+ targeting_key=None,
122
+ attributes={
123
+ "user_id": user_id,
124
+ "userId": user_id_attr,
125
+ "other_field": "value",
126
+ },
127
+ )
128
+ user = DevCycleUser.create_user_from_context(context)
129
+ self.assertEqual(user.user_id, user_id)
130
+ self.assertIsNotNone(user.customData)
131
+ self.assertNotIn("user_id", user.customData)
132
+ self.assertNotIn("userId", user.customData)
133
+ self.assertEqual(user.customData["other_field"], "value")
134
+
135
+ # Test exclusion when userId is used
136
+ context = EvaluationContext(
137
+ targeting_key=None,
138
+ attributes={"userId": user_id_attr, "other_field": "value"},
139
+ )
140
+ user = DevCycleUser.create_user_from_context(context)
141
+ self.assertEqual(user.user_id, user_id_attr)
142
+ self.assertIsNotNone(user.customData)
143
+ self.assertNotIn("userId", user.customData)
144
+ self.assertEqual(user.customData["other_field"], "value")
145
+
56
146
  def test_create_user_from_context_with_attributes(self):
57
147
  test_user_id = "12345"
58
148
  context = EvaluationContext(