Storages#
The contract between the server and the data of an application, and the storages that keep the resources in memory.
- class scim2_server.storage.ScimStorage[source]#
Where a SCIM server reads and writes its resources.
Subclass it to connect the server to a data source, such as a SQL database or a directory. The server handles the SCIM protocol, and calls these methods to read, search, create, update and delete resources. Every method receives the
ResourceTypeit applies to, so a single storage can serve several resource types.A storage follows these rules, which
ScimStorageContractchecks:Every resource it returns is a copy. Changing it does not change the stored resource, and the resources it receives are not changed either.
It fills
id,meta.resourceType,meta.created,meta.lastModifiedandmeta.version. It leavesmeta.locationto the server, which knows the URLs. For the same reason, a reference to another resource, such asmembers.$ref, can be relative to the SCIM root, such asUsers/2819c223. The server returns its URL.The version changes whenever the resource changes. An update that changes nothing may keep it.
A resource that does not exist raises
NotFoundException.A value already taken by an attribute whose uniqueness is
serverorglobalraisesUniquenessException.It supports what the
ServiceProviderConfigof the server announces, such as sorting. The server refuses the rest before calling the storage.
- supports_cursors: bool = False#
Whether
search()pages the resources with cursors that give stable pages.Set it to
Trueoncesearch()follows the rules of the cursors. The server refuses to start when its configuration announces cursor pagination and the storage does not support it.
- abstractmethod get(resource_type: ResourceType, resource_id: str, *, response_parameters: ResponseParameters[Any] | None = None) Resource[source]#
Return a resource.
The server passes
response_parameterswhen it returns the resource to the client, for a GET request. The storage may then leave out the attributes the response does not keep, for instance to avoid loading the members of a group. It must return every attribute the response keeps.Path.iter_pathsgives them. The server applies the parameters to the response anyway. Withoutresponse_parameters, the storage returns the whole resource.A
getmethod withoutresponse_parametersis deprecated, and raises aDeprecationWarning. The server then does not pass the parameters. scim2-server 0.9 will require it.- Raises:
NotFoundException – When no resource of this type has this identifier.
- abstractmethod search(resource_types: list[ResourceType], search_request: SearchRequest[Any], *, position: Any = None) SearchPage[source]#
Return one page of the matching resources, and their number.
The search request is already validated, and its
countis already bounded by themaxResultsof the server. The storage filters, sorts and pages the resources of every given resource type as a single collection. Several resource types mean a search at the server root.An attribute that a resource type does not declare matches none of its resources (RFC 7644 §3.4.2.1).
A
start_indexpages the resources by index. Acursorthat is notNonepages them with a cursor (RFC 9865), when the storagesupports_cursors. The storage then returns thenextandpreviouspositions of the page, as values that JSON can hold. The server hides them in the cursors it gives the client, and passes them back asposition.positionisNoneon the first page.The cursors give stable pages. A position holds the sort value and the identifier of the last resource of the page, or of the first one for the previous page. A resource that exists during the whole paging, and whose sort value does not change, is returned exactly once. A resource created or deleted meanwhile is returned or not, depending on where it sorts.
A
searchmethod withoutpositionis deprecated, and raises aDeprecationWarning. It returns the number of matching resources and the page, and pages by index only. scim2-server 0.9 will requireposition.- Raises:
InvalidFilterException – When the storage cannot evaluate the filter. Filtering the page afterwards would make
totalResultsand the paging wrong.InvalidCursorException – When the storage cannot read
position.NotImplementedException – When the storage does not support searching several resource types at once.
- abstractmethod create(resource_type: ResourceType, resource: Resource) Resource[source]#
Store a new resource, and return the stored resource.
- Raises:
UniquenessException – When a unique value is taken.
- abstractmethod update(resource_type: ResourceType, resource: Resource, *, expected_version: str | None = None) Resource[source]#
Replace the stored resource that has the identifier of
resource, and return the stored resource.The server calls it for PUT and PATCH requests. It applies the request to the stored resource first, so
resourceis the whole new state of the resource.- Parameters:
expected_version – The version the stored resource must still have, when given.
- Raises:
NotFoundException – When the resource does not exist.
PreconditionFailedException – When the stored version is not
expected_version.UniquenessException – When a unique value is taken.
- abstractmethod delete(resource_type: ResourceType, resource_id: str, *, expected_version: str | None = None) None[source]#
Delete a resource.
- Parameters:
expected_version – The version the stored resource must still have, when given.
- Raises:
NotFoundException – When the resource does not exist.
PreconditionFailedException – When the stored version is not
expected_version.
- operation() AbstractContextManager[None][source]#
Enclose one SCIM operation: a single request, or one operation of a bulk request.
It does nothing by default. A SQL storage can open a savepoint here, so that a failed operation does not prevent the next ones of a bulk request (RFC 7644 §3.7). Committing the request is left to the application.
- class scim2_server.storage.AsyncScimStorage[source]#
The asynchronous variant of
ScimStorage.Its methods are coroutines, and follow the rules of
ScimStorage, whichAsyncScimStorageContractchecks.- supports_cursors: bool = False#
Whether
search()pages the resources with cursors that give stable pages. SeeScimStorage.supports_cursors.
- abstractmethod async get(resource_type: ResourceType, resource_id: str, *, response_parameters: ResponseParameters[Any] | None = None) Resource[source]#
Return a resource. See
ScimStorage.get().
- abstractmethod async search(resource_types: list[ResourceType], search_request: SearchRequest[Any], *, position: Any = None) SearchPage[source]#
Return one page of the matching resources, and their number. See
ScimStorage.search().
- abstractmethod async create(resource_type: ResourceType, resource: Resource) Resource[source]#
Store a new resource. See
ScimStorage.create().
- abstractmethod async update(resource_type: ResourceType, resource: Resource, *, expected_version: str | None = None) Resource[source]#
Replace a stored resource. See
ScimStorage.update().
- abstractmethod async delete(resource_type: ResourceType, resource_id: str, *, expected_version: str | None = None) None[source]#
Delete a resource. See
ScimStorage.delete().
- operation() AbstractAsyncContextManager[None][source]#
Enclose one SCIM operation. See
ScimStorage.operation().
- class scim2_server.storage.SearchPage(total: int | None, resources: list[Resource], next: Any = None, previous: Any = None)[source]#
A page of found resources, as
ScimStorage.search()returns it.- total: int | None#
The number of matching resources, on every page.
It may be
Nonewhen the resources are paged with a cursor (RFC 9865 §2).
- class scim2_server.memory.InMemoryStorage(clock: Callable[[], ~datetime.datetime]=<function utcnow>)[source]#
A storage keeping the resources in memory, for tests, debugging and demos.
It is not optimized for performance: a search walks every resource. A lock serializes every access, so it can serve a threaded server.
- Parameters:
clock – Return the date of a write, for
meta.createdandmeta.lastModified. Pass a fixed clock to get predictable dates.
- generate_id(resource_type: ResourceType, resource: Resource) str[source]#
Return the identifier of a new resource.
Override this method to get predictable identifiers.
- class scim2_server.memory.AsyncInMemoryStorage(storage: InMemoryStorage | None = None)[source]#
The asynchronous variant of
InMemoryStorage.It serves the resources of an
InMemoryStorage. Every call runs without awaiting anything, so a call is never interrupted by another coroutine.operation()takes no lock: holding the lock of the storage across anawaitwould block the event loop. Two concurrent updates of a resource are still told apart byexpected_version.- Parameters:
storage – The storage to serve. Pass a subclass of
InMemoryStorageto change how identifiers are generated.