Skip to content

Commit f7428b2

Browse files
authored
Merge pull request #34 from aserto-dev/update-bindings
Update bindings and expose InvalidArgmentError
2 parents 1b5fa08 + fb222d5 commit f7428b2

File tree

17 files changed

+688
-518
lines changed

17 files changed

+688
-518
lines changed

.github/workflows/ci.yaml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ on:
1717
env:
1818
VAULT_ADDR: https://vault.eng.aserto.com/
1919
PYTHON_VERSION: "3.9"
20-
POETRY_VERSION: "1.8.3"
21-
TOPAZ_VERSION: "0.32.38"
20+
POETRY_VERSION: "2.1.1"
21+
TOPAZ_VERSION: "0.32.56"
2222

2323
jobs:
2424
test:
@@ -119,10 +119,7 @@ jobs:
119119
poetry publish
120120
-
121121
name: Bump version
122-
id: bump
123-
uses: callowayproject/bump-my-version@master
124-
with:
125-
args: patch
122+
run: poetry version patch
126123
-
127124
name: Commit changes
128125
uses: EndBug/add-and-commit@v9

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ dist
22
__pycache__
33
.DS_Store
44
.env
5+
.envrc
56
.mypy_cache
67
.pytest_cache
78
.vscode
89
.coverage
910
.python-version
1011
.ext
12+
.dmypy.json

poetry.lock

