Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Added
- Resources define their schema URN with a ``__schema__`` classvar instead of a ``schemas`` default value. :issue:`110`
- Validation that the base schema is present in ``schemas`` during SCIM context validation.
- Validation that extension schemas are known during SCIM context validation.
- Introduce SCIM exceptions hierarchy (:class:`~scim2_models.SCIMException` and subclasses) corresponding to RFC 7644 error types. :issue:`103`
- :meth:`Error.from_validation_error <scim2_models.Error.from_validation_error>` to convert Pydantic :class:`~pydantic.ValidationError` to SCIM :class:`~scim2_models.Error`.

Changed
^^^^^^^
Expand All @@ -17,6 +19,7 @@ Changed
Deprecated
^^^^^^^^^^
- Defining ``schemas`` with a default value is deprecated. Use ``__schema__ = URN("...")`` instead.
- ``Error.make_*_error()`` methods are deprecated. Use ``<Exception>.to_error()`` instead.

[0.5.2] - 2026-01-22
--------------------
Expand Down
79 changes: 66 additions & 13 deletions doc/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -275,26 +275,79 @@ Extensions attributes are accessed with brackets, e.g. ``user[EnterpriseUser].em
... }


Pre-defined Error objects
=========================
Errors and Exceptions
=====================

:rfc:`RFC7643 §3.12 <7643#section-3.12>` pre-defined errors are usable.
scim2-models provides a hierarchy of exceptions corresponding to :rfc:`RFC7644 §3.12 <7644#section-3.12>` error types.
Each exception can be converted to an :class:`~scim2_models.Error` response object or used in Pydantic validators.

Raising exceptions
~~~~~~~~~~~~~~~~~~

Exceptions are named after their ``scimType`` value:

.. code-block:: python

>>> from scim2_models import Error
>>> from scim2_models import InvalidPathException, PathNotFoundException

>>> error = Error.make_invalid_path_error()
>>> dump = error.model_dump()
>>> assert dump == {
... 'detail': 'The "path" attribute was invalid or malformed (see Figure 7 of RFC7644).',
... 'schemas': ['urn:ietf:params:scim:api:messages:2.0:Error'],
... 'scimType': 'invalidPath',
... 'status': '400'
... }
>>> raise InvalidPathException(path="invalid..path")
Traceback (most recent call last):
...
scim2_models.exceptions.InvalidPathException: The path attribute was invalid or malformed

>>> raise PathNotFoundException(path="unknownAttr")
Traceback (most recent call last):
...
scim2_models.exceptions.PathNotFoundException: The specified path references a non-existent field

Converting to Error response
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Use :meth:`~scim2_models.SCIMException.to_error` to convert an exception to an :class:`~scim2_models.Error` response:

.. code-block:: python

>>> from scim2_models import InvalidPathException

>>> exc = InvalidPathException(path="invalid..path")
>>> error = exc.to_error()
>>> error.status
400
>>> error.scim_type
'invalidPath'

The exhaustive list is available in the :class:`reference <scim2_models.Error>`.
Converting from ValidationError
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Use :meth:`Error.from_validation_error <scim2_models.Error.from_validation_error>` to convert a single Pydantic error to an :class:`~scim2_models.Error`:

.. code-block:: python

>>> from pydantic import ValidationError
>>> from scim2_models import Error, User
>>> from scim2_models.base import Context

>>> try:
... User.model_validate({"userName": None}, context={"scim": Context.RESOURCE_CREATION_REQUEST})
... except ValidationError as exc:
... error = Error.from_validation_error(exc.errors()[0])
>>> error.scim_type
'invalidValue'

Use :meth:`Error.from_validation_errors <scim2_models.Error.from_validation_errors>` to convert all errors at once:

.. code-block:: python

>>> try:
... User.model_validate({"userName": 123, "displayName": 456})
... except ValidationError as exc:
... errors = Error.from_validation_errors(exc)
>>> len(errors)
2
>>> [e.detail for e in errors]
['Input should be a valid string: userName', 'Input should be a valid string: displayName']

The exhaustive list of exceptions is available in the :class:`reference <scim2_models.SCIMException>`.

Custom models
=============
Expand Down
30 changes: 24 additions & 6 deletions scim2_models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@
from .attributes import MultiValuedComplexAttribute
from .base import BaseModel
from .context import Context
from .exceptions import InvalidFilterException
from .exceptions import InvalidPathException
from .exceptions import InvalidSyntaxException
from .exceptions import InvalidValueException
from .exceptions import InvalidVersionException
from .exceptions import MutabilityException
from .exceptions import NoTargetException
from .exceptions import PathNotFoundException
from .exceptions import SCIMException
from .exceptions import SensitiveException
from .exceptions import TooManyException
from .exceptions import UniquenessException
from .messages.bulk import BulkOperation
from .messages.bulk import BulkRequest
from .messages.bulk import BulkResponse
Expand All @@ -17,10 +29,7 @@
from .messages.patch_op import PatchOperation
from .messages.search_request import SearchRequest
from .path import URN
from .path import InvalidPathError
from .path import Path
from .path import PathError
from .path import PathNotFoundError
from .reference import ExternalReference
from .reference import Reference
from .reference import URIReference
Expand Down Expand Up @@ -84,17 +93,22 @@
"GroupMember",
"GroupMembership",
"Im",
"InvalidPathError",
"InvalidFilterException",
"InvalidPathException",
"InvalidSyntaxException",
"InvalidValueException",
"InvalidVersionException",
"ListResponse",
"Manager",
"Message",
"Meta",
"Mutability",
"MutabilityException",
"MultiValuedComplexAttribute",
"Name",
"NoTargetException",
"Path",
"PathError",
"PathNotFoundError",
"PathNotFoundException",
"Patch",
"PatchOp",
"PatchOperation",
Expand All @@ -106,12 +120,16 @@
"ResourceType",
"Returned",
"Role",
"SCIMException",
"Schema",
"SchemaExtension",
"SearchRequest",
"SensitiveException",
"ServiceProviderConfig",
"Sort",
"TooManyException",
"Uniqueness",
"UniquenessException",
"URIReference",
"URN",
"User",
Expand Down
Loading
Loading