launchdarkly-openfeature-server 0.3.0__tar.gz → 0.4.2__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.
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/PKG-INFO +5 -6
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/README.md +1 -1
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/ld_openfeature/provider.py +25 -17
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/pyproject.toml +5 -5
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/tests/test_provider.py +35 -27
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/LICENSE +0 -0
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/ld_openfeature/__init__.py +0 -0
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/ld_openfeature/impl/context_converter.py +0 -0
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/ld_openfeature/impl/details_converter.py +0 -0
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/ld_openfeature/py.typed +0 -0
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/tests/__init__.py +0 -0
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/tests/impl/test_context_converter.py +0 -0
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/tests/impl/test_details_converter.py +0 -0
- {launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/tests/test_data_sources.py +0 -0
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: launchdarkly-openfeature-server
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: An OpenFeature provider for the LaunchDarkly Python server SDK
|
|
5
|
-
Home-page: https://github.com/launchdarkly/openfeature-python-server
|
|
6
5
|
License: Apache-2.0
|
|
7
6
|
Author: LaunchDarkly
|
|
8
7
|
Author-email: dev@launchdarkly.com
|
|
9
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.9,<4.0
|
|
10
9
|
Classifier: Intended Audience :: Developers
|
|
11
10
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
11
|
Classifier: Operating System :: OS Independent
|
|
13
12
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
16
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Topic :: Software Development
|
|
20
19
|
Classifier: Topic :: Software Development :: Libraries
|
|
21
20
|
Requires-Dist: launchdarkly-server-sdk (<10)
|
|
@@ -50,7 +49,7 @@ This provider is designed primarily for use in multi-user systems such as web se
|
|
|
50
49
|
|
|
51
50
|
## Supported Python versions
|
|
52
51
|
|
|
53
|
-
This version of the LaunchDarkly provider works with Python 3.
|
|
52
|
+
This version of the LaunchDarkly provider works with Python 3.9 and above.
|
|
54
53
|
|
|
55
54
|
## Getting started
|
|
56
55
|
|
|
@@ -24,7 +24,7 @@ This provider is designed primarily for use in multi-user systems such as web se
|
|
|
24
24
|
|
|
25
25
|
## Supported Python versions
|
|
26
26
|
|
|
27
|
-
This version of the LaunchDarkly provider works with Python 3.
|
|
27
|
+
This version of the LaunchDarkly provider works with Python 3.9 and above.
|
|
28
28
|
|
|
29
29
|
## Getting started
|
|
30
30
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import threading
|
|
2
2
|
from typing import Any, List, Optional, Union
|
|
3
3
|
|
|
4
|
+
from ldclient.evaluation import EvaluationDetail
|
|
4
5
|
from ldclient import LDClient, Config
|
|
5
6
|
from ldclient.interfaces import DataSourceStatus, FlagChange, DataSourceState
|
|
6
7
|
from openfeature.evaluation_context import EvaluationContext
|
|
@@ -150,24 +151,31 @@ class LaunchDarklyProvider(AbstractProvider):
|
|
|
150
151
|
ld_context = self.__context_converter.to_ld_context(evaluation_context)
|
|
151
152
|
result = self.__client.variation_detail(flag_key, ld_context, default_value)
|
|
152
153
|
|
|
153
|
-
|
|
154
|
+
resolved_value = self.__validate_and_cast_value(flag_type, result.value)
|
|
155
|
+
if resolved_value is None:
|
|
154
156
|
return self.__mismatched_type_details(default_value)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
157
|
+
|
|
158
|
+
resolved_detail = EvaluationDetail(
|
|
159
|
+
value=resolved_value,
|
|
160
|
+
variation_index=result.variation_index,
|
|
161
|
+
reason=result.reason,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
return self.__details_converter.to_resolution_details(resolved_detail)
|
|
165
|
+
|
|
166
|
+
def __validate_and_cast_value(self, flag_type: FlagType, value: Any):
|
|
167
|
+
"""Serializes the raw flag value to the expected type based on flag_type."""
|
|
168
|
+
if flag_type == FlagType.BOOLEAN and isinstance(value, bool):
|
|
169
|
+
return value
|
|
170
|
+
elif flag_type == FlagType.STRING and isinstance(value, str):
|
|
171
|
+
return value
|
|
172
|
+
elif flag_type == FlagType.INTEGER and isinstance(value, (int, float)) and not isinstance(value, bool):
|
|
173
|
+
return int(value) # Float decimals are truncated to int
|
|
174
|
+
elif flag_type == FlagType.FLOAT and isinstance(value, (int, float)) and not isinstance(value, bool):
|
|
175
|
+
return float(value)
|
|
176
|
+
elif flag_type == FlagType.OBJECT and isinstance(value, (dict, list)):
|
|
177
|
+
return value
|
|
178
|
+
return None
|
|
171
179
|
|
|
172
180
|
@staticmethod
|
|
173
181
|
def __mismatched_type_details(default_value: Any) -> FlagResolutionDetails:
|
{launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/pyproject.toml
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "launchdarkly-openfeature-server"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.2"
|
|
4
4
|
description = "An OpenFeature provider for the LaunchDarkly Python server SDK"
|
|
5
5
|
authors = ["LaunchDarkly <dev@launchdarkly.com>"]
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -12,11 +12,11 @@ classifiers = [
|
|
|
12
12
|
"License :: OSI Approved :: Apache Software License",
|
|
13
13
|
"Operating System :: OS Independent",
|
|
14
14
|
"Programming Language :: Python :: 3",
|
|
15
|
-
"Programming Language :: Python :: 3.8",
|
|
16
15
|
"Programming Language :: Python :: 3.9",
|
|
17
16
|
"Programming Language :: Python :: 3.10",
|
|
18
17
|
"Programming Language :: Python :: 3.11",
|
|
19
18
|
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
20
|
"Topic :: Software Development",
|
|
21
21
|
"Topic :: Software Development :: Libraries",
|
|
22
22
|
]
|
|
@@ -27,7 +27,7 @@ packages = [
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
[tool.poetry.dependencies]
|
|
30
|
-
python = "^3.
|
|
30
|
+
python = "^3.9"
|
|
31
31
|
openfeature-sdk = ">=0.7.0,<1"
|
|
32
32
|
launchdarkly-server-sdk = "<10"
|
|
33
33
|
|
|
@@ -56,13 +56,13 @@ jinja2 = "3.1.3"
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
[tool.mypy]
|
|
59
|
-
python_version = "3.
|
|
59
|
+
python_version = "3.9"
|
|
60
60
|
install_types = true
|
|
61
61
|
non_interactive = true
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
[tool.isort]
|
|
65
|
-
py_version=
|
|
65
|
+
py_version=39
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
[tool.pytest.ini_options]
|
|
@@ -88,32 +88,38 @@ def test_invalid_types_generate_type_mismatch_results(provider: LaunchDarklyProv
|
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
@pytest.mark.parametrize(
|
|
91
|
-
"default_value,return_value,expected_value,method_name",
|
|
92
|
-
|
|
93
|
-
pytest.param(True, False, False, 'resolve_boolean_details'),
|
|
94
|
-
pytest.param(False, True, True, 'resolve_boolean_details'),
|
|
95
|
-
pytest.param(False, 1, False, 'resolve_boolean_details'),
|
|
96
|
-
pytest.param(False, "True", False, 'resolve_boolean_details'),
|
|
97
|
-
pytest.param(True, [], True, 'resolve_boolean_details'),
|
|
98
|
-
|
|
99
|
-
pytest.param('default-string', 'return-string', 'return-string', 'resolve_string_details'),
|
|
100
|
-
pytest.param('default-string', 1, 'default-string', 'resolve_string_details'),
|
|
101
|
-
pytest.param('default-string', True, 'default-string', 'resolve_string_details'),
|
|
102
|
-
|
|
103
|
-
pytest.param(1, 2, 2, 'resolve_integer_details'),
|
|
104
|
-
pytest.param(1, True, 1, 'resolve_integer_details'),
|
|
105
|
-
pytest.param(1, False, 1, 'resolve_integer_details'),
|
|
106
|
-
pytest.param(1, "", 1, 'resolve_integer_details'),
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
pytest.param(1.0, 2, 2.0, 'resolve_float_details'),
|
|
110
|
-
pytest.param(1.0,
|
|
111
|
-
pytest.param(1.0,
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
pytest.param(['default-value'],
|
|
115
|
-
pytest.param(['default-value'],
|
|
116
|
-
pytest.param(['default-value'],
|
|
91
|
+
"default_value,return_value,expected_value,expected_type,method_name",
|
|
92
|
+
[
|
|
93
|
+
pytest.param(True, False, False, bool, 'resolve_boolean_details'),
|
|
94
|
+
pytest.param(False, True, True, bool, 'resolve_boolean_details'),
|
|
95
|
+
pytest.param(False, 1, False, bool, 'resolve_boolean_details'),
|
|
96
|
+
pytest.param(False, "True", False, bool, 'resolve_boolean_details'),
|
|
97
|
+
pytest.param(True, [], True, bool, 'resolve_boolean_details'),
|
|
98
|
+
|
|
99
|
+
pytest.param('default-string', 'return-string', 'return-string', str, 'resolve_string_details'),
|
|
100
|
+
pytest.param('default-string', 1, 'default-string', str, 'resolve_string_details'),
|
|
101
|
+
pytest.param('default-string', True, 'default-string', str, 'resolve_string_details'),
|
|
102
|
+
|
|
103
|
+
pytest.param(1, 2, 2, int, 'resolve_integer_details'),
|
|
104
|
+
pytest.param(1, True, 1, int, 'resolve_integer_details'),
|
|
105
|
+
pytest.param(1, False, 1, int, 'resolve_integer_details'),
|
|
106
|
+
pytest.param(1, "", 1, int, 'resolve_integer_details'),
|
|
107
|
+
pytest.param(1, 2.9, 2, int, 'resolve_integer_details'),
|
|
108
|
+
|
|
109
|
+
pytest.param(1.0, 2.0, 2.0, float, 'resolve_float_details'),
|
|
110
|
+
pytest.param(1.0, 2, 2.0, float, 'resolve_float_details'),
|
|
111
|
+
pytest.param(1.0, True, 1.0, float, 'resolve_float_details'),
|
|
112
|
+
pytest.param(1.0, 'return-string', 1.0, float, 'resolve_float_details'),
|
|
113
|
+
|
|
114
|
+
pytest.param(['default-value'], ['return-string'], ['return-string'], list, 'resolve_object_details'),
|
|
115
|
+
pytest.param(['default-value'], True, ['default-value'], list, 'resolve_object_details'),
|
|
116
|
+
pytest.param(['default-value'], 1, ['default-value'], list, 'resolve_object_details'),
|
|
117
|
+
pytest.param(['default-value'], 'return-string', ['default-value'], list, 'resolve_object_details'),
|
|
118
|
+
|
|
119
|
+
pytest.param({'key': 'default'}, {'key': 'return'}, {'key': 'return'}, dict, 'resolve_object_details'),
|
|
120
|
+
pytest.param({'key': 'default'}, True, {'key': 'default'}, dict, 'resolve_object_details'),
|
|
121
|
+
pytest.param({'key': 'default'}, 1, {'key': 'default'}, dict, 'resolve_object_details'),
|
|
122
|
+
pytest.param({'key': 'default'}, 'return-string', {'key': 'default'}, dict, 'resolve_object_details'),
|
|
117
123
|
],
|
|
118
124
|
)
|
|
119
125
|
def test_check_method_and_result_match_type(
|
|
@@ -121,6 +127,7 @@ def test_check_method_and_result_match_type(
|
|
|
121
127
|
default_value: Union[bool, str, int, float, List],
|
|
122
128
|
return_value: Union[bool, str, int, float, List],
|
|
123
129
|
expected_value: Union[bool, str, int, float, List],
|
|
130
|
+
expected_type: type,
|
|
124
131
|
method_name: str,
|
|
125
132
|
# end of parameterized values
|
|
126
133
|
test_data_source: TestData,
|
|
@@ -130,8 +137,9 @@ def test_check_method_and_result_match_type(
|
|
|
130
137
|
|
|
131
138
|
method = getattr(provider, method_name)
|
|
132
139
|
resolution_details = method("check-method-flag", default_value, evaluation_context)
|
|
133
|
-
|
|
140
|
+
|
|
134
141
|
assert resolution_details.value == expected_value
|
|
142
|
+
#assert isinstance(resolution_details.value, expected_type)
|
|
135
143
|
|
|
136
144
|
|
|
137
145
|
def test_logger_changes_should_cascade_to_evaluation_converter(provider: LaunchDarklyProvider, caplog):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{launchdarkly_openfeature_server-0.3.0 → launchdarkly_openfeature_server-0.4.2}/tests/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|