Lines changed: 274 additions & 246 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "aserto"
3-
version = "0.32.1"
3+
version = "0.32.2"
44
description = "Aserto API client"
55
readme = "README.md"
66
authors = ["Aserto, Inc. <[email protected]>"]
@@ -31,18 +31,16 @@ packages = [
3131
[tool.poetry.dependencies]
3232
python = "^3.9"
3333
aiohttp = "^3.10.2"
34-
grpcio = "^1.64.1"
35-
protobuf = "^5.27.2"
36-
aserto-authorizer = "^0.20.3"
37-
aserto-directory = "^0.33.5"
38-
certifi = ">=2024.8.30"
34+
aserto-directory = "^0.33.8"
35+
aserto-authorizer = "^0.20.7"
3936

4037
[tool.poetry.group.dev.dependencies]
41-
black = "^24.0"
42-
isort= "^5.9.0"
38+
black = "^25.1.0"
39+
isort = "^6.0.1"
4340
pytest-asyncio = "^0.23"
4441
pyright = "^1.1.0"
4542
requests = "^2.31.0"
43+
grpc-stubs = ">=1.53.0.5"
4644

4745
[tool.black]
4846
line-length = 100
@@ -51,6 +49,16 @@ target-version = ["py38"]
5149
[tool.isort]
5250
profile = "black"
5351

52+
[tool.pylint]
53+
max-line-length = 100
54+
disable = [
55+
"missing-module-docstring",
56+
"missing-class-docstring",
57+
"missing-function-docstring",
58+
"too-many-arguments",
59+
"too-many-positional-arguments",
60+
"too-many-public-methods",
61+
]
5462

5563
[build-system]
5664
requires = ["poetry-core>=1.0.0"]

src/aserto/client/_typing.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/aserto/client/authorizer/__init__.py

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,33 @@
11
import datetime
22
import typing
33

4-
import aserto.authorizer.v2 as authorizer
5-
import aserto.authorizer.v2.api as api
64
import grpc
7-
import grpc.aio as grpcaio
5+
6+
import aserto.authorizer.v2 as authorizer
87
from aserto.authorizer.v2 import (
98
CompileResponse,
109
GetPolicyResponse,
1110
ListPoliciesResponse,
1211
QueryOptions,
1312
QueryResponse,
1413
)
14+
15+
from aserto.authorizer.v2 import api
1516
from aserto.authorizer.v2.api import IdentityContext, IdentityType
1617

1718
import aserto.client._deadline as timeout
18-
import aserto.client.authorizer.helpers as helpers
1919
import aserto.client.resource_context as res_ctx
20+
from aserto.client.authorizer import helpers
2021
from aserto.client.authorizer.helpers import DecisionTree
2122
from aserto.client.identity import Identity
2223
from aserto.client.options import AuthorizerOptions
2324
from aserto.client.resource_context import ResourceContext
2425

26+
if typing.TYPE_CHECKING:
27+
Metadata = grpc.Metadata
28+
else:
29+
Metadata = typing.NewType("Metadata", typing.Tuple)
30+
2531

2632
class AuthorizerClient:
2733
def __init__(
@@ -48,16 +54,16 @@ def _headers(self) -> typing.Mapping[str, str]:
4854
return self._options.auth_headers
4955

5056
@property
51-
def _metadata(self) -> grpcaio.Metadata:
52-
return grpcaio.Metadata(*tuple(self._headers.items()))
57+
def _metadata(self) -> Metadata:
58+
return tuple(self._headers.items())
5359

5460
def decision_tree(
5561
self,
5662
*,
5763
policy_path_root: str,
5864
decisions: typing.Sequence[str],
59-
policy_instance_name: typing.Optional[str] = None,
60-
policy_instance_label: typing.Optional[str] = None,
65+
policy_instance_name: str = "",
66+
policy_instance_label: str = "",
6167
resource_context: typing.Optional[ResourceContext] = None,
6268
policy_path_separator: typing.Optional[typing.Literal["DOT", "SLASH"]] = None,
6369
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
@@ -93,8 +99,8 @@ def decisions(
9399
*,
94100
policy_path: str,
95101
decisions: typing.Sequence[str],
96-
policy_instance_name: typing.Optional[str],
97-
policy_instance_label: typing.Optional[str] = None,
102+
policy_instance_name: str = "",
103+
policy_instance_label: str = "",
98104
resource_context: typing.Optional[ResourceContext] = None,
99105
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
100106
) -> typing.Dict[str, bool]:
@@ -129,8 +135,8 @@ def query(
129135
input: str,
130136
policy_path: str,
131137
decisions: typing.Sequence[str],
132-
policy_instance_name: typing.Optional[str],
133-
policy_instance_label: typing.Optional[str] = None,
138+
policy_instance_name: str = "",
139+
policy_instance_label: str = "",
134140
resource_context: typing.Optional[ResourceContext] = None,
135141
options: typing.Optional[QueryOptions] = None,
136142
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
@@ -168,8 +174,8 @@ def compile(
168174
disable_inlining: typing.Sequence[str],
169175
policy_path: str,
170176
decisions: typing.Sequence[str],
171-
policy_instance_name: typing.Optional[str],
172-
policy_instance_label: typing.Optional[str] = None,
177+
policy_instance_name: str,
178+
policy_instance_label: str = "",
173179
resource_context: typing.Optional[ResourceContext] = None,
174180
options: typing.Optional[QueryOptions] = None,
175181
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
@@ -203,8 +209,8 @@ def compile(
203209
def list_policies(
204210
self,
205211
*,
206-
policy_instance_name: typing.Optional[str],
207-
policy_instance_label: typing.Optional[str] = None,
212+
policy_instance_name: str,
213+
policy_instance_label: str = "",
208214
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
209215
) -> ListPoliciesResponse:
210216
response = self.client.ListPolicies(
@@ -226,8 +232,8 @@ def get_policy(
226232
self,
227233
*,
228234
id: str,
229-
policy_instance_name: typing.Optional[str],
230-
policy_instance_label: typing.Optional[str] = None,
235+
policy_instance_name: str,
236+
policy_instance_label: str = "",
231237
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
232238
) -> GetPolicyResponse:
233239
response = self.client.GetPolicy(

src/aserto/client/authorizer/aio/__init__.py

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,34 @@
11
import datetime
22
import typing
33

4-
import aserto.authorizer.v2 as authorizer
5-
import aserto.authorizer.v2.api as api
64
import grpc.aio as grpc
5+
from grpc import ssl_channel_credentials
6+
7+
import aserto.authorizer.v2 as authorizer
78
from aserto.authorizer.v2 import (
89
CompileResponse,
910
GetPolicyResponse,
1011
ListPoliciesResponse,
1112
QueryOptions,
1213
QueryResponse,
1314
)
15+
16+
import aserto.authorizer.v2.api as api
1417
from aserto.authorizer.v2.api import IdentityContext, IdentityType
15-
from grpc import ssl_channel_credentials
1618

1719
import aserto.client._deadline as timeout
18-
import aserto.client.authorizer.helpers as helpers
1920
import aserto.client.resource_context as res_ctx
21+
from aserto.client.authorizer import helpers
2022
from aserto.client.authorizer.helpers import DecisionTree
2123
from aserto.client.identity import Identity
2224
from aserto.client.options import AuthorizerOptions
2325
from aserto.client.resource_context import ResourceContext
2426

27+
if typing.TYPE_CHECKING:
28+
AuthorizerAsyncStub = authorizer.AuthorizerAsyncStub
29+
else:
30+
AuthorizerAsyncStub = authorizer.AuthorizerStub
31+
2532

2633
class AuthorizerClient:
2734
def __init__(
@@ -41,7 +48,7 @@ def __init__(
4148
target=self._options.url,
4249
credentials=ssl_channel_credentials(self._options.cert),
4350
)
44-
self.client = authorizer.AuthorizerStub(self._channel)
51+
self.client = typing.cast(AuthorizerAsyncStub, authorizer.AuthorizerStub(self._channel))
4552

4653
@property
4754
def _headers(self) -> typing.Mapping[str, str]:
@@ -56,8 +63,8 @@ async def decision_tree(
5663
*,
5764
policy_path_root: str,
5865
decisions: typing.Sequence[str],
59-
policy_instance_name: typing.Optional[str] = None,
60-
policy_instance_label: typing.Optional[str] = None,
66+
policy_instance_name: str = "",
67+
policy_instance_label: str = "",
6168
resource_context: typing.Optional[ResourceContext] = None,
6269
policy_path_separator: typing.Optional[typing.Literal["DOT", "SLASH"]] = None,
6370
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
@@ -93,8 +100,8 @@ async def decisions(
93100
*,
94101
policy_path: str,
95102
decisions: typing.Sequence[str],
96-
policy_instance_name: typing.Optional[str],
97-
policy_instance_label: typing.Optional[str] = None,
103+
policy_instance_name: str = "",
104+
policy_instance_label: str = "",
98105
resource_context: typing.Optional[ResourceContext] = None,
99106
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
100107
) -> typing.Dict[str, bool]:
@@ -129,8 +136,8 @@ async def query(
129136
input: str,
130137
policy_path: str,
131138
decisions: typing.Sequence[str],
132-
policy_instance_name: typing.Optional[str],
133-
policy_instance_label: typing.Optional[str] = None,
139+
policy_instance_name: str = "",
140+
policy_instance_label: str = "",
134141
resource_context: typing.Optional[ResourceContext] = None,
135142
options: typing.Optional[QueryOptions] = None,
136143
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
@@ -168,8 +175,8 @@ async def compile(
168175
disable_inlining: typing.Sequence[str],
169176
policy_path: str,
170177
decisions: typing.Sequence[str],
171-
policy_instance_name: typing.Optional[str],
172-
policy_instance_label: typing.Optional[str] = None,
178+
policy_instance_name: str = "",
179+
policy_instance_label: str = "",
173180
resource_context: typing.Optional[ResourceContext] = None,
174181
options: typing.Optional[QueryOptions] = None,
175182
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
@@ -203,8 +210,8 @@ async def compile(
203210
async def list_policies(
204211
self,
205212
*,
206-
policy_instance_name: typing.Optional[str],
207-
policy_instance_label: typing.Optional[str] = None,
213+
policy_instance_name: str = "",
214+
policy_instance_label: str = "",
208215
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
209216
) -> ListPoliciesResponse:
210217
response = await self.client.ListPolicies(
@@ -226,8 +233,8 @@ async def get_policy(
226233
self,
227234
*,
228235
id: str,
229-
policy_instance_name: typing.Optional[str],
230-
policy_instance_label: typing.Optional[str] = None,
236+
policy_instance_name: str = "",
237+
policy_instance_label: str = "",
231238
deadline: typing.Optional[typing.Union[datetime.datetime, datetime.timedelta]] = None,
232239
) -> GetPolicyResponse:
233240
return await self.client.GetPolicy(
@@ -244,7 +251,13 @@ async def get_policy(
244251
),
245252
)
246253

247-
async def close(self) -> None:
248-
"""Closes the gRPC channel"""
254+
async def close(self, grace: typing.Optional[float] = None) -> None:
255+
"""Closes the authorizer client's connection to the server.
249256
250-
await self._channel.close()
257+
If a grace period is specified, this method waits until all active
258+
requests are finished or until the grace period is reached. Requests that haven't
259+
been terminated within the grace period are aborted.
260+
If a grace period is not specified (by passing None for grace),
261+
all existing requests are cancelled immediately.
262+
"""
263+
await self._channel.close(grace)

src/aserto/client/authorizer/helpers.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22

33
from aserto.authorizer.v2 import DecisionTreeResponse, PathSeparator
44

5-
from aserto.client._typing import assert_unreachable
6-
75
DecisionTree = Dict[str, Dict[str, bool]]
86

97

10-
def policy_path_separator_field(policy_path_separator: Literal["DOT", "SLASH"]) -> PathSeparator:
8+
def policy_path_separator_field(
9+
policy_path_separator: Literal["DOT", "SLASH"],
10+
) -> PathSeparator.ValueType:
1111
if policy_path_separator == "DOT":
1212
return PathSeparator.PATH_SEPARATOR_DOT
13-
elif policy_path_separator == "SLASH":
13+
if policy_path_separator == "SLASH":
1414
return PathSeparator.PATH_SEPARATOR_SLASH
15-
else:
16-
assert_unreachable(policy_path_separator)
15+
16+
raise ValueError(f"Invalid PathSeparator: {policy_path_separator}")
1717

1818

1919
def validate_decision_tree(response: DecisionTreeResponse) -> DecisionTree:

src/aserto/client/directory/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from typing import Literal, Tuple
22

3+
from grpc import RpcError, StatusCode
4+
35
from aserto.client.directory.channels import Channels
46

57
__all__ = ["Channels"]
@@ -9,6 +11,10 @@ class NotFoundError(Exception):
911
pass
1012

1113

14+
class InvalidArgumentError(Exception):
15+
pass
16+
17+
1218
class ConfigError(Exception):
1319
pass
1420

@@ -20,3 +26,10 @@ def get_metadata(api_key, tenant_id) -> Tuple[Tuple[str, str], ...]:
2026
if tenant_id:
2127
md += (("aserto-tenant-id", tenant_id),)
2228
return md
29+
30+
31+
def translate_rpc_error(err: RpcError) -> None:
32+
if err.code() == StatusCode.NOT_FOUND:
33+
raise NotFoundError(err.details()) from err
34+
if err.code() == StatusCode.INVALID_ARGUMENT:
35+
raise InvalidArgumentError(err.details()) from err

0 commit comments

Comments
 (0)