openfeature-provider-flagd 0.2.0__py3-none-any.whl → 0.2.1__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.
- openfeature/contrib/provider/flagd/config.py +21 -0
- openfeature/contrib/provider/flagd/provider.py +27 -1
- openfeature/contrib/provider/flagd/resolvers/grpc.py +5 -2
- openfeature/contrib/provider/flagd/resolvers/in_process.py +1 -1
- openfeature/contrib/provider/flagd/resolvers/process/connector/file_watcher.py +3 -2
- openfeature/contrib/provider/flagd/resolvers/process/connector/grpc_watcher.py +32 -6
- openfeature/contrib/provider/flagd/sync_metadata_hook.py +14 -0
- {openfeature_provider_flagd-0.2.0.dist-info → openfeature_provider_flagd-0.2.1.dist-info}/METADATA +1 -1
- {openfeature_provider_flagd-0.2.0.dist-info → openfeature_provider_flagd-0.2.1.dist-info}/RECORD +11 -10
- {openfeature_provider_flagd-0.2.0.dist-info → openfeature_provider_flagd-0.2.1.dist-info}/WHEEL +0 -0
- {openfeature_provider_flagd-0.2.0.dist-info → openfeature_provider_flagd-0.2.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,6 +3,8 @@ import os
|
|
|
3
3
|
import typing
|
|
4
4
|
from enum import Enum
|
|
5
5
|
|
|
6
|
+
import grpc
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
class ResolverType(Enum):
|
|
8
10
|
RPC = "rpc"
|
|
@@ -45,9 +47,11 @@ ENV_VAR_RETRY_BACKOFF_MS = "FLAGD_RETRY_BACKOFF_MS"
|
|
|
45
47
|
ENV_VAR_RETRY_BACKOFF_MAX_MS = "FLAGD_RETRY_BACKOFF_MAX_MS"
|
|
46
48
|
ENV_VAR_RETRY_GRACE_PERIOD_SECONDS = "FLAGD_RETRY_GRACE_PERIOD"
|
|
47
49
|
ENV_VAR_SELECTOR = "FLAGD_SOURCE_SELECTOR"
|
|
50
|
+
ENV_VAR_PROVIDER_ID = "FLAGD_SOURCE_PROVIDER_ID"
|
|
48
51
|
ENV_VAR_STREAM_DEADLINE_MS = "FLAGD_STREAM_DEADLINE_MS"
|
|
49
52
|
ENV_VAR_TLS = "FLAGD_TLS"
|
|
50
53
|
ENV_VAR_TLS_CERT = "FLAGD_SERVER_CERT_PATH"
|
|
54
|
+
ENV_VAR_DEFAULT_AUTHORITY = "FLAGD_DEFAULT_AUTHORITY"
|
|
51
55
|
|
|
52
56
|
T = typing.TypeVar("T")
|
|
53
57
|
|
|
@@ -81,6 +85,7 @@ class Config:
|
|
|
81
85
|
port: typing.Optional[int] = None,
|
|
82
86
|
tls: typing.Optional[bool] = None,
|
|
83
87
|
selector: typing.Optional[str] = None,
|
|
88
|
+
provider_id: typing.Optional[str] = None,
|
|
84
89
|
resolver: typing.Optional[ResolverType] = None,
|
|
85
90
|
offline_flag_source_path: typing.Optional[str] = None,
|
|
86
91
|
offline_poll_interval_ms: typing.Optional[int] = None,
|
|
@@ -93,6 +98,8 @@ class Config:
|
|
|
93
98
|
cache: typing.Optional[CacheType] = None,
|
|
94
99
|
max_cache_size: typing.Optional[int] = None,
|
|
95
100
|
cert_path: typing.Optional[str] = None,
|
|
101
|
+
default_authority: typing.Optional[str] = None,
|
|
102
|
+
channel_credentials: typing.Optional[grpc.ChannelCredentials] = None,
|
|
96
103
|
):
|
|
97
104
|
self.host = env_or_default(ENV_VAR_HOST, DEFAULT_HOST) if host is None else host
|
|
98
105
|
|
|
@@ -227,3 +234,17 @@ class Config:
|
|
|
227
234
|
self.selector = (
|
|
228
235
|
env_or_default(ENV_VAR_SELECTOR, None) if selector is None else selector
|
|
229
236
|
)
|
|
237
|
+
|
|
238
|
+
self.provider_id = (
|
|
239
|
+
env_or_default(ENV_VAR_PROVIDER_ID, None)
|
|
240
|
+
if provider_id is None
|
|
241
|
+
else provider_id
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
self.default_authority = (
|
|
245
|
+
env_or_default(ENV_VAR_DEFAULT_AUTHORITY, None)
|
|
246
|
+
if default_authority is None
|
|
247
|
+
else default_authority
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
self.channel_credentials = channel_credentials
|
|
@@ -24,13 +24,18 @@
|
|
|
24
24
|
import typing
|
|
25
25
|
import warnings
|
|
26
26
|
|
|
27
|
+
import grpc
|
|
28
|
+
|
|
27
29
|
from openfeature.evaluation_context import EvaluationContext
|
|
30
|
+
from openfeature.event import ProviderEventDetails
|
|
28
31
|
from openfeature.flag_evaluation import FlagResolutionDetails
|
|
32
|
+
from openfeature.hook import Hook
|
|
29
33
|
from openfeature.provider import AbstractProvider
|
|
30
34
|
from openfeature.provider.metadata import Metadata
|
|
31
35
|
|
|
32
36
|
from .config import CacheType, Config, ResolverType
|
|
33
37
|
from .resolvers import AbstractResolver, GrpcResolver, InProcessResolver
|
|
38
|
+
from .sync_metadata_hook import SyncMetadataHook
|
|
34
39
|
|
|
35
40
|
T = typing.TypeVar("T")
|
|
36
41
|
|
|
@@ -47,6 +52,7 @@ class FlagdProvider(AbstractProvider):
|
|
|
47
52
|
timeout: typing.Optional[int] = None,
|
|
48
53
|
retry_backoff_ms: typing.Optional[int] = None,
|
|
49
54
|
selector: typing.Optional[str] = None,
|
|
55
|
+
provider_id: typing.Optional[str] = None,
|
|
50
56
|
resolver_type: typing.Optional[ResolverType] = None,
|
|
51
57
|
offline_flag_source_path: typing.Optional[str] = None,
|
|
52
58
|
stream_deadline_ms: typing.Optional[int] = None,
|
|
@@ -56,6 +62,8 @@ class FlagdProvider(AbstractProvider):
|
|
|
56
62
|
retry_backoff_max_ms: typing.Optional[int] = None,
|
|
57
63
|
retry_grace_period: typing.Optional[int] = None,
|
|
58
64
|
cert_path: typing.Optional[str] = None,
|
|
65
|
+
default_authority: typing.Optional[str] = None,
|
|
66
|
+
channel_credentials: typing.Optional[grpc.ChannelCredentials] = None,
|
|
59
67
|
):
|
|
60
68
|
"""
|
|
61
69
|
Create an instance of the FlagdProvider
|
|
@@ -88,6 +96,7 @@ class FlagdProvider(AbstractProvider):
|
|
|
88
96
|
retry_backoff_max_ms=retry_backoff_max_ms,
|
|
89
97
|
retry_grace_period=retry_grace_period,
|
|
90
98
|
selector=selector,
|
|
99
|
+
provider_id=provider_id,
|
|
91
100
|
resolver=resolver_type,
|
|
92
101
|
offline_flag_source_path=offline_flag_source_path,
|
|
93
102
|
stream_deadline_ms=stream_deadline_ms,
|
|
@@ -95,9 +104,19 @@ class FlagdProvider(AbstractProvider):
|
|
|
95
104
|
cache=cache,
|
|
96
105
|
max_cache_size=max_cache_size,
|
|
97
106
|
cert_path=cert_path,
|
|
107
|
+
default_authority=default_authority,
|
|
108
|
+
channel_credentials=channel_credentials,
|
|
98
109
|
)
|
|
110
|
+
self.enriched_context: dict = {}
|
|
99
111
|
|
|
100
112
|
self.resolver = self.setup_resolver()
|
|
113
|
+
self.hooks: list[Hook] = [SyncMetadataHook(self.get_enriched_context)]
|
|
114
|
+
|
|
115
|
+
def get_enriched_context(self) -> EvaluationContext:
|
|
116
|
+
return EvaluationContext(attributes=self.enriched_context)
|
|
117
|
+
|
|
118
|
+
def get_provider_hooks(self) -> list[Hook]:
|
|
119
|
+
return self.hooks
|
|
101
120
|
|
|
102
121
|
def setup_resolver(self) -> AbstractResolver:
|
|
103
122
|
if self.config.resolver == ResolverType.RPC:
|
|
@@ -114,7 +133,7 @@ class FlagdProvider(AbstractProvider):
|
|
|
114
133
|
):
|
|
115
134
|
return InProcessResolver(
|
|
116
135
|
self.config,
|
|
117
|
-
self.
|
|
136
|
+
self.emit_provider_ready_with_context,
|
|
118
137
|
self.emit_provider_error,
|
|
119
138
|
self.emit_provider_stale,
|
|
120
139
|
self.emit_provider_configuration_changed,
|
|
@@ -184,3 +203,10 @@ class FlagdProvider(AbstractProvider):
|
|
|
184
203
|
return self.resolver.resolve_object_details(
|
|
185
204
|
key, default_value, evaluation_context
|
|
186
205
|
)
|
|
206
|
+
|
|
207
|
+
def emit_provider_ready_with_context(
|
|
208
|
+
self, details: ProviderEventDetails, context: dict
|
|
209
|
+
) -> None:
|
|
210
|
+
self.enriched_context = context
|
|
211
|
+
self.emit_provider_ready(details)
|
|
212
|
+
pass
|
|
@@ -137,7 +137,10 @@ class GrpcResolver:
|
|
|
137
137
|
|
|
138
138
|
def _state_change_callback(self, new_state: ChannelConnectivity) -> None:
|
|
139
139
|
logger.debug(f"gRPC state change: {new_state}")
|
|
140
|
-
if
|
|
140
|
+
if (
|
|
141
|
+
new_state == grpc.ChannelConnectivity.READY
|
|
142
|
+
or new_state == grpc.ChannelConnectivity.IDLE
|
|
143
|
+
):
|
|
141
144
|
if not self.thread or not self.thread.is_alive():
|
|
142
145
|
self.thread = threading.Thread(
|
|
143
146
|
target=self.listen,
|
|
@@ -276,7 +279,7 @@ class GrpcResolver:
|
|
|
276
279
|
return cached_flag
|
|
277
280
|
|
|
278
281
|
context = self._convert_context(evaluation_context)
|
|
279
|
-
call_args = {"timeout": self.deadline}
|
|
282
|
+
call_args = {"timeout": self.deadline, "wait_for_ready": True}
|
|
280
283
|
try:
|
|
281
284
|
request: Message
|
|
282
285
|
if flag_type == FlagType.BOOLEAN:
|
|
@@ -21,7 +21,7 @@ class InProcessResolver:
|
|
|
21
21
|
def __init__(
|
|
22
22
|
self,
|
|
23
23
|
config: Config,
|
|
24
|
-
emit_provider_ready: typing.Callable[[ProviderEventDetails], None],
|
|
24
|
+
emit_provider_ready: typing.Callable[[ProviderEventDetails, dict], None],
|
|
25
25
|
emit_provider_error: typing.Callable[[ProviderEventDetails], None],
|
|
26
26
|
emit_provider_stale: typing.Callable[[ProviderEventDetails], None],
|
|
27
27
|
emit_provider_configuration_changed: typing.Callable[
|
|
@@ -24,7 +24,7 @@ class FileWatcher(FlagStateConnector):
|
|
|
24
24
|
self,
|
|
25
25
|
config: Config,
|
|
26
26
|
flag_store: FlagStore,
|
|
27
|
-
emit_provider_ready: typing.Callable[[ProviderEventDetails], None],
|
|
27
|
+
emit_provider_ready: typing.Callable[[ProviderEventDetails, dict], None],
|
|
28
28
|
emit_provider_error: typing.Callable[[ProviderEventDetails], None],
|
|
29
29
|
):
|
|
30
30
|
if config.offline_flag_source_path is None:
|
|
@@ -94,7 +94,8 @@ class FileWatcher(FlagStateConnector):
|
|
|
94
94
|
self.emit_provider_ready(
|
|
95
95
|
ProviderEventDetails(
|
|
96
96
|
message="Reloading file contents recovered from error state"
|
|
97
|
-
)
|
|
97
|
+
),
|
|
98
|
+
{},
|
|
98
99
|
)
|
|
99
100
|
self.should_emit_ready_on_success = False
|
|
100
101
|
|
|
@@ -5,6 +5,7 @@ import time
|
|
|
5
5
|
import typing
|
|
6
6
|
|
|
7
7
|
import grpc
|
|
8
|
+
from google.protobuf.json_format import MessageToDict
|
|
8
9
|
|
|
9
10
|
from openfeature.evaluation_context import EvaluationContext
|
|
10
11
|
from openfeature.event import ProviderEventDetails
|
|
@@ -26,7 +27,7 @@ class GrpcWatcher(FlagStateConnector):
|
|
|
26
27
|
self,
|
|
27
28
|
config: Config,
|
|
28
29
|
flag_store: FlagStore,
|
|
29
|
-
emit_provider_ready: typing.Callable[[ProviderEventDetails], None],
|
|
30
|
+
emit_provider_ready: typing.Callable[[ProviderEventDetails, dict], None],
|
|
30
31
|
emit_provider_error: typing.Callable[[ProviderEventDetails], None],
|
|
31
32
|
emit_provider_stale: typing.Callable[[ProviderEventDetails], None],
|
|
32
33
|
):
|
|
@@ -41,6 +42,7 @@ class GrpcWatcher(FlagStateConnector):
|
|
|
41
42
|
self.streamline_deadline_seconds = config.stream_deadline_ms * 0.001
|
|
42
43
|
self.deadline = config.deadline_ms * 0.001
|
|
43
44
|
self.selector = config.selector
|
|
45
|
+
self.provider_id = config.provider_id
|
|
44
46
|
self.emit_provider_ready = emit_provider_ready
|
|
45
47
|
self.emit_provider_error = emit_provider_error
|
|
46
48
|
self.emit_provider_stale = emit_provider_stale
|
|
@@ -54,13 +56,23 @@ class GrpcWatcher(FlagStateConnector):
|
|
|
54
56
|
def _generate_channel(self, config: Config) -> grpc.Channel:
|
|
55
57
|
target = f"{config.host}:{config.port}"
|
|
56
58
|
# Create the channel with the service config
|
|
57
|
-
options = [
|
|
59
|
+
options: list[tuple[str, typing.Any]] = [
|
|
58
60
|
("grpc.keepalive_time_ms", config.keep_alive_time),
|
|
59
61
|
("grpc.initial_reconnect_backoff_ms", config.retry_backoff_ms),
|
|
60
62
|
("grpc.max_reconnect_backoff_ms", config.retry_backoff_max_ms),
|
|
61
63
|
("grpc.min_reconnect_backoff_ms", config.stream_deadline_ms),
|
|
62
64
|
]
|
|
63
|
-
if config.
|
|
65
|
+
if config.default_authority is not None:
|
|
66
|
+
options.append(("grpc.default_authority", config.default_authority))
|
|
67
|
+
|
|
68
|
+
if config.channel_credentials is not None:
|
|
69
|
+
channel_args = {
|
|
70
|
+
"options": options,
|
|
71
|
+
"credentials": config.channel_credentials,
|
|
72
|
+
}
|
|
73
|
+
channel = grpc.secure_channel(target, **channel_args)
|
|
74
|
+
|
|
75
|
+
elif config.tls:
|
|
64
76
|
channel_args = {
|
|
65
77
|
"options": options,
|
|
66
78
|
"credentials": grpc.ssl_channel_credentials(),
|
|
@@ -106,7 +118,10 @@ class GrpcWatcher(FlagStateConnector):
|
|
|
106
118
|
|
|
107
119
|
def _state_change_callback(self, new_state: grpc.ChannelConnectivity) -> None:
|
|
108
120
|
logger.debug(f"gRPC state change: {new_state}")
|
|
109
|
-
if
|
|
121
|
+
if (
|
|
122
|
+
new_state == grpc.ChannelConnectivity.READY
|
|
123
|
+
or new_state == grpc.ChannelConnectivity.IDLE
|
|
124
|
+
):
|
|
110
125
|
if not self.thread or not self.thread.is_alive():
|
|
111
126
|
self.thread = threading.Thread(
|
|
112
127
|
target=self.listen,
|
|
@@ -153,10 +168,20 @@ class GrpcWatcher(FlagStateConnector):
|
|
|
153
168
|
if self.streamline_deadline_seconds > 0
|
|
154
169
|
else {}
|
|
155
170
|
)
|
|
156
|
-
request_args = {
|
|
171
|
+
request_args = {}
|
|
172
|
+
if self.selector is not None:
|
|
173
|
+
request_args["selector"] = self.selector
|
|
174
|
+
if self.provider_id is not None:
|
|
175
|
+
request_args["provider_id"] = self.provider_id
|
|
157
176
|
|
|
158
177
|
while self.active:
|
|
159
178
|
try:
|
|
179
|
+
context_values_request = sync_pb2.GetMetadataRequest()
|
|
180
|
+
context_values_response: sync_pb2.GetMetadataResponse = (
|
|
181
|
+
self.stub.GetMetadata(context_values_request, wait_for_ready=True)
|
|
182
|
+
)
|
|
183
|
+
context_values = MessageToDict(context_values_response)
|
|
184
|
+
|
|
160
185
|
request = sync_pb2.SyncFlagsRequest(**request_args)
|
|
161
186
|
|
|
162
187
|
logger.debug("Setting up gRPC sync flags connection")
|
|
@@ -173,7 +198,8 @@ class GrpcWatcher(FlagStateConnector):
|
|
|
173
198
|
self.emit_provider_ready(
|
|
174
199
|
ProviderEventDetails(
|
|
175
200
|
message="gRPC sync connection established"
|
|
176
|
-
)
|
|
201
|
+
),
|
|
202
|
+
context_values["metadata"],
|
|
177
203
|
)
|
|
178
204
|
self.connected = True
|
|
179
205
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
from openfeature.evaluation_context import EvaluationContext
|
|
4
|
+
from openfeature.hook import Hook, HookContext, HookHints
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class SyncMetadataHook(Hook):
|
|
8
|
+
def __init__(self, context_supplier: typing.Callable[[], EvaluationContext]):
|
|
9
|
+
self.context_supplier = context_supplier
|
|
10
|
+
|
|
11
|
+
def before(
|
|
12
|
+
self, hook_context: HookContext, hints: HookHints
|
|
13
|
+
) -> typing.Optional[EvaluationContext]:
|
|
14
|
+
return self.context_supplier()
|
{openfeature_provider_flagd-0.2.0.dist-info → openfeature_provider_flagd-0.2.1.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openfeature-provider-flagd
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: OpenFeature provider for the flagd flag evaluation engine
|
|
5
5
|
Project-URL: Homepage, https://github.com/open-feature/python-sdk-contrib
|
|
6
6
|
Author-email: OpenFeature <openfeature-core@groups.io>
|
{openfeature_provider_flagd-0.2.0.dist-info → openfeature_provider_flagd-0.2.1.dist-info}/RECORD
RENAMED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
openfeature/.gitignore,sha256=1ZPH4VtVL4bMQmBJXQJxeAyUa74LCtqV1a_yjeDIzSQ,8
|
|
2
2
|
openfeature/contrib/provider/flagd/__init__.py,sha256=WlrcPaCH31dEG1IvrvpeuhAaQ8Ni8LEzDpNM_x-qKOA,65
|
|
3
|
-
openfeature/contrib/provider/flagd/config.py,sha256=
|
|
3
|
+
openfeature/contrib/provider/flagd/config.py,sha256=6a3bA_Kaq_Jfku91vdq3MIcES-Gnh12r_MsvWGJsveg,7720
|
|
4
4
|
openfeature/contrib/provider/flagd/flag_type.py,sha256=rZYfmqQEmtqVVTb8e-d8Wt8ZCnHtf7xPSmYxyU8w0R0,158
|
|
5
|
-
openfeature/contrib/provider/flagd/provider.py,sha256=
|
|
5
|
+
openfeature/contrib/provider/flagd/provider.py,sha256=e9yCN2QZ92Wz7Z2VWa_j5ibOvw-ck6eOPwgJpNrctj8,7810
|
|
6
|
+
openfeature/contrib/provider/flagd/sync_metadata_hook.py,sha256=fd3uRtwDhVlCW9vZhS35p9qENkl6wDHwlFH-L48aPDM,456
|
|
6
7
|
openfeature/contrib/provider/flagd/resolvers/__init__.py,sha256=CzsnsfxJCaD_S1gBf15kkJBVD-gVLKIwDi4W1nE-dXw,181
|
|
7
|
-
openfeature/contrib/provider/flagd/resolvers/grpc.py,sha256=
|
|
8
|
-
openfeature/contrib/provider/flagd/resolvers/in_process.py,sha256=
|
|
8
|
+
openfeature/contrib/provider/flagd/resolvers/grpc.py,sha256=KJTrwZM-XF2-Xw-O4YvrN-Xvn_KqsO9T29lBAjiDS-4,13581
|
|
9
|
+
openfeature/contrib/provider/flagd/resolvers/in_process.py,sha256=ek4T5MsG1YcceyZ1p2yVMawxfnrBFwT1qCCpQqh_coE,4624
|
|
9
10
|
openfeature/contrib/provider/flagd/resolvers/protocol.py,sha256=Wc7oUH6ytPuKg8Lj_3y-_LLkQkuvsow9IiSfmlM8I2o,1402
|
|
10
11
|
openfeature/contrib/provider/flagd/resolvers/process/custom_ops.py,sha256=bZX1At0dRxhghhWz4g-8N-YPobcVfYSv9PTsYh-lZDc,4549
|
|
11
12
|
openfeature/contrib/provider/flagd/resolvers/process/flags.py,sha256=nDXkl80DiJBlSrz0l7xT-DAr6zzZSS0mwOSjvUAV2gY,3255
|
|
12
13
|
openfeature/contrib/provider/flagd/resolvers/process/targeting.py,sha256=qjYgfoJK9B1ghh19cUq7f-VEql7Hh1J7sh0BhnNc_h0,905
|
|
13
14
|
openfeature/contrib/provider/flagd/resolvers/process/connector/__init__.py,sha256=hyYYxRYEnSho5F28M2hbhhtkG4DQTwJjD36ddI0Xs7M,289
|
|
14
|
-
openfeature/contrib/provider/flagd/resolvers/process/connector/file_watcher.py,sha256=
|
|
15
|
-
openfeature/contrib/provider/flagd/resolvers/process/connector/grpc_watcher.py,sha256=
|
|
15
|
+
openfeature/contrib/provider/flagd/resolvers/process/connector/file_watcher.py,sha256=f4jg9tHj94R_PJ4sCZ2f6B1r7Fgm1NqEZr68qH9pYYk,3920
|
|
16
|
+
openfeature/contrib/provider/flagd/resolvers/process/connector/grpc_watcher.py,sha256=l-GgF3MpIEkjrtHyuuSZgOZvgOuBKqgx_NOZImNAyDQ,8392
|
|
16
17
|
openfeature/schemas/protobuf/flagd/evaluation/v1/evaluation_pb2.py,sha256=YPBimdlVBCfnVqxq9uek3H4nyaIR0MhggCAaR0XtIt4,7527
|
|
17
18
|
openfeature/schemas/protobuf/flagd/evaluation/v1/evaluation_pb2.pyi,sha256=afh-fdsmyfS62C-iq7EQsqr_5yZP_QxJXp81Q0Lcllk,18333
|
|
18
19
|
openfeature/schemas/protobuf/flagd/evaluation/v1/evaluation_pb2_grpc.py,sha256=AFwLCOCunFSWGnlt8Asj3pxORfcx168r4jVmt9CLB0I,17189
|
|
@@ -29,7 +30,7 @@ openfeature/schemas/protobuf/sync/v1/sync_service_pb2.py,sha256=Sw0kLvO0wIRXsaFi
|
|
|
29
30
|
openfeature/schemas/protobuf/sync/v1/sync_service_pb2.pyi,sha256=o3YpW_5iQJWjU7IFEsyspeqLyBDC4C_psBNErwziumE,7986
|
|
30
31
|
openfeature/schemas/protobuf/sync/v1/sync_service_pb2_grpc.py,sha256=cAbP4qfaS2Dpze8BH3w-PAJfL7LCA7xZYJfFro5b_2I,6185
|
|
31
32
|
openfeature/schemas/protobuf/sync/v1/sync_service_pb2_grpc.pyi,sha256=4NoAkGicVNxx4yVK5_JvvPn1OGlRdPhqM2wCpkwCjEI,3024
|
|
32
|
-
openfeature_provider_flagd-0.2.
|
|
33
|
-
openfeature_provider_flagd-0.2.
|
|
34
|
-
openfeature_provider_flagd-0.2.
|
|
35
|
-
openfeature_provider_flagd-0.2.
|
|
33
|
+
openfeature_provider_flagd-0.2.1.dist-info/METADATA,sha256=MwEbcjspmlvG0b1RkL4iigjJmd8P0dUg-bJiymkM-Kk,21635
|
|
34
|
+
openfeature_provider_flagd-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
35
|
+
openfeature_provider_flagd-0.2.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
36
|
+
openfeature_provider_flagd-0.2.1.dist-info/RECORD,,
|
{openfeature_provider_flagd-0.2.0.dist-info → openfeature_provider_flagd-0.2.1.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|