diff --git a/permit/_sync_types.pyi b/permit/_sync_types.pyi index c5ccbb01..c7e0ee4c 100644 --- a/permit/_sync_types.pyi +++ b/permit/_sync_types.pyi @@ -132,7 +132,7 @@ class SyncConditionSetRulesApi(BasePermitApi): Args: user_set_key: the key of the userset, if used only rules matching that userset will be fetched. - permission_key: the key of the permission, formatted as :. + permission_key: the key of the permission, formatted as `:`. if used, only rules granting that permission will be fetched. resource_set_key: the key of the resourceset, if used only rules matching that resourceset will be fetched. @@ -546,7 +546,7 @@ class SyncGroupsApi(BasePermitApi): Returns: One page of groups, with the total count. Each group's ``group_instance_key`` is - its instance key alone, and ``id`` is its instance id. + its instance key alone, and ``id`` is its instance id. Raises: PermitApiError: If the API returns an error HTTP status code. @@ -566,7 +566,7 @@ class SyncGroupsApi(BasePermitApi): Returns: The group. Its ``group_instance_key`` is its instance key alone, and ``id`` is - its instance id. + its instance id. Raises: PermitApiError: If the API returns an error HTTP status code, such as 404 when no @@ -813,7 +813,7 @@ class SyncPdpsApi(BasePermitApi): Returns: The id of the data update that carries the refresh, and the ids of the PDP - configurations it was sent to. + configurations it was sent to. Raises: pydantic.v1.ValidationError: If ``reason`` is longer than 512 characters. Nothing @@ -1689,9 +1689,9 @@ class SyncResourceInstancesApi(BasePermitApi): this method raises as a ``PermitApiError`` that says so. Args: - resource_instances: The resource instance identities to delete. - Each identity can be either `resource_type:instance_key` (like Repository:react) or the - resource instance uuid. + resource_instances: The resource instance identities to delete. Each identity can + be either `resource_type:instance_key` (like Repository:react) or the resource + instance uuid. Returns: the bulk delete report. @@ -1716,7 +1716,7 @@ class SyncResourceRelationsApi(BasePermitApi): Returns: a PaginatedResultRelationRead holding the relations in ``.data`` and the - total number of relations on the resource in ``.total_count``. + total number of relations on the resource in ``.total_count``. Raises: PermitApiError: If the API returns an error HTTP status code. @@ -2416,8 +2416,8 @@ class SyncRolesApi(BasePermitApi): Args: role_key: The key of the role. - permissions: An array of permission keys () to be assigned to the - role. + permissions: An array of permission keys (``) to be assigned + to the role. Returns: A RoleRead object representing the updated role. @@ -2432,8 +2432,8 @@ class SyncRolesApi(BasePermitApi): Args: role_key: The key of the role. - permissions: An array of permission keys () to be removed from - the role. + permissions: An array of permission keys (``) to be removed + from the role. Returns: A RoleRead object representing the updated role. @@ -3079,7 +3079,7 @@ class SyncEnforcer: Defaults to None. Returns: - AuthorizedUsersResult: Contains all the authorized users and the role assignments that + Contains all the authorized users and the role assignments that granted the permission. Raises: @@ -3087,15 +3087,17 @@ class SyncEnforcer: PDP. Examples: + ```python # all the users that can close any issue? - await permit.authorized_users('close', 'issue') + await permit.authorized_users("close", "issue") # all the users that can close an issue who's id is 1234? - await permit.authorized_users('close', 'issue:1234') + await permit.authorized_users("close", "issue:1234") # all the users that can close (any) issues belonging to the 't1' tenant? # (in a multi tenant application) - await permit.authorized_users('close', {'type': 'issue', 'tenant': 't1'}) + await permit.authorized_users("close", {"type": "issue", "tenant": "t1"}) + ``` """ def bulk_check(self, checks: list[CheckQuery], context: Context | None = None) -> list[bool]: """Checks if a user is authorized to perform an action on a resource in a context. @@ -3109,7 +3111,7 @@ class SyncEnforcer: Defaults to None. Returns: - list[bool]: A list of booleans indicating whether the user is authorized for each + A list of booleans indicating whether the user is authorized for each resource. Raises: @@ -3117,24 +3119,28 @@ class SyncEnforcer: PDP. Examples: + ```python # Bulk query of multiple check conventions - await permit.bulk_check([ - { - "user": user, - "action": "close", - "resource": {type: "issue", key: "1234"}, - }, - { - "user": {key: "user"}, - "action": "close", - "resource": "issue:1235", - }, - { - "user": "user_a", - "action": "close", - "resource": "issue", - }, - ]) + await permit.bulk_check( + [ + { + "user": user, + "action": "close", + "resource": {"type": "issue", "key": "1234"}, + }, + { + "user": {"key": "user"}, + "action": "close", + "resource": "issue:1235", + }, + { + "user": "user_a", + "action": "close", + "resource": "issue", + }, + ] + ) + ``` """ def check( self, user: User, action: Action, resource: Resource, context: Context | None = None @@ -3149,22 +3155,24 @@ class SyncEnforcer: Defaults to None. Returns: - bool: True if the user is authorized, False otherwise. + True if the user is authorized, False otherwise. Raises: PermitConnectionError: If an error occurs while sending the authorization request to the PDP. Examples: + ```python # can the user close any issue? - await permit.check(user, 'close', 'issue') + await permit.check(user, "close", "issue") # can the user close any issue who's id is 1234? - await permit.check(user, 'close', 'issue:1234') + await permit.check(user, "close", "issue:1234") # can the user close (any) issues belonging to the 't1' tenant? # (in a multi tenant application) - await permit.check(user, 'close', {'type': 'issue', 'tenant': 't1'}) + await permit.check(user, "close", {"type": "issue", "tenant": "t1"}) + ``` """ def get_user_permissions( self, @@ -3212,7 +3220,7 @@ class SyncEnforcer: Returns: The user's tenants, each with its key and attributes. Empty when the user has no - tenant-level role or the PDP does not know the user. + tenant-level role or the PDP does not know the user. Raises: PermitConnectionError: If the PDP answers 404 (as the cloud PDP does), answers any @@ -3231,7 +3239,7 @@ class SyncEnforcer: key, which is sent as the resource context of that check. Returns: - list[dict]: The subset of ``resources`` the user is authorized for, in input order. + The subset of ``resources`` the user is authorized for, in input order. """ class SyncPdpRoleAssignmentsApi(BasePdpPermitApi): diff --git a/permit/api/condition_set_rules.py b/permit/api/condition_set_rules.py index f0d42320..a9330732 100644 --- a/permit/api/condition_set_rules.py +++ b/permit/api/condition_set_rules.py @@ -41,7 +41,7 @@ async def list( Args: user_set_key: the key of the userset, if used only rules matching that userset will be fetched. - permission_key: the key of the permission, formatted as :. + permission_key: the key of the permission, formatted as `:`. if used, only rules granting that permission will be fetched. resource_set_key: the key of the resourceset, if used only rules matching that resourceset will be fetched. diff --git a/permit/api/context.py b/permit/api/context.py index 72d3b5df..aeefc2a7 100644 --- a/permit/api/context.py +++ b/permit/api/context.py @@ -69,6 +69,7 @@ class ApiContext: the full object hierarchy in every request. For example, in order to list roles, the user need to specify the (id or key) of the: + - the org - the project - then environment @@ -78,7 +79,8 @@ class ApiContext: from that context. We then get this kind of experience: - ``` + + ```python await permit.api.roles.list() ``` diff --git a/permit/api/encoders.py b/permit/api/encoders.py index 8ef1fa55..d8020190 100644 --- a/permit/api/encoders.py +++ b/permit/api/encoders.py @@ -75,15 +75,19 @@ def decimal_encoder(dec_value: Decimal) -> int | float: results in failed round-tripping between encode and parse. Our Id type is a prime example of this. - >>> decimal_encoder(Decimal("1.0")) - 1.0 - - >>> decimal_encoder(Decimal("1")) - 1 - Raises: TypeError: If ``dec_value`` is NaN or infinite. JSON has no such values, so encoding one would send the API an invalid request body. + + Examples: + ```pycon + >>> decimal_encoder(Decimal("1.0")) + 1.0 + + >>> decimal_encoder(Decimal("1")) + 1 + + ``` """ exponent = dec_value.as_tuple().exponent if not isinstance(exponent, int): diff --git a/permit/api/groups.py b/permit/api/groups.py index 7ab0ca84..e03a3c81 100644 --- a/permit/api/groups.py +++ b/permit/api/groups.py @@ -75,7 +75,7 @@ async def list(self, page: int = 1, per_page: int = 100) -> PaginatedResultGroup Returns: One page of groups, with the total count. Each group's ``group_instance_key`` is - its instance key alone, and ``id`` is its instance id. + its instance key alone, and ``id`` is its instance id. Raises: PermitApiError: If the API returns an error HTTP status code. @@ -104,7 +104,7 @@ async def get(self, group_instance_key: str) -> GroupReadSchema: Returns: The group. Its ``group_instance_key`` is its instance key alone, and ``id`` is - its instance id. + its instance id. Raises: PermitApiError: If the API returns an error HTTP status code, such as 404 when no diff --git a/permit/api/pdps.py b/permit/api/pdps.py index 2699e928..06687ce0 100644 --- a/permit/api/pdps.py +++ b/permit/api/pdps.py @@ -47,7 +47,7 @@ async def refresh(self, reason: str | None = None) -> PDPDataRefreshResponse: Returns: The id of the data update that carries the refresh, and the ids of the PDP - configurations it was sent to. + configurations it was sent to. Raises: pydantic.v1.ValidationError: If ``reason`` is longer than 512 characters. Nothing diff --git a/permit/api/resource_instances.py b/permit/api/resource_instances.py index 82007494..4207fb41 100644 --- a/permit/api/resource_instances.py +++ b/permit/api/resource_instances.py @@ -392,9 +392,9 @@ async def bulk_delete( this method raises as a ``PermitApiError`` that says so. Args: - resource_instances: The resource instance identities to delete. - Each identity can be either `resource_type:instance_key` (like Repository:react) or the - resource instance uuid. + resource_instances: The resource instance identities to delete. Each identity can + be either `resource_type:instance_key` (like Repository:react) or the resource + instance uuid. Returns: the bulk delete report. diff --git a/permit/api/resource_relations.py b/permit/api/resource_relations.py index b8bece2b..a7df9537 100644 --- a/permit/api/resource_relations.py +++ b/permit/api/resource_relations.py @@ -38,7 +38,7 @@ async def list( Returns: a PaginatedResultRelationRead holding the relations in ``.data`` and the - total number of relations on the resource in ``.total_count``. + total number of relations on the resource in ``.total_count``. Raises: PermitApiError: If the API returns an error HTTP status code. diff --git a/permit/api/roles.py b/permit/api/roles.py index fb2900ee..6948835d 100644 --- a/permit/api/roles.py +++ b/permit/api/roles.py @@ -180,8 +180,8 @@ async def assign_permissions(self, role_key: str, permissions: builtins.list[str Args: role_key: The key of the role. - permissions: An array of permission keys () to be assigned to the - role. + permissions: An array of permission keys (``) to be assigned + to the role. Returns: A RoleRead object representing the updated role. @@ -205,8 +205,8 @@ async def remove_permissions(self, role_key: str, permissions: builtins.list[str Args: role_key: The key of the role. - permissions: An array of permission keys () to be removed from - the role. + permissions: An array of permission keys (``) to be removed + from the role. Returns: A RoleRead object representing the updated role. diff --git a/permit/enforcement/enforcer.py b/permit/enforcement/enforcer.py index 072a13da..b66d9efc 100644 --- a/permit/enforcement/enforcer.py +++ b/permit/enforcement/enforcer.py @@ -144,7 +144,7 @@ async def authorized_users( Defaults to None. Returns: - AuthorizedUsersResult: Contains all the authorized users and the role assignments that + Contains all the authorized users and the role assignments that granted the permission. Raises: @@ -152,15 +152,17 @@ async def authorized_users( PDP. Examples: + ```python # all the users that can close any issue? - await permit.authorized_users('close', 'issue') + await permit.authorized_users("close", "issue") # all the users that can close an issue who's id is 1234? - await permit.authorized_users('close', 'issue:1234') + await permit.authorized_users("close", "issue:1234") # all the users that can close (any) issues belonging to the 't1' tenant? # (in a multi tenant application) - await permit.authorized_users('close', {'type': 'issue', 'tenant': 't1'}) + await permit.authorized_users("close", {"type": "issue", "tenant": "t1"}) + ``` """ context = context or {} @@ -260,7 +262,7 @@ async def bulk_check( Defaults to None. Returns: - list[bool]: A list of booleans indicating whether the user is authorized for each + A list of booleans indicating whether the user is authorized for each resource. Raises: @@ -268,24 +270,28 @@ async def bulk_check( PDP. Examples: + ```python # Bulk query of multiple check conventions - await permit.bulk_check([ - { - "user": user, - "action": "close", - "resource": {type: "issue", key: "1234"}, - }, - { - "user": {key: "user"}, - "action": "close", - "resource": "issue:1235", - }, - { - "user": "user_a", - "action": "close", - "resource": "issue", - }, - ]) + await permit.bulk_check( + [ + { + "user": user, + "action": "close", + "resource": {"type": "issue", "key": "1234"}, + }, + { + "user": {"key": "user"}, + "action": "close", + "resource": "issue:1235", + }, + { + "user": "user_a", + "action": "close", + "resource": "issue", + }, + ] + ) + ``` """ context = context or {} request_body = [] @@ -384,22 +390,24 @@ async def check( Defaults to None. Returns: - bool: True if the user is authorized, False otherwise. + True if the user is authorized, False otherwise. Raises: PermitConnectionError: If an error occurs while sending the authorization request to the PDP. Examples: + ```python # can the user close any issue? - await permit.check(user, 'close', 'issue') + await permit.check(user, "close", "issue") # can the user close any issue who's id is 1234? - await permit.check(user, 'close', 'issue:1234') + await permit.check(user, "close", "issue:1234") # can the user close (any) issues belonging to the 't1' tenant? # (in a multi tenant application) - await permit.check(user, 'close', {'type': 'issue', 'tenant': 't1'}) + await permit.check(user, "close", {"type": "issue", "tenant": "t1"}) + ``` """ context = context or {} @@ -592,7 +600,7 @@ async def get_user_tenants( Returns: The user's tenants, each with its key and attributes. Empty when the user has no - tenant-level role or the PDP does not know the user. + tenant-level role or the PDP does not know the user. Raises: PermitConnectionError: If the PDP answers 404 (as the cloud PDP does), answers any @@ -658,7 +666,7 @@ async def filter_objects( key, which is sent as the resource context of that check. Returns: - list[dict]: The subset of ``resources`` the user is authorized for, in input order. + The subset of ``resources`` the user is authorized for, in input order. """ requests: list[CheckQuery] = [] for resource in resources: diff --git a/permit/permit.py b/permit/permit.py index 4683859c..8462c9a5 100644 --- a/permit/permit.py +++ b/permit/permit.py @@ -32,10 +32,12 @@ class Permit: The client keeps its HTTP connections open and reuses them: one aiohttp session, with its own pool of connections, for the Permit API and one for the PDP, per event loop it is used on. They are created by the first request from each loop. Close them with - ``await permit.close()``, or use the client as an async context manager:: + ``await permit.close()``, or use the client as an async context manager: - async with Permit(token="") as permit: - await permit.check("user", "read", "document") + ```python + async with Permit(token="") as permit: + await permit.check("user", "read", "document") + ``` A client that is never closed leaves nothing open behind it under ``asyncio.run()``, which closes the loop's sessions as it shuts the loop down, nor once it is garbage @@ -131,10 +133,11 @@ def config(self) -> PermitConfig: Once the SDK is initialized, the configuration is read-only. - Usage example: - + Examples: + ```python permit = Permit(config) pdp_url = permit.config.pdp + ``` """ return self._config.copy() @@ -173,11 +176,11 @@ def wait_for_sync( default when that is None too. Yields: - Permit: A Permit instance that is configured to wait for facts to be synced. It - sends its requests over this client's connections, so it needs no ``close()``: - closing this client closes them, and its own ``close()`` does nothing. With - ``proxy_facts_via_pdp`` off, it logs a warning and yields this client itself, - whose ``close()`` closes them. + A Permit instance that is configured to wait for facts to be synced. It + sends its requests over this client's connections, so it needs no ``close()``: + closing this client closes them, and its own ``close()`` does nothing. With + ``proxy_facts_via_pdp`` off, it logs a warning and yields this client itself, + whose ``close()`` closes them. See Also: https://docs.permit.io/how-to/manage-data/local-facts-uploader @@ -205,10 +208,11 @@ def wait_for_sync( def api(self) -> PermitApiClient: """Access the Permit REST API using this property. - Usage example: - + Examples: + ```python permit = Permit(token="") await permit.api.roles.create(...) + ``` """ return self._api @@ -216,10 +220,11 @@ def api(self) -> PermitApiClient: def elements(self) -> ElementsApi: """Access the Permit Elements API using this property. - Usage example: - + Examples: + ```python permit = Permit(token="") - await permit.elements.loginAs(user, tenant) + await permit.elements.login_as(user, tenant) + ``` """ return self._elements @@ -229,10 +234,11 @@ def pdp_api(self) -> PermitPdpApiClient: Container PDP only: the cloud PDP serves none of its routes. - Usage example: - + Examples: + ```python permit = Permit(token="") await permit.pdp_api.role_assignments.list() + ``` """ return self._pdp_api @@ -251,7 +257,7 @@ async def authorized_users( Defaults to None. Returns: - AuthorizedUsersResult: Contains all the authorized users and the role assignments that + Contains all the authorized users and the role assignments that granted the permission. Raises: @@ -259,15 +265,17 @@ async def authorized_users( PDP. Examples: + ```python # all the users that can close any issue? - await permit.authorized_users('close', 'issue') + await permit.authorized_users("close", "issue") # all the users that can close an issue who's id is 1234? - await permit.authorized_users('close', 'issue:1234') + await permit.authorized_users("close", "issue:1234") # all the users that can close (any) issues belonging to the 't1' tenant? # (in a multi tenant application) - await permit.authorized_users('close', {'type': 'issue', 'tenant': 't1'}) + await permit.authorized_users("close", {"type": "issue", "tenant": "t1"}) + ``` """ return await self._enforcer.authorized_users(action, resource, context) @@ -284,7 +292,7 @@ async def bulk_check( Defaults to None. Returns: - list[bool]: A list of booleans indicating whether the user is authorized for each + A list of booleans indicating whether the user is authorized for each resource. Raises: @@ -292,24 +300,28 @@ async def bulk_check( PDP. Examples: + ```python # Bulk query of multiple check conventions - await permit.bulk_check([ - { - "user": user, - "action": "close", - "resource": {type: "issue", key: "1234"}, - }, - { - "user": {key: "user"}, - "action": "close", - "resource": "issue:1235", - }, - { - "user": "user_a", - "action": "close", - "resource": "issue", - }, - ]) + await permit.bulk_check( + [ + { + "user": user, + "action": "close", + "resource": {"type": "issue", "key": "1234"}, + }, + { + "user": {"key": "user"}, + "action": "close", + "resource": "issue:1235", + }, + { + "user": "user_a", + "action": "close", + "resource": "issue", + }, + ] + ) + ``` """ return await self._enforcer.bulk_check(checks, context) @@ -330,22 +342,24 @@ async def check( Defaults to None. Returns: - bool: True if the user is authorized, False otherwise. + True if the user is authorized, False otherwise. Raises: PermitConnectionError: If an error occurs while sending the authorization request to the PDP. Examples: + ```python # can the user close any issue? - await permit.check(user, 'close', 'issue') + await permit.check(user, "close", "issue") # can the user close any issue who's id is 1234? - await permit.check(user, 'close', 'issue:1234') + await permit.check(user, "close", "issue:1234") # can the user close (any) issues belonging to the 't1' tenant? # (in a multi tenant application) - await permit.check(user, 'close', {'type': 'issue', 'tenant': 't1'}) + await permit.check(user, "close", {"type": "issue", "tenant": "t1"}) + ``` """ return await self._enforcer.check(user, action, resource, context) @@ -370,7 +384,7 @@ async def get_user_permissions( either; pass ``{}`` to send the base context alone. Returns: - dict: User permissions per tenant + User permissions per tenant Raises: PermitConnectionError: If an error occurs while sending the request to the PDP @@ -400,7 +414,7 @@ async def get_user_tenants( Defaults to None. Returns: - list[TenantDetails]: The user's tenants, each with its key and attributes. Empty + The user's tenants, each with its key and attributes. Empty when the user has no tenant-level role or the PDP does not know the user. Raises: @@ -408,9 +422,11 @@ async def get_user_tenants( other error status, or cannot be reached. Examples: + ```python # the tenants in which alice has a role tenants = await permit.get_user_tenants("alice") keys = [tenant.key for tenant in tenants] + ``` """ return await self._enforcer.get_user_tenants(user, context) @@ -427,7 +443,7 @@ async def filter_objects( `type`, `key`, `context`, `attributes` and `tenant`. Returns: - list[dict[str, Any]]: The permitted subset of `resources`, in their original order + The permitted subset of `resources`, in their original order Raises: PermitConnectionError: If an error occurs while sending the request to the PDP diff --git a/permit/sync.py b/permit/sync.py index 2f9320b1..e453d89c 100644 --- a/permit/sync.py +++ b/permit/sync.py @@ -48,8 +48,10 @@ class Permit(AsyncPermit): address, as for the async client, ``permit.Permit``. Examples: + ```python with Permit(token="") as permit: permit.check("user", "read", "document") + ``` """ def __init__(self, config: PermitConfig | None = None, **options: Any) -> None: @@ -91,11 +93,13 @@ def close(self) -> None: # type: ignore[override] stop and join. Examples: + ```python permit = Permit(token="") try: permit.check("user", "read", "document") finally: permit.close() + ``` """ if not self._owns_sessions: return @@ -134,10 +138,11 @@ def __aenter__(self) -> None: # type: ignore[override] def api(self) -> SyncPermitApiClient: # type: ignore[override] """Access the Permit REST API using this property. - Usage example: - + Examples: + ```python permit = Permit(token="") permit.api.roles.create(...) + ``` """ return self._api # type: ignore[return-value] @@ -145,10 +150,11 @@ def api(self) -> SyncPermitApiClient: # type: ignore[override] def elements(self) -> SyncElementsApi: # type: ignore[override] """Access the Permit Elements API using this property. - Usage example: - + Examples: + ```python permit = Permit(token="") - permit.elements.loginAs(user, tenant) + permit.elements.login_as(user, tenant) + ``` """ return self._elements # type: ignore[return-value] @@ -158,9 +164,11 @@ def pdp_api(self) -> SyncPDPApi: Container PDP only: the cloud PDP serves none of its routes. - Usage example: - permit = Permit(token="") - permit.pdp_api.role_assignments(...) + Examples: + ```python + permit = Permit(token="") + permit.pdp_api.role_assignments.list() + ``` """ return self._pdp_api # type: ignore[return-value] @@ -178,7 +186,7 @@ def bulk_check( # type: ignore[override] Defaults to None. Returns: - list[bool]: A list of booleans indicating whether the user is authorized for each + A list of booleans indicating whether the user is authorized for each resource. Raises: @@ -186,24 +194,28 @@ def bulk_check( # type: ignore[override] PDP. Examples: + ```python # Bulk query of multiple check conventions - await permit.bulk_check([ - { - "user": user, - "action": "close", - "resource": {type: "issue", key: "1234"}, - }, - { - "user": {key: "user"}, - "action": "close", - "resource": "issue:1235", - }, - { - "user": "user_a", - "action": "close", - "resource": "issue", - }, - ]) + permit.bulk_check( + [ + { + "user": user, + "action": "close", + "resource": {"type": "issue", "key": "1234"}, + }, + { + "user": {"key": "user"}, + "action": "close", + "resource": "issue:1235", + }, + { + "user": "user_a", + "action": "close", + "resource": "issue", + }, + ] + ) + ``` """ return self._enforcer.bulk_check(checks, context) # type: ignore[return-value] @@ -224,22 +236,24 @@ def check( # type: ignore[override] Defaults to None. Returns: - bool: True if the user is authorized, False otherwise. + True if the user is authorized, False otherwise. Raises: PermitConnectionError: If an error occurs while sending the authorization request to the PDP. Examples: + ```python # can the user close any issue? - permit.check(user, 'close', 'issue') + permit.check(user, "close", "issue") # can the user close any issue who's id is 1234? - permit.check(user, 'close', 'issue:1234') + permit.check(user, "close", "issue:1234") # can the user close (any) issues belonging to the 't1' tenant? # (in a multi tenant application) - permit.check(user, 'close', {'type': 'issue', 'tenant': 't1'}) + permit.check(user, "close", {"type": "issue", "tenant": "t1"}) + ``` """ return self._enforcer.check(user, action, resource, context) # type: ignore[return-value] @@ -258,7 +272,7 @@ def authorized_users( # type: ignore[override] Defaults to None. Returns: - AuthorizedUsersResult: Contains all the authorized users and the role assignments that + Contains all the authorized users and the role assignments that granted the permission. Raises: @@ -266,15 +280,17 @@ def authorized_users( # type: ignore[override] PDP. Examples: + ```python # all the users that can close any issue? - permit.authorized_users('close', 'issue') + permit.authorized_users("close", "issue") # all the users that can close an issue who's id is 1234? - permit.authorized_users('close', 'issue:1234') + permit.authorized_users("close", "issue:1234") # all the users that can close (any) issues belonging to the 't1' tenant? # (in a multi tenant application) - permit.authorized_users('close', {'type': 'issue', 'tenant': 't1'}) + permit.authorized_users("close", {"type": "issue", "tenant": "t1"}) + ``` """ return self._enforcer.authorized_users(action, resource, context) # type: ignore[return-value] @@ -299,7 +315,7 @@ def get_user_permissions( # type: ignore[override] either; pass ``{}`` to send the base context alone. Returns: - dict: User permissions per tenant + User permissions per tenant Raises: PermitConnectionError: If an error occurs while sending the request to the PDP @@ -329,7 +345,7 @@ def get_user_tenants( # type: ignore[override] Defaults to None. Returns: - list[TenantDetails]: The user's tenants, each with its key and attributes. Empty + The user's tenants, each with its key and attributes. Empty when the user has no tenant-level role or the PDP does not know the user. Raises: @@ -337,9 +353,11 @@ def get_user_tenants( # type: ignore[override] other error status, or cannot be reached. Examples: + ```python # the tenants in which alice has a role tenants = permit.get_user_tenants("alice") keys = [tenant.key for tenant in tenants] + ``` """ return self._enforcer.get_user_tenants(user, context) # type: ignore[return-value] @@ -356,7 +374,7 @@ def filter_objects( # type: ignore[override] `type`, `key`, `context`, `attributes` and `tenant`. Returns: - list[dict[str, Any]]: The permitted subset of `resources`, in their original order + The permitted subset of `resources`, in their original order Raises: PermitConnectionError: If an error occurs while sending the request to the PDP diff --git a/permit/utils/sync.py b/permit/utils/sync.py index 2aaf7974..967ad229 100644 --- a/permit/utils/sync.py +++ b/permit/utils/sync.py @@ -33,10 +33,10 @@ """A coroutine function that closes the HTTP sessions of a sync client.""" SYNC_WRAPPER_MARKER = "__permit_sync_wrapper__" -"""Attribute set on every wrapper produced by :func:`async_to_sync`. +"""Attribute set on every wrapper produced by `async_to_sync`. It marks a callable as "already converted", which makes the conversion done by -:class:`SyncClass` idempotent and keeps :func:`iscoroutine_func` from walking +`SyncClass` idempotent and keeps `iscoroutine_func` from walking into the coroutine function such a wrapper consumes. """ @@ -233,7 +233,7 @@ async def _track(self, coroutine: Coroutine[Any, Any, T], call_site: _CallSite) Returns: What the coroutine returns, or the exception it raises, as a `_Raised`. A - cancellation, of the task or from the coroutine, is raised. + cancellation, of the task or from the coroutine, is raised. """ # Never None: this coroutine only ever runs as a task. task = cast("asyncio.Task[Any]", asyncio.current_task()) @@ -261,7 +261,7 @@ def submit( Returns: The future of the coroutine's result, or of the exception it raised, as a - `_Raised`. + `_Raised`. Raises: RuntimeError: If the loop is closed. `coroutine` is closed, never started. @@ -550,11 +550,11 @@ def async_to_sync(func: Callable[P, Coroutine[Any, Any, T]]) -> Callable[P, T]: Returns: A callable that runs `func` to completion and returns its result: on the background - loop of the sync client that the first argument (`self`, for a method) belongs to, - otherwise in an event loop of its own. When it is called from inside a coroutine - that a blocking call is already driving, the coroutine is handed back untouched - instead, so that internal `await self.public_method(...)` calls keep working on a - converted class. + loop of the sync client that the first argument (`self`, for a method) belongs to, + otherwise in an event loop of its own. When it is called from inside a coroutine + that a blocking call is already driving, the coroutine is handed back untouched + instead, so that internal `await self.public_method(...)` calls keep working on a + converted class. """ @wraps(func)