Skip to content

Commit b45e3c8

Browse files
authored
chore(flagd): refine typing by adding types-grpcio (#308)
* refine typing by adding types-grpcio Signed-off-by: gruebel <[email protected]> * fix CR comments Signed-off-by: gruebel <[email protected]> --------- Signed-off-by: gruebel <[email protected]>
1 parent fe8130a commit b45e3c8

File tree

6 files changed

+336
-308
lines changed

6 files changed

+336
-308
lines changed

providers/openfeature-provider-flagd/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ dev = [
4040
"pytest>=8.4.0,<9.0.0",
4141
"pytest-bdd>=8.1.0,<9.0.0",
4242
"testcontainers>=4.12.0,<5.0.0",
43+
"types-grpcio>=1.0.0,<2.0.0",
4344
"types-protobuf>=6.30.0,<7.0.0",
4445
"types-pyyaml>=6.0.0,<7.0.0",
4546
]
@@ -97,7 +98,6 @@ disallow_any_generics = false
9798

9899
[[tool.mypy.overrides]]
99100
module = [
100-
"grpc.*",
101101
"json_logic.*",
102102
]
103103
ignore_missing_imports = true

providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/grpc.py

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
from ..config import CacheType, Config
3131
from ..flag_type import FlagType
32+
from .types import GrpcMultiCallableArgs
3233

3334
if typing.TYPE_CHECKING:
3435
from google.protobuf.message import Message
@@ -121,15 +122,16 @@ def _generate_channel(self, config: Config) -> grpc.Channel:
121122
),
122123
]
123124
if config.tls:
124-
channel_args = {
125-
"options": options,
126-
"credentials": grpc.ssl_channel_credentials(),
127-
}
125+
credentials = grpc.ssl_channel_credentials()
128126
if config.cert_path:
129127
with open(config.cert_path, "rb") as f:
130-
channel_args["credentials"] = grpc.ssl_channel_credentials(f.read())
128+
credentials = grpc.ssl_channel_credentials(f.read())
131129

132-
channel = grpc.secure_channel(target, **channel_args)
130+
channel = grpc.secure_channel(
131+
target,
132+
credentials=credentials,
133+
options=options,
134+
)
133135

