diff --git a/.openapi-generator/FILES b/.openapi-generator/FILES index 0305274..7ebaedc 100644 --- a/.openapi-generator/FILES +++ b/.openapi-generator/FILES @@ -1,18 +1,14 @@ .codecov.yml .fossa.yml .github/CODEOWNERS +.github/dependabot.yaml .github/ISSUE_TEMPLATE/bug_report.yaml .github/ISSUE_TEMPLATE/config.yaml .github/ISSUE_TEMPLATE/feature_request.yaml -.github/dependabot.yaml .gitignore .snyk CHANGELOG.md CONTRIBUTING.md -LICENSE -NOTICE.txt -README.md -VERSION.txt docs/AbortedMessageResponse.md docs/Any.md docs/Assertion.md @@ -58,6 +54,7 @@ docs/NotFoundErrorCode.md docs/NullValue.md docs/ObjectRelation.md docs/OpenFgaApi.md +docs/opentelemetry.md docs/PathUnknownErrorMessageResponse.md docs/ReadAssertionsResponse.md docs/ReadAuthorizationModelResponse.md @@ -72,8 +69,8 @@ docs/RelationshipCondition.md docs/SourceInfo.md docs/Status.md docs/Store.md -docs/StreamResultOfStreamedListObjectsResponse.md docs/StreamedListObjectsResponse.md +docs/StreamResultOfStreamedListObjectsResponse.md docs/Tuple.md docs/TupleChange.md docs/TupleKey.md @@ -81,20 +78,20 @@ docs/TupleKeyWithoutCondition.md docs/TupleOperation.md docs/TupleToUserset.md docs/TypeDefinition.md -docs/TypeName.md docs/TypedWildcard.md +docs/TypeName.md docs/UnauthenticatedResponse.md docs/UnprocessableContentErrorCode.md docs/UnprocessableContentMessageResponse.md docs/User.md -docs/UserTypeFilter.md docs/Users.md docs/Userset.md +docs/Usersets.md docs/UsersetTree.md docs/UsersetTreeDifference.md docs/UsersetTreeTupleToUserset.md docs/UsersetUser.md -docs/Usersets.md +docs/UserTypeFilter.md docs/ValidationErrorMessageResponse.md docs/WriteAssertionsRequest.md docs/WriteAuthorizationModelRequest.md @@ -102,28 +99,29 @@ docs/WriteAuthorizationModelResponse.md docs/WriteRequest.md docs/WriteRequestDeletes.md docs/WriteRequestWrites.md -docs/opentelemetry.md -example/Makefile -example/README.md example/example1/example1.py example/example1/requirements.txt example/example1/setup.cfg example/example1/setup.py +example/Makefile example/opentelemetry/.env.example example/opentelemetry/.gitignore -example/opentelemetry/README.md example/opentelemetry/main.py +example/opentelemetry/README.md example/opentelemetry/requirements.txt example/opentelemetry/setup.cfg example/opentelemetry/setup.py -example/streamed-list-objects/README.md +example/README.md example/streamed-list-objects/example.py example/streamed-list-objects/model.json +example/streamed-list-objects/README.md +LICENSE +NOTICE.txt openfga_sdk/__init__.py +openfga_sdk/api_client.py openfga_sdk/api/__init__.py -openfga_sdk/api/open_fga_api.py openfga_sdk/api/open_fga_api_sync.py -openfga_sdk/api_client.py +openfga_sdk/api/open_fga_api.py openfga_sdk/client/__init__.py openfga_sdk/client/client.py openfga_sdk/client/configuration.py @@ -152,8 +150,8 @@ openfga_sdk/help.py openfga_sdk/models/__init__.py openfga_sdk/models/aborted_message_response.py openfga_sdk/models/any.py -openfga_sdk/models/assertion.py openfga_sdk/models/assertion_tuple_key.py +openfga_sdk/models/assertion.py openfga_sdk/models/auth_error_code.py openfga_sdk/models/authorization_model.py openfga_sdk/models/batch_check_item.py @@ -161,21 +159,21 @@ openfga_sdk/models/batch_check_request.py openfga_sdk/models/batch_check_response.py openfga_sdk/models/batch_check_single_result.py openfga_sdk/models/check_error.py -openfga_sdk/models/check_request.py openfga_sdk/models/check_request_tuple_key.py +openfga_sdk/models/check_request.py openfga_sdk/models/check_response.py openfga_sdk/models/computed.py -openfga_sdk/models/condition.py openfga_sdk/models/condition_metadata.py openfga_sdk/models/condition_param_type_ref.py +openfga_sdk/models/condition.py openfga_sdk/models/consistency_preference.py openfga_sdk/models/contextual_tuple_keys.py openfga_sdk/models/create_store_request.py openfga_sdk/models/create_store_response.py openfga_sdk/models/difference.py openfga_sdk/models/error_code.py -openfga_sdk/models/expand_request.py openfga_sdk/models/expand_request_tuple_key.py +openfga_sdk/models/expand_request.py openfga_sdk/models/expand_response.py openfga_sdk/models/fga_object.py openfga_sdk/models/forbidden_response.py @@ -199,8 +197,8 @@ openfga_sdk/models/read_assertions_response.py openfga_sdk/models/read_authorization_model_response.py openfga_sdk/models/read_authorization_models_response.py openfga_sdk/models/read_changes_response.py -openfga_sdk/models/read_request.py openfga_sdk/models/read_request_tuple_key.py +openfga_sdk/models/read_request.py openfga_sdk/models/read_response.py openfga_sdk/models/relation_metadata.py openfga_sdk/models/relation_reference.py @@ -210,34 +208,34 @@ openfga_sdk/models/status.py openfga_sdk/models/store.py openfga_sdk/models/stream_result_of_streamed_list_objects_response.py openfga_sdk/models/streamed_list_objects_response.py -openfga_sdk/models/tuple.py openfga_sdk/models/tuple_change.py -openfga_sdk/models/tuple_key.py openfga_sdk/models/tuple_key_without_condition.py +openfga_sdk/models/tuple_key.py openfga_sdk/models/tuple_operation.py openfga_sdk/models/tuple_to_userset.py +openfga_sdk/models/tuple.py openfga_sdk/models/type_definition.py openfga_sdk/models/type_name.py openfga_sdk/models/typed_wildcard.py openfga_sdk/models/unauthenticated_response.py openfga_sdk/models/unprocessable_content_error_code.py openfga_sdk/models/unprocessable_content_message_response.py -openfga_sdk/models/user.py openfga_sdk/models/user_type_filter.py +openfga_sdk/models/user.py openfga_sdk/models/users.py -openfga_sdk/models/userset.py -openfga_sdk/models/userset_tree.py openfga_sdk/models/userset_tree_difference.py openfga_sdk/models/userset_tree_tuple_to_userset.py +openfga_sdk/models/userset_tree.py openfga_sdk/models/userset_user.py +openfga_sdk/models/userset.py openfga_sdk/models/usersets.py openfga_sdk/models/validation_error_message_response.py openfga_sdk/models/write_assertions_request.py openfga_sdk/models/write_authorization_model_request.py openfga_sdk/models/write_authorization_model_response.py -openfga_sdk/models/write_request.py openfga_sdk/models/write_request_deletes.py openfga_sdk/models/write_request_writes.py +openfga_sdk/models/write_request.py openfga_sdk/oauth2.py openfga_sdk/rest.py openfga_sdk/sync/__init__.py @@ -255,15 +253,16 @@ openfga_sdk/telemetry/metrics.py openfga_sdk/telemetry/telemetry.py openfga_sdk/validation.py pyproject.toml +README.md requirements.txt setup.py test-requirements.txt +test/__init__.py test/_/configuration_test.py test/_/credentials_test.py test/_/oauth2_test.py test/_/rest_test.py test/_/validation_test.py -test/__init__.py test/api/__init__.py test/client/__init__.py test/client/client_test.py @@ -280,3 +279,4 @@ test/telemetry/histograms_test.py test/telemetry/metrics_test.py test/telemetry/telemetry_test.py test/test_open_fga_api.py +VERSION.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index db9d9d2..7082413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog -## [Unreleased](https://github.com/openfga/python-sdk/compare/v0.9.4...HEAD) +## [Unreleased](https://github.com/openfga/python-sdk/compare/v0.9.5...HEAD) + +### [0.9.5](https://github.com/openfga/python-sdk/compare/v0.9.4...0.9.5) (2025-07-09) + +- fix: aiohttp.ClientResponse.data should be awaited (#197) - thanks @cmbernard333 ### [0.9.4](https://github.com/openfga/python-sdk/compare/v0.9.3...0.9.4) (2025-04-30) diff --git a/README.md b/README.md index 85f35a6..f39b9bf 100644 --- a/README.md +++ b/README.md @@ -724,6 +724,8 @@ Similar to [check](#check), but instead of checking a single user-object relatio [API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/BatchCheck) +> **Note**: The order of `batch_check` results is not guaranteed to match the order of the checks provided. Use `correlation_id` to pair responses with requests. + ```python # from openfga_sdk import OpenFgaClient # from openfga_sdk.client.models import ( diff --git a/VERSION.txt b/VERSION.txt index a602fc9..b0bb878 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.9.4 +0.9.5 diff --git a/docs/OpenFgaApi.md b/docs/OpenFgaApi.md index bce2198..a485182 100644 --- a/docs/OpenFgaApi.md +++ b/docs/OpenFgaApi.md @@ -779,7 +779,7 @@ No authorization required Get tuples from the store that matches a query, without following userset rewrite rules -The Read API will return the tuples for a certain store that match a query filter specified in the body of the request. The API doesn't guarantee order by any field. It is different from the `/stores/{store_id}/expand` API in that it only returns relationship tuples that are stored in the system and satisfy the query. In the body: 1. `tuple_key` is optional. If not specified, it will return all tuples in the store. 2. `tuple_key.object` is mandatory if `tuple_key` is specified. It can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 3. `tuple_key.user` is mandatory if tuple_key is specified in the case the `tuple_key.object` is a type only. If tuple_key.user is specified, it needs to be a full object (e.g., `type:user_id`). ## Examples ### Query for all objects in a type definition To query for all objects that `user:bob` has `reader` relationship in the `document` type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and a continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `user:bob` has a `reader` relationship with 1 document `document:2021-budget`. Note that this API, unlike the List Objects API, does not evaluate the tuples in the store. The continuation token will be empty if there are no more tuples to query. ### Query for all stored relationship tuples that have a particular relation and object To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`). Note that, even if the model said that all `writers` are also `readers`, the API will not return writers such as `user:anne` because it only returns tuples and does not evaluate them. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`) and 1 `writer` (`user:anne`). +The Read API will return the tuples for a certain store that match a query filter specified in the body of the request. The API doesn't guarantee order by any field. It is different from the `/stores/{store_id}/expand` API in that it only returns relationship tuples that are stored in the system and satisfy the query. In the body: 1. `tuple_key` is optional. If not specified, it will return all tuples in the store. 2. `tuple_key.object` is mandatory if `tuple_key` is specified. It can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 3. `tuple_key.user` is mandatory if tuple_key is specified in the case the `tuple_key.object` is a type only. ## Examples ### Query for all objects in a type definition To query for all objects that `user:bob` has `reader` relationship in the `document` type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and a continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `user:bob` has a `reader` relationship with 1 document `document:2021-budget`. Note that this API, unlike the List Objects API, does not evaluate the tuples in the store. The continuation token will be empty if there are no more tuples to query. ### Query for all stored relationship tuples that have a particular relation and object To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`). Note that, even if the model said that all `writers` are also `readers`, the API will not return writers such as `user:anne` because it only returns tuples and does not evaluate them. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`) and 1 `writer` (`user:anne`). ### Example diff --git a/example/example1/requirements.txt b/example/example1/requirements.txt index 29275f2..c351dfa 100644 --- a/example/example1/requirements.txt +++ b/example/example1/requirements.txt @@ -4,7 +4,7 @@ attrs >= 23.1.0 frozenlist >= 1.4.1 idna >= 3.6 multidict >= 6.0.4 -openfga-sdk >= 0.9.4 +openfga-sdk >= 0.9.5 python-dateutil >= 2.8.2 urllib3 >= 2.1.0 yarl >= 1.9.4 diff --git a/example/example1/setup.py b/example/example1/setup.py index 77787f3..6a2f4a5 100644 --- a/example/example1/setup.py +++ b/example/example1/setup.py @@ -15,7 +15,7 @@ NAME = "example1" VERSION = "0.0.1" -REQUIRES = ["openfga-sdk >= 0.9.4"] +REQUIRES = ["openfga-sdk >= 0.9.5"] setup( name=NAME, diff --git a/openfga_sdk/__init__.py b/openfga_sdk/__init__.py index e57a523..caeb2cf 100644 --- a/openfga_sdk/__init__.py +++ b/openfga_sdk/__init__.py @@ -10,7 +10,7 @@ NOTE: This file was auto generated by OpenAPI Generator (https://openapi-generator.tech). DO NOT EDIT. """ -__version__ = "0.9.4" +__version__ = "0.9.5" from openfga_sdk.api.open_fga_api import OpenFgaApi from openfga_sdk.api_client import ApiClient diff --git a/openfga_sdk/api/open_fga_api.py b/openfga_sdk/api/open_fga_api.py index 2be2fbf..bac1b3a 100644 --- a/openfga_sdk/api/open_fga_api.py +++ b/openfga_sdk/api/open_fga_api.py @@ -1599,7 +1599,7 @@ async def list_users_with_http_info(self, body, **kwargs): async def read(self, body, **kwargs): """Get tuples from the store that matches a query, without following userset rewrite rules - The Read API will return the tuples for a certain store that match a query filter specified in the body of the request. The API doesn't guarantee order by any field. It is different from the `/stores/{store_id}/expand` API in that it only returns relationship tuples that are stored in the system and satisfy the query. In the body: 1. `tuple_key` is optional. If not specified, it will return all tuples in the store. 2. `tuple_key.object` is mandatory if `tuple_key` is specified. It can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 3. `tuple_key.user` is mandatory if tuple_key is specified in the case the `tuple_key.object` is a type only. If tuple_key.user is specified, it needs to be a full object (e.g., `type:user_id`). ## Examples ### Query for all objects in a type definition To query for all objects that `user:bob` has `reader` relationship in the `document` type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and a continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `user:bob` has a `reader` relationship with 1 document `document:2021-budget`. Note that this API, unlike the List Objects API, does not evaluate the tuples in the store. The continuation token will be empty if there are no more tuples to query. ### Query for all stored relationship tuples that have a particular relation and object To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`). Note that, even if the model said that all `writers` are also `readers`, the API will not return writers such as `user:anne` because it only returns tuples and does not evaluate them. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`) and 1 `writer` (`user:anne`). + The Read API will return the tuples for a certain store that match a query filter specified in the body of the request. The API doesn't guarantee order by any field. It is different from the `/stores/{store_id}/expand` API in that it only returns relationship tuples that are stored in the system and satisfy the query. In the body: 1. `tuple_key` is optional. If not specified, it will return all tuples in the store. 2. `tuple_key.object` is mandatory if `tuple_key` is specified. It can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 3. `tuple_key.user` is mandatory if tuple_key is specified in the case the `tuple_key.object` is a type only. ## Examples ### Query for all objects in a type definition To query for all objects that `user:bob` has `reader` relationship in the `document` type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and a continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `user:bob` has a `reader` relationship with 1 document `document:2021-budget`. Note that this API, unlike the List Objects API, does not evaluate the tuples in the store. The continuation token will be empty if there are no more tuples to query. ### Query for all stored relationship tuples that have a particular relation and object To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`). Note that, even if the model said that all `writers` are also `readers`, the API will not return writers such as `user:anne` because it only returns tuples and does not evaluate them. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`) and 1 `writer` (`user:anne`). >>> thread = await api.read(body) @@ -1626,7 +1626,7 @@ async def read(self, body, **kwargs): async def read_with_http_info(self, body, **kwargs): """Get tuples from the store that matches a query, without following userset rewrite rules - The Read API will return the tuples for a certain store that match a query filter specified in the body of the request. The API doesn't guarantee order by any field. It is different from the `/stores/{store_id}/expand` API in that it only returns relationship tuples that are stored in the system and satisfy the query. In the body: 1. `tuple_key` is optional. If not specified, it will return all tuples in the store. 2. `tuple_key.object` is mandatory if `tuple_key` is specified. It can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 3. `tuple_key.user` is mandatory if tuple_key is specified in the case the `tuple_key.object` is a type only. If tuple_key.user is specified, it needs to be a full object (e.g., `type:user_id`). ## Examples ### Query for all objects in a type definition To query for all objects that `user:bob` has `reader` relationship in the `document` type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and a continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `user:bob` has a `reader` relationship with 1 document `document:2021-budget`. Note that this API, unlike the List Objects API, does not evaluate the tuples in the store. The continuation token will be empty if there are no more tuples to query. ### Query for all stored relationship tuples that have a particular relation and object To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`). Note that, even if the model said that all `writers` are also `readers`, the API will not return writers such as `user:anne` because it only returns tuples and does not evaluate them. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`) and 1 `writer` (`user:anne`). + The Read API will return the tuples for a certain store that match a query filter specified in the body of the request. The API doesn't guarantee order by any field. It is different from the `/stores/{store_id}/expand` API in that it only returns relationship tuples that are stored in the system and satisfy the query. In the body: 1. `tuple_key` is optional. If not specified, it will return all tuples in the store. 2. `tuple_key.object` is mandatory if `tuple_key` is specified. It can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 3. `tuple_key.user` is mandatory if tuple_key is specified in the case the `tuple_key.object` is a type only. ## Examples ### Query for all objects in a type definition To query for all objects that `user:bob` has `reader` relationship in the `document` type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and a continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `user:bob` has a `reader` relationship with 1 document `document:2021-budget`. Note that this API, unlike the List Objects API, does not evaluate the tuples in the store. The continuation token will be empty if there are no more tuples to query. ### Query for all stored relationship tuples that have a particular relation and object To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`). Note that, even if the model said that all `writers` are also `readers`, the API will not return writers such as `user:anne` because it only returns tuples and does not evaluate them. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`) and 1 `writer` (`user:anne`). >>> thread = api.read_with_http_info(body) diff --git a/openfga_sdk/api_client.py b/openfga_sdk/api_client.py index 9305ade..f8d6651 100644 --- a/openfga_sdk/api_client.py +++ b/openfga_sdk/api_client.py @@ -39,7 +39,7 @@ from openfga_sdk.telemetry.attributes import TelemetryAttribute, TelemetryAttributes -DEFAULT_USER_AGENT = "openfga-sdk python/0.9.4" +DEFAULT_USER_AGENT = "openfga-sdk python/0.9.5" def random_time(loop_count, min_wait_in_ms) -> float: diff --git a/openfga_sdk/configuration.py b/openfga_sdk/configuration.py index 01ed94b..2fc81e6 100644 --- a/openfga_sdk/configuration.py +++ b/openfga_sdk/configuration.py @@ -538,7 +538,7 @@ def to_debug_report(self): f"OS: {sys.platform}\n" f"Python Version: {sys.version}\n" "Version of the API: 1.x\n" - "SDK Package Version: 0.9.4" + "SDK Package Version: 0.9.5" ) def get_host_settings(self): diff --git a/openfga_sdk/oauth2.py b/openfga_sdk/oauth2.py index 222b251..5405286 100644 --- a/openfga_sdk/oauth2.py +++ b/openfga_sdk/oauth2.py @@ -83,7 +83,7 @@ async def _obtain_token(self, client): { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "openfga-sdk (python) 0.9.4", + "User-Agent": "openfga-sdk (python) 0.9.5", } ) diff --git a/openfga_sdk/rest.py b/openfga_sdk/rest.py index 01cc9c7..c575070 100644 --- a/openfga_sdk/rest.py +++ b/openfga_sdk/rest.py @@ -278,8 +278,12 @@ async def handle_response_exception( if 200 <= response.status <= 299: return - if isinstance(response, aiohttp.ClientResponse) and not hasattr(response, "data"): + if isinstance(response, aiohttp.ClientResponse) and not hasattr( + response, "data" + ): + # Read the body once and expose it for downstream error handlers response.data = await response.read() + match response.status: case 400: raise ValidationException(http_resp=response) diff --git a/openfga_sdk/sync/api_client.py b/openfga_sdk/sync/api_client.py index 5a5839b..db4a5c7 100644 --- a/openfga_sdk/sync/api_client.py +++ b/openfga_sdk/sync/api_client.py @@ -38,7 +38,7 @@ from openfga_sdk.telemetry.attributes import TelemetryAttribute, TelemetryAttributes -DEFAULT_USER_AGENT = "openfga-sdk python/0.9.4" +DEFAULT_USER_AGENT = "openfga-sdk python/0.9.5" def random_time(loop_count, min_wait_in_ms) -> float: diff --git a/openfga_sdk/sync/oauth2.py b/openfga_sdk/sync/oauth2.py index 62eb788..9e3b8b7 100644 --- a/openfga_sdk/sync/oauth2.py +++ b/openfga_sdk/sync/oauth2.py @@ -83,7 +83,7 @@ def _obtain_token(self, client): { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "openfga-sdk (python) 0.9.4", + "User-Agent": "openfga-sdk (python) 0.9.5", } ) diff --git a/openfga_sdk/sync/open_fga_api.py b/openfga_sdk/sync/open_fga_api.py index f9f28eb..5d2bb3f 100644 --- a/openfga_sdk/sync/open_fga_api.py +++ b/openfga_sdk/sync/open_fga_api.py @@ -1597,7 +1597,7 @@ def list_users_with_http_info(self, body, **kwargs): def read(self, body, **kwargs): """Get tuples from the store that matches a query, without following userset rewrite rules - The Read API will return the tuples for a certain store that match a query filter specified in the body of the request. The API doesn't guarantee order by any field. It is different from the `/stores/{store_id}/expand` API in that it only returns relationship tuples that are stored in the system and satisfy the query. In the body: 1. `tuple_key` is optional. If not specified, it will return all tuples in the store. 2. `tuple_key.object` is mandatory if `tuple_key` is specified. It can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 3. `tuple_key.user` is mandatory if tuple_key is specified in the case the `tuple_key.object` is a type only. If tuple_key.user is specified, it needs to be a full object (e.g., `type:user_id`). ## Examples ### Query for all objects in a type definition To query for all objects that `user:bob` has `reader` relationship in the `document` type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and a continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `user:bob` has a `reader` relationship with 1 document `document:2021-budget`. Note that this API, unlike the List Objects API, does not evaluate the tuples in the store. The continuation token will be empty if there are no more tuples to query. ### Query for all stored relationship tuples that have a particular relation and object To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`). Note that, even if the model said that all `writers` are also `readers`, the API will not return writers such as `user:anne` because it only returns tuples and does not evaluate them. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`) and 1 `writer` (`user:anne`). + The Read API will return the tuples for a certain store that match a query filter specified in the body of the request. The API doesn't guarantee order by any field. It is different from the `/stores/{store_id}/expand` API in that it only returns relationship tuples that are stored in the system and satisfy the query. In the body: 1. `tuple_key` is optional. If not specified, it will return all tuples in the store. 2. `tuple_key.object` is mandatory if `tuple_key` is specified. It can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 3. `tuple_key.user` is mandatory if tuple_key is specified in the case the `tuple_key.object` is a type only. ## Examples ### Query for all objects in a type definition To query for all objects that `user:bob` has `reader` relationship in the `document` type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and a continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `user:bob` has a `reader` relationship with 1 document `document:2021-budget`. Note that this API, unlike the List Objects API, does not evaluate the tuples in the store. The continuation token will be empty if there are no more tuples to query. ### Query for all stored relationship tuples that have a particular relation and object To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`). Note that, even if the model said that all `writers` are also `readers`, the API will not return writers such as `user:anne` because it only returns tuples and does not evaluate them. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`) and 1 `writer` (`user:anne`). >>> thread = api.read(body) @@ -1624,7 +1624,7 @@ def read(self, body, **kwargs): def read_with_http_info(self, body, **kwargs): """Get tuples from the store that matches a query, without following userset rewrite rules - The Read API will return the tuples for a certain store that match a query filter specified in the body of the request. The API doesn't guarantee order by any field. It is different from the `/stores/{store_id}/expand` API in that it only returns relationship tuples that are stored in the system and satisfy the query. In the body: 1. `tuple_key` is optional. If not specified, it will return all tuples in the store. 2. `tuple_key.object` is mandatory if `tuple_key` is specified. It can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 3. `tuple_key.user` is mandatory if tuple_key is specified in the case the `tuple_key.object` is a type only. If tuple_key.user is specified, it needs to be a full object (e.g., `type:user_id`). ## Examples ### Query for all objects in a type definition To query for all objects that `user:bob` has `reader` relationship in the `document` type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and a continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `user:bob` has a `reader` relationship with 1 document `document:2021-budget`. Note that this API, unlike the List Objects API, does not evaluate the tuples in the store. The continuation token will be empty if there are no more tuples to query. ### Query for all stored relationship tuples that have a particular relation and object To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`). Note that, even if the model said that all `writers` are also `readers`, the API will not return writers such as `user:anne` because it only returns tuples and does not evaluate them. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`) and 1 `writer` (`user:anne`). + The Read API will return the tuples for a certain store that match a query filter specified in the body of the request. The API doesn't guarantee order by any field. It is different from the `/stores/{store_id}/expand` API in that it only returns relationship tuples that are stored in the system and satisfy the query. In the body: 1. `tuple_key` is optional. If not specified, it will return all tuples in the store. 2. `tuple_key.object` is mandatory if `tuple_key` is specified. It can be a full object (e.g., `type:object_id`) or type only (e.g., `type:`). 3. `tuple_key.user` is mandatory if tuple_key is specified in the case the `tuple_key.object` is a type only. ## Examples ### Query for all objects in a type definition To query for all objects that `user:bob` has `reader` relationship in the `document` type definition, call read API with body of ```json { \"tuple_key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:\" } } ``` The API will return tuples and a continuation token, something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `user:bob` has a `reader` relationship with 1 document `document:2021-budget`. Note that this API, unlike the List Objects API, does not evaluate the tuples in the store. The continuation token will be empty if there are no more tuples to query. ### Query for all stored relationship tuples that have a particular relation and object To query for all users that have `reader` relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\", \"relation\": \"reader\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`). Note that, even if the model said that all `writers` are also `readers`, the API will not return writers such as `user:anne` because it only returns tuples and does not evaluate them. ### Query for all users with all relationships for a particular document To query for all users that have any relationship with `document:2021-budget`, call read API with body of ```json { \"tuple_key\": { \"object\": \"document:2021-budget\" } } ``` The API will return something like ```json { \"tuples\": [ { \"key\": { \"user\": \"user:anne\", \"relation\": \"writer\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-05T13:42:12.356Z\" }, { \"key\": { \"user\": \"user:bob\", \"relation\": \"reader\", \"object\": \"document:2021-budget\" }, \"timestamp\": \"2021-10-06T15:32:11.128Z\" } ], \"continuation_token\": \"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==\" } ``` This means that `document:2021-budget` has 1 `reader` (`user:bob`) and 1 `writer` (`user:anne`). >>> thread = api.read_with_http_info(body) diff --git a/setup.py b/setup.py index 6805830..b888486 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ NAME = "openfga-sdk" -VERSION = "0.9.4" +VERSION = "0.9.5" REQUIRES = [] diff --git a/test/api/open_fga_api_test.py b/test/api/open_fga_api_test.py index d21604a..f8e5a0c 100644 --- a/test/api/open_fga_api_test.py +++ b/test/api/open_fga_api_test.py @@ -1782,7 +1782,7 @@ async def test_check_api_token(self, mock_request): { "Accept": "application/json", "Content-Type": "application/json", - "User-Agent": "openfga-sdk python/0.9.4", + "User-Agent": "openfga-sdk python/0.9.5", "Authorization": "Bearer TOKEN1", } ) @@ -1836,7 +1836,7 @@ async def test_check_custom_header(self, mock_request): { "Accept": "application/json", "Content-Type": "application/json", - "User-Agent": "openfga-sdk python/0.9.4", + "User-Agent": "openfga-sdk python/0.9.5", "Custom Header": "custom value", } ) diff --git a/test/oauth2_test.py b/test/oauth2_test.py index d263d55..0b5adef 100644 --- a/test/oauth2_test.py +++ b/test/oauth2_test.py @@ -84,7 +84,7 @@ async def test_get_authentication_obtain_client_credentials(self, mock_request): { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "openfga-sdk (python) 0.9.4", + "User-Agent": "openfga-sdk (python) 0.9.5", } ) mock_request.assert_called_once_with( @@ -310,7 +310,7 @@ async def test_get_authentication_keep_full_url(self, mock_request): { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "openfga-sdk (python) 0.9.4", + "User-Agent": "openfga-sdk (python) 0.9.5", } ) mock_request.assert_called_once_with( @@ -365,7 +365,7 @@ async def test_get_authentication_add_scheme(self, mock_request): { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "openfga-sdk (python) 0.9.4", + "User-Agent": "openfga-sdk (python) 0.9.5", } ) mock_request.assert_called_once_with( @@ -420,7 +420,7 @@ async def test_get_authentication_add_path(self, mock_request): { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "openfga-sdk (python) 0.9.4", + "User-Agent": "openfga-sdk (python) 0.9.5", } ) mock_request.assert_called_once_with( @@ -475,7 +475,7 @@ async def test_get_authentication_add_scheme_and_path(self, mock_request): { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "openfga-sdk (python) 0.9.4", + "User-Agent": "openfga-sdk (python) 0.9.5", } ) mock_request.assert_called_once_with( diff --git a/test/rest_test.py b/test/rest_test.py index 9cfcf24..343e09d 100644 --- a/test/rest_test.py +++ b/test/rest_test.py @@ -14,6 +14,7 @@ from unittest.mock import AsyncMock, MagicMock +import aiohttp import pytest from openfga_sdk.exceptions import ( @@ -183,6 +184,31 @@ async def test_handle_response_exception_error(status, exc): await client.handle_response_exception(mock_response) +@pytest.mark.asyncio +async def test_handle_response_exception_reads_data(): + mock_config = MagicMock() + mock_config.ssl_ca_cert = None + mock_config.cert_file = None + mock_config.key_file = None + mock_config.verify_ssl = True + mock_config.connection_pool_maxsize = 4 + mock_config.proxy = None + mock_config.proxy_headers = None + mock_config.timeout_millisec = 5000 + + client = RESTClientObject(configuration=mock_config) + + mock_response = MagicMock(spec=aiohttp.ClientResponse) + mock_response.status = 400 + mock_response.read = AsyncMock(return_value=b'{"error":"bad"}') + + with pytest.raises(ValidationException): + await client.handle_response_exception(mock_response) + + mock_response.read.assert_awaited_once() + assert mock_response.data == b'{"error":"bad"}' + + @pytest.mark.asyncio async def test_close(): mock_config = MagicMock() diff --git a/test/sync/oauth2_test.py b/test/sync/oauth2_test.py index 78e22e8..0a872e1 100644 --- a/test/sync/oauth2_test.py +++ b/test/sync/oauth2_test.py @@ -84,7 +84,7 @@ def test_get_authentication_obtain_client_credentials(self, mock_request): { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded", - "User-Agent": "openfga-sdk (python) 0.9.4", + "User-Agent": "openfga-sdk (python) 0.9.5", } ) mock_request.assert_called_once_with( diff --git a/test/sync/open_fga_api_test.py b/test/sync/open_fga_api_test.py index ce527a0..000cbf8 100644 --- a/test/sync/open_fga_api_test.py +++ b/test/sync/open_fga_api_test.py @@ -1841,7 +1841,7 @@ def test_check_api_token(self, mock_request): { "Accept": "application/json", "Content-Type": "application/json", - "User-Agent": "openfga-sdk python/0.9.4", + "User-Agent": "openfga-sdk python/0.9.5", "Authorization": "Bearer TOKEN1", } ) @@ -1895,7 +1895,7 @@ def test_check_custom_header(self, mock_request): { "Accept": "application/json", "Content-Type": "application/json", - "User-Agent": "openfga-sdk python/0.9.4", + "User-Agent": "openfga-sdk python/0.9.5", "Custom Header": "custom value", } )