Skip to content

Commit a6558dc

Browse files
authored
fix: Backward compatible type subscriptions/unions (#48)
* fix: Backward compatible type subscriptions/unions Previously, the codebase specified support for Python>=3.8, when it used `|` type union syntax (introduced in 3.10), and subscriptable built-in types (introduced in 3.9). This change uses earlier syntax in order to allow 3.8 interpreters to handle type specific code. Signed-off-by: Sam Lock <sam@swlock.co.uk>
1 parent b84b976 commit a6558dc

File tree

5 files changed

+342
-306
lines changed

5 files changed

+342
-306
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## Unreleased
22

3+
### Bug fixes
4+
5+
- Backward compatible type subscriptions/unions
6+
37
## v0.10.3 (2024-01-18)
48

59
### Chores

cerbos/sdk/_async/_grpc.py

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ async def wrapper(*args, **kwargs):
4040
return wrapper
4141

4242

43-
def get_cert(c: TLSVerify) -> bytes | None:
43+
def get_cert(c: TLSVerify) -> Union[bytes, None]:
4444
try:
4545
if isinstance(c, str):
4646
with open(c, "rb") as f:
@@ -82,10 +82,10 @@ def __init__(
8282
creds: grpc.ChannelCredentials,
8383
methods: List[Dict[str, str]] = None,
8484
tls_verify: TLSVerify = False,
85-
timeout_secs: float | None = None,
85+
timeout_secs: Union[float, None] = None,
8686
request_retries: int = 0,
8787
wait_for_ready: bool = False,
88-
channel_options: dict[str, Any] | None = None,
88+
channel_options: Union[Dict[str, Any], None] = None,
8989
):
9090
if timeout_secs and not isinstance(timeout_secs, (int, float)):
9191
raise TypeError("timeout_secs must be a number type")
@@ -98,7 +98,7 @@ def __init__(
9898
if request_retries < 2:
9999
request_retries = 0
100100

101-
method_config: dict[str, Any] = {}
101+
method_config: Dict[str, Any] = {}
102102

103103
if methods:
104104
method_config["name"] = methods
@@ -155,7 +155,7 @@ class AsyncCerbosClient(AsyncClientBase):
155155
timeout_secs (float): Optional request timeout in seconds (no timeout by default)
156156
request_retries (int): Optional maximum number of retries, including the original attempt. Anything below 2 will be treated as 0 (disabled)
157157
wait_for_ready (bool): Boolean specifying whether RPCs should wait until the connection is ready. Defaults to False
158-
channel_options (dict[str, Any]): Optional gRPC channel options to pass on channel creation. The values need to match the expected types: https://github.com/grpc/grpc/blob/7536d8a849c0096e4c968e7730306872bb5ec674/include/grpc/impl/grpc_types.h
158+
channel_options (Dict[str, Any]): Optional gRPC channel options to pass on channel creation. The values need to match the expected types: https://github.com/grpc/grpc/blob/7536d8a849c0096e4c968e7730306872bb5ec674/include/grpc/impl/grpc_types.h
159159
160160
Example:
161161
with AsyncCerbosClient("localhost:3593") as cerbos:
@@ -174,10 +174,10 @@ def __init__(
174174
host: str,
175175
tls_verify: TLSVerify = False,
176176
playground_instance: str = "",
177-
timeout_secs: float | None = None,
177+
timeout_secs: Union[float, None] = None,
178178
request_retries: int = 0,
179179
wait_for_ready: bool = False,
180-
channel_options: dict[str, Any] | None = None,
180+
channel_options: Union[Dict[str, Any], None] = None,
181181
):
182182
creds: grpc.ChannelCredentials = None
183183
if tls_verify:
@@ -216,8 +216,8 @@ async def check_resources(
216216
self,
217217
principal: engine_pb2.Principal,
218218
resources: List[request_pb2.CheckResourcesRequest.ResourceEntry],
219-
request_id: str | None = None,
220-
aux_data: request_pb2.AuxData | None = None,
219+
request_id: Union[str, None] = None,
220+
aux_data: Union[request_pb2.AuxData, None] = None,
221221
) -> response_pb2.CheckResourcesResponse:
222222
"""Check permissions for a list of resources
223223
@@ -243,8 +243,8 @@ async def is_allowed(
243243
action: str,
244244
principal: engine_pb2.Principal,
245245
resource: engine_pb2.Resource,
246-
request_id: str | None = None,
247-
aux_data: request_pb2.AuxData | None = None,
246+
request_id: Union[str, None] = None,
247+
aux_data: Union[request_pb2.AuxData, None] = None,
248248
) -> bool:
249249
"""Check permission for a single action
250250
@@ -276,8 +276,8 @@ async def plan_resources(
276276
action: str,
277277
principal: engine_pb2.Principal,
278278
resource: engine_pb2.PlanResourcesInput.Resource,
279-
request_id: str | None = None,
280-
aux_data: request_pb2.AuxData | None = None,
279+
request_id: Union[str, None] = None,
280+
aux_data: Union[request_pb2.AuxData, None] = None,
281281
) -> response_pb2.PlanResourcesResponse:
282282
"""Create a query plan for performing the given action on resources of the given kind
283283
@@ -309,7 +309,7 @@ async def server_info(
309309
def with_principal(
310310
self,
311311
principal: engine_pb2.Principal,
312-
aux_data: request_pb2.AuxData | None = None,
312+
aux_data: Union[request_pb2.AuxData, None] = None,
313313
) -> "AsyncPrincipalContext":
314314
"""Fixes the principal for subsequent requests"""
315315

@@ -325,13 +325,13 @@ class AsyncPrincipalContext:
325325

326326
_client: AsyncCerbosClient
327327
_principal: engine_pb2.Principal
328-
_aux_data: request_pb2.AuxData | None
328+
_aux_data: Union[request_pb2.AuxData, None]
329329

330330
def __init__(
331331
self,
332332
client: AsyncCerbosClient,
333333
principal: engine_pb2.Principal,
334-
aux_data: request_pb2.AuxData | None = None,
334+
aux_data: Union[request_pb2.AuxData, None] = None,
335335
):
336336
self._client = client
337337
self._principal = principal
@@ -340,7 +340,7 @@ def __init__(
340340
async def check_resources(
341341
self,
342342
resources: List[request_pb2.CheckResourcesRequest.ResourceEntry],
343-
request_id: str | None = None,
343+
request_id: Union[str, None] = None,
344344
) -> response_pb2.CheckResourcesResponse:
345345
"""Check permissions for a list of resources
346346
@@ -360,8 +360,8 @@ async def plan_resources(
360360
self,
361361
action: str,
362362
resource: engine_pb2.PlanResourcesInput.Resource,
363-
request_id: str | None = None,
364-
aux_data: request_pb2.AuxData | None = None,
363+
request_id: Union[str, None] = None,
364+
aux_data: Union[request_pb2.AuxData, None] = None,
365365
) -> response_pb2.PlanResourcesResponse:
366366
"""Create a query plan for performing the given action on resources of the given kind
367367
@@ -381,7 +381,10 @@ async def plan_resources(
381381
)
382382

383383
async def is_allowed(
384-
self, action: str, resource: engine_pb2.Resource, request_id: str | None = None
384+
self,
385+
action: str,
386+
resource: engine_pb2.Resource,
387+
request_id: Union[str, None] = None,
385388
) -> bool:
386389
"""Check permission for a single action
387390
@@ -400,7 +403,7 @@ async def is_allowed(
400403
)
401404

402405

403-
def _get_request_id(request_id: str | None) -> str:
406+
def _get_request_id(request_id: Union[str, None]) -> str:
404407
if request_id is None:
405408
return str(uuid.uuid4())
406409

@@ -417,7 +420,7 @@ class AsyncCerbosAdminClient(AsyncClientBase):
417420
timeout_secs (float): Optional request timeout in seconds (no timeout by default)
418421
request_retries (int): Optional maximum number of retries, including the original attempt. Anything below 2 will be treated as 0 (disabled)
419422
wait_for_ready (bool): Boolean specifying whether RPCs should wait until the connection is ready. Defaults to False
420-
channel_options (dict[str, Any]): Optional gRPC channel options to pass on channel creation. The values need to match the expected types: https://github.com/grpc/grpc/blob/7536d8a849c0096e4c968e7730306872bb5ec674/include/grpc/impl/grpc_types.h
423+
channel_options (Dict[str, Any]): Optional gRPC channel options to pass on channel creation. The values need to match the expected types: https://github.com/grpc/grpc/blob/7536d8a849c0096e4c968e7730306872bb5ec674/include/grpc/impl/grpc_types.h
421424
422425
Example:
423426
with AsyncCerbosAdminClient("localhost:3593", admin_credentials=AdminCredentials("admin", "some_password")) as cerbos:
@@ -435,12 +438,12 @@ class AsyncCerbosAdminClient(AsyncClientBase):
435438
def __init__(
436439
self,
437440
host: str,
438-
admin_credentials: AdminCredentials | None = None,
441+
admin_credentials: Union[AdminCredentials, None] = None,
439442
tls_verify: TLSVerify = False,
440-
timeout_secs: float | None = None,
443+
timeout_secs: Union[float, None] = None,
441444
request_retries: int = 0,
442445
wait_for_ready: bool = False,
443-
channel_options: dict[str, Any] | None = None,
446+
channel_options: Union[Dict[str, Any], None] = None,
444447
):
445448
admin_credentials = admin_credentials or AdminCredentials()
446449
self._creds_metadata = admin_credentials.metadata()
@@ -612,8 +615,8 @@ async def reload_store(
612615
# @handle_errors
613616
# async def list_audit_logs(
614617
# self,
615-
# start_time: datetime | None = None,
616-
# end_time: datetime | None = None,
618+
# start_time: Union[datetime, None] = None,
619+
# end_time: Union[datetime, None] = None,
617620
# lookup: str = "",
618621
# tail: int = 0,
619622
# kind: request_pb2.ListAuditLogEntriesRequest.Kind = request_pb2.ListAuditLogEntriesRequest.KIND_ACCESS,

cerbos/sdk/_sync/_grpc.py

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def wrapper(*args, **kwargs):
4040
return wrapper
4141

4242

43-
def get_cert(c: TLSVerify) -> bytes | None:
43+
def get_cert(c: TLSVerify) -> Union[bytes, None]:
4444
try:
4545
if isinstance(c, str):
4646
with open(c, "rb") as f:
@@ -82,10 +82,10 @@ def __init__(
8282
creds: grpc.ChannelCredentials,
8383
methods: List[Dict[str, str]] = None,
8484
tls_verify: TLSVerify = False,
85-
timeout_secs: float | None = None,
85+
timeout_secs: Union[float, None] = None,
8686
request_retries: int = 0,
8787
wait_for_ready: bool = False,
88-
channel_options: dict[str, Any] | None = None,
88+
channel_options: Union[Dict[str, Any], None] = None,
8989
):
9090
if timeout_secs and not isinstance(timeout_secs, (int, float)):
9191
raise TypeError("timeout_secs must be a number type")
@@ -98,7 +98,7 @@ def __init__(
9898
if request_retries < 2:
9999
request_retries = 0
100100

101-
method_config: dict[str, Any] = {}
101+
method_config: Dict[str, Any] = {}
102102

103103
if methods:
104104
method_config["name"] = methods
@@ -155,7 +155,7 @@ class CerbosClient(SyncClientBase):
155155
timeout_secs (float): Optional request timeout in seconds (no timeout by default)
156156
request_retries (int): Optional maximum number of retries, including the original attempt. Anything below 2 will be treated as 0 (disabled)
157157
wait_for_ready (bool): Boolean specifying whether RPCs should wait until the connection is ready. Defaults to False
158-
channel_options (dict[str, Any]): Optional gRPC channel options to pass on channel creation. The values need to match the expected types: https://github.com/grpc/grpc/blob/7536d8a849c0096e4c968e7730306872bb5ec674/include/grpc/impl/grpc_types.h
158+
channel_options (Dict[str, Any]): Optional gRPC channel options to pass on channel creation. The values need to match the expected types: https://github.com/grpc/grpc/blob/7536d8a849c0096e4c968e7730306872bb5ec674/include/grpc/impl/grpc_types.h
159159
160160
Example:
161161
with AsyncCerbosClient("localhost:3593") as cerbos:
@@ -174,10 +174,10 @@ def __init__(
174174
host: str,
175175
tls_verify: TLSVerify = False,
176176
playground_instance: str = "",
177-
timeout_secs: float | None = None,
177+
timeout_secs: Union[float, None] = None,
178178
request_retries: int = 0,
179179
wait_for_ready: bool = False,
180-
channel_options: dict[str, Any] | None = None,
180+
channel_options: Union[Dict[str, Any], None] = None,
181181
):
182182
creds: grpc.ChannelCredentials = None
183183
if tls_verify:
@@ -216,8 +216,8 @@ def check_resources(
216216
self,
217217
principal: engine_pb2.Principal,
218218
resources: List[request_pb2.CheckResourcesRequest.ResourceEntry],
219-
request_id: str | None = None,
220-
aux_data: request_pb2.AuxData | None = None,
219+
request_id: Union[str, None] = None,
220+
aux_data: Union[request_pb2.AuxData, None] = None,
221221
) -> response_pb2.CheckResourcesResponse:
222222
"""Check permissions for a list of resources
223223
@@ -243,8 +243,8 @@ def is_allowed(
243243
action: str,
244244
principal: engine_pb2.Principal,
245245
resource: engine_pb2.Resource,
246-
request_id: str | None = None,
247-
aux_data: request_pb2.AuxData | None = None,
246+
request_id: Union[str, None] = None,
247+
aux_data: Union[request_pb2.AuxData, None] = None,
248248
) -> bool:
249249
"""Check permission for a single action
250250
@@ -276,8 +276,8 @@ def plan_resources(
276276
action: str,
277277
principal: engine_pb2.Principal,
278278
resource: engine_pb2.PlanResourcesInput.Resource,
279-
request_id: str | None = None,
280-
aux_data: request_pb2.AuxData | None = None,
279+
request_id: Union[str, None] = None,
280+
aux_data: Union[request_pb2.AuxData, None] = None,
281281
) -> response_pb2.PlanResourcesResponse:
282282
"""Create a query plan for performing the given action on resources of the given kind
283283
@@ -309,7 +309,7 @@ def server_info(
309309
def with_principal(
310310
self,
311311
principal: engine_pb2.Principal,
312-
aux_data: request_pb2.AuxData | None = None,
312+
aux_data: Union[request_pb2.AuxData, None] = None,
313313
) -> "PrincipalContext":
314314
"""Fixes the principal for subsequent requests"""
315315

@@ -325,13 +325,13 @@ class PrincipalContext:
325325

326326
_client: CerbosClient
327327
_principal: engine_pb2.Principal
328-
_aux_data: request_pb2.AuxData | None
328+
_aux_data: Union[request_pb2.AuxData, None]
329329

330330
def __init__(
331331
self,
332332
client: CerbosClient,
333333
principal: engine_pb2.Principal,
334-
aux_data: request_pb2.AuxData | None = None,
334+
aux_data: Union[request_pb2.AuxData, None] = None,
335335
):
336336
self._client = client
337337
self._principal = principal
@@ -340,7 +340,7 @@ def __init__(
340340
def check_resources(
341341
self,
342342
resources: List[request_pb2.CheckResourcesRequest.ResourceEntry],
343-
request_id: str | None = None,
343+
request_id: Union[str, None] = None,
344344
) -> response_pb2.CheckResourcesResponse:
345345
"""Check permissions for a list of resources
346346
@@ -360,8 +360,8 @@ def plan_resources(
360360
self,
361361
action: str,
362362
resource: engine_pb2.PlanResourcesInput.Resource,
363-
request_id: str | None = None,
364-
aux_data: request_pb2.AuxData | None = None,
363+
request_id: Union[str, None] = None,
364+
aux_data: Union[request_pb2.AuxData, None] = None,
365365
) -> response_pb2.PlanResourcesResponse:
366366
"""Create a query plan for performing the given action on resources of the given kind
367367
@@ -381,7 +381,10 @@ def plan_resources(
381381
)
382382

383383
def is_allowed(
384-
self, action: str, resource: engine_pb2.Resource, request_id: str | None = None
384+
self,
385+
action: str,
386+
resource: engine_pb2.Resource,
387+
request_id: Union[str, None] = None,
385388
) -> bool:
386389
"""Check permission for a single action
387390
@@ -400,7 +403,7 @@ def is_allowed(
400403
)
401404

402405

403-
def _get_request_id(request_id: str | None) -> str:
406+
def _get_request_id(request_id: Union[str, None]) -> str:
404407
if request_id is None:
405408
return str(uuid.uuid4())
406409

@@ -417,7 +420,7 @@ class CerbosAdminClient(SyncClientBase):
417420
timeout_secs (float): Optional request timeout in seconds (no timeout by default)
418421
request_retries (int): Optional maximum number of retries, including the original attempt. Anything below 2 will be treated as 0 (disabled)
419422
wait_for_ready (bool): Boolean specifying whether RPCs should wait until the connection is ready. Defaults to False
420-
channel_options (dict[str, Any]): Optional gRPC channel options to pass on channel creation. The values need to match the expected types: https://github.com/grpc/grpc/blob/7536d8a849c0096e4c968e7730306872bb5ec674/include/grpc/impl/grpc_types.h
423+
channel_options (Dict[str, Any]): Optional gRPC channel options to pass on channel creation. The values need to match the expected types: https://github.com/grpc/grpc/blob/7536d8a849c0096e4c968e7730306872bb5ec674/include/grpc/impl/grpc_types.h
421424
422425
Example:
423426
with AsyncCerbosAdminClient("localhost:3593", admin_credentials=AdminCredentials("admin", "some_password")) as cerbos:
@@ -435,12 +438,12 @@ class CerbosAdminClient(SyncClientBase):
435438
def __init__(
436439
self,
437440
host: str,
438-
admin_credentials: AdminCredentials | None = None,
441+
admin_credentials: Union[AdminCredentials, None] = None,
439442
tls_verify: TLSVerify = False,
440-
timeout_secs: float | None = None,
443+
timeout_secs: Union[float, None] = None,
441444
request_retries: int = 0,
442445
wait_for_ready: bool = False,
443-
channel_options: dict[str, Any] | None = None,
446+
channel_options: Union[Dict[str, Any], None] = None,
444447
):
445448
admin_credentials = admin_credentials or AdminCredentials()
446449
self._creds_metadata = admin_credentials.metadata()
@@ -608,8 +611,8 @@ def reload_store(self, wait: bool = False) -> response_pb2.ReloadStoreResponse:
608611
# @handle_errors
609612
# async def list_audit_logs(
610613
# self,
611-
# start_time: datetime | None = None,
612-
# end_time: datetime | None = None,
614+
# start_time: Union[datetime, None] = None,
615+
# end_time: Union[datetime, None] = None,
613616
# lookup: str = "",
614617
# tail: int = 0,
615618
# kind: request_pb2.ListAuditLogEntriesRequest.Kind = request_pb2.ListAuditLogEntriesRequest.KIND_ACCESS,

0 commit comments

Comments
 (0)