134136
else:
135137
channel = grpc.insecure_channel(
@@ -220,20 +222,16 @@ def emit_error(self) -> None:
220222

221223
def listen(self) -> None:
222224
logger.debug("gRPC starting listener thread")
223-
call_args = (
224-
{"timeout": self.streamline_deadline_seconds}
225-
if self.streamline_deadline_seconds > 0
226-
else {}
227-
)
225+
call_args: GrpcMultiCallableArgs = {"wait_for_ready": True}
226+
if self.streamline_deadline_seconds > 0:
227+
call_args["timeout"] = self.streamline_deadline_seconds
228228
request = evaluation_pb2.EventStreamRequest()
229229

230230
# defining a never ending loop to recreate the stream
231231
while self.active:
232232
try:
233233
logger.debug("Setting up gRPC sync flags connection")
234-
for message in self.stub.EventStream(
235-
request, wait_for_ready=True, **call_args
236-
):
234+
for message in self.stub.EventStream(request, **call_args):
237235
if message.type == "provider_ready":
238236
self.emit_provider_ready(
239237
ProviderEventDetails(
@@ -309,20 +307,72 @@ def resolve_object_details(
309307
]:
310308
return self._resolve(key, FlagType.OBJECT, default_value, evaluation_context)
311309

310+
@typing.overload
311+
def _resolve(
312+
self,
313+
flag_key: str,
314+
flag_type: FlagType,
315+
default_value: bool,
316+
evaluation_context: typing.Optional[EvaluationContext],
317+
) -> FlagResolutionDetails[bool]: ...
318+
319+
@typing.overload
320+
def _resolve(
321+
self,
322+
flag_key: str,
323+
flag_type: FlagType,
324+
default_value: int,
325+
evaluation_context: typing.Optional[EvaluationContext],
326+
) -> FlagResolutionDetails[int]: ...
327+
328+
@typing.overload
329+
def _resolve(
330+
self,
331+
flag_key: str,
332+
flag_type: FlagType,
333+
default_value: float,
334+
evaluation_context: typing.Optional[EvaluationContext],
335+
) -> FlagResolutionDetails[float]: ...
336+
337+
@typing.overload
338+
def _resolve(
339+
self,
340+
flag_key: str,
341+
flag_type: FlagType,
342+
default_value: str,
343+
evaluation_context: typing.Optional[EvaluationContext],
344+
) -> FlagResolutionDetails[str]: ...
345+
346+
@typing.overload
347+
def _resolve(
348+
self,
349+
flag_key: str,
350+
flag_type: FlagType,
351+
default_value: typing.Union[
352+
typing.Sequence[FlagValueType], typing.Mapping[str, FlagValueType]
353+
],
354+
evaluation_context: typing.Optional[EvaluationContext],
355+
) -> FlagResolutionDetails[
356+
typing.Union[typing.Sequence[FlagValueType], typing.Mapping[str, FlagValueType]]
357+
]: ...
358+
312359
def _resolve( # noqa: PLR0915 C901
313360
self,
314361
flag_key: str,
315362
flag_type: FlagType,
316-
default_value: T,
363+
default_value: FlagValueType,
317364
evaluation_context: typing.Optional[EvaluationContext],
318-
) -> FlagResolutionDetails[T]:
365+
) -> FlagResolutionDetails[FlagValueType]:
319366
if self.cache is not None and flag_key in self.cache:
320-
cached_flag: FlagResolutionDetails[T] = self.cache[flag_key]
367+
cached_flag: FlagResolutionDetails[FlagValueType] = self.cache[flag_key]
321368
cached_flag.reason = Reason.CACHED
322369
return cached_flag
323370

324371
context = self._convert_context(evaluation_context)
325-
call_args = {"timeout": self.deadline, "wait_for_ready": True}
372+
call_args: GrpcMultiCallableArgs = {
373+
"timeout": self.deadline,
374+
"wait_for_ready": True,
375+
}
326376
try:
327377
request: Message
328378
if flag_type == FlagType.BOOLEAN:

providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/process/connector/grpc_watcher.py

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
)
1818

1919
from ....config import Config
20+
from ...types import GrpcMultiCallableArgs
2021
from ..connector import FlagStateConnector
2122
from ..flags import FlagStore
2223

@@ -105,22 +106,23 @@ def _generate_channel(self, config: Config) -> grpc.Channel:
105106
options.append(("grpc.default_authority", config.default_authority))
106107

107108
if config.channel_credentials is not None:
108-
channel_args = {
109-
"options": options,
110-
"credentials": config.channel_credentials,
111-
}
112-
channel = grpc.secure_channel(target, **channel_args)
109+
channel = grpc.secure_channel(
110+
target,
111+
credentials=config.channel_credentials,
112+
options=options,
113+
)
113114

114115
elif config.tls:
115-
channel_args = {
116-
"options": options,
117-
"credentials": grpc.ssl_channel_credentials(),
118-
}
116+
credentials = grpc.ssl_channel_credentials()
119117
if config.cert_path:
120118
with open(config.cert_path, "rb") as f:
121-
channel_args["credentials"] = grpc.ssl_channel_credentials(f.read())
119+
credentials = grpc.ssl_channel_credentials(f.read())
122120

123-
channel = grpc.secure_channel(target, **channel_args)
121+
channel = grpc.secure_channel(
122+
target,
123+
credentials=credentials,
124+
options=options,
125+
)
124126

125127
else:
126128
channel = grpc.insecure_channel(
@@ -227,12 +229,10 @@ def _fetch_metadata(self) -> typing.Optional[sync_pb2.GetMetadataResponse]:
227229
else:
228230
raise e
229231

230-
def listen(self) -> None:
231-
call_args = (
232-
{"timeout": self.streamline_deadline_seconds}
233-
if self.streamline_deadline_seconds > 0
234-
else {}
235-
)
232+
def listen(self) -> None: # noqa: C901
233+
call_args: GrpcMultiCallableArgs = {"wait_for_ready": True}
234+
if self.streamline_deadline_seconds > 0:
235+
call_args["timeout"] = self.streamline_deadline_seconds
236236
request_args = self._create_request_args()
237237

238238
while self.active:
@@ -242,9 +242,7 @@ def listen(self) -> None:
242242
request = sync_pb2.SyncFlagsRequest(**request_args)
243243

244244
logger.debug("Setting up gRPC sync flags connection")
245-
for flag_rsp in self.stub.SyncFlags(
246-
request, wait_for_ready=True, **call_args
247-
):
245+
for flag_rsp in self.stub.SyncFlags(request, **call_args):
248246
flag_str = flag_rsp.flag_configuration
249247
logger.debug(
250248
f"Received flag configuration - {abs(hash(flag_str)) % (10**8)}"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import typing
2+
3+
4+
class GrpcMultiCallableArgs(typing.TypedDict, total=False):
5+
timeout: typing.Optional[float]
6+
wait_for_ready: typing.Optional[bool]

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ dependencies = [
1515
[dependency-groups]
1616
dev = [
1717
"coverage[toml]>=7.10.0,<8.0.0",
18-
"mypy[faster-cache]>=1.17.0,<2.0.0",
18+
"mypy>=1.18.0,<2.0.0",
1919
"pytest>=8.4.0,<9.0.0",
2020
]
2121

0 commit comments

Comments
 (0)