scim2-client 0.3.3__tar.gz → 0.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {scim2_client-0.3.3 → scim2_client-0.4.1}/PKG-INFO +9 -6
- {scim2_client-0.3.3 → scim2_client-0.4.1}/README.md +8 -5
- {scim2_client-0.3.3 → scim2_client-0.4.1}/doc/changelog.rst +28 -3
- {scim2_client-0.3.3 → scim2_client-0.4.1}/doc/tutorial.rst +59 -14
- {scim2_client-0.3.3 → scim2_client-0.4.1}/pyproject.toml +2 -1
- {scim2_client-0.3.3 → scim2_client-0.4.1}/scim2_client/__init__.py +2 -2
- {scim2_client-0.3.3 → scim2_client-0.4.1}/scim2_client/client.py +143 -57
- {scim2_client-0.3.3 → scim2_client-0.4.1}/scim2_client/engines/werkzeug.py +9 -1
- {scim2_client-0.3.3 → scim2_client-0.4.1}/scim2_client/errors.py +1 -1
- scim2_client-0.4.1/tests/conftest.py +17 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/tests/engines/test_httpx.py +17 -14
- {scim2_client-0.3.3 → scim2_client-0.4.1}/tests/engines/test_werkzeug.py +10 -14
- {scim2_client-0.3.3 → scim2_client-0.4.1}/tests/test_create.py +32 -51
- {scim2_client-0.3.3 → scim2_client-0.4.1}/tests/test_delete.py +11 -23
- {scim2_client-0.3.3 → scim2_client-0.4.1}/tests/test_query.py +65 -154
- {scim2_client-0.3.3 → scim2_client-0.4.1}/tests/test_replace.py +25 -43
- scim2_client-0.4.1/tests/test_utils.py +49 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/uv.lock +7 -7
- scim2_client-0.3.3/tests/test_utils.py +0 -16
- {scim2_client-0.3.3 → scim2_client-0.4.1}/.github/FUNDING.yml +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/.github/workflows/release.yml +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/.github/workflows/tests.yaml +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/.gitignore +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/.pre-commit-config.yaml +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/.readthedocs.yml +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/LICENSE.md +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/doc/__init__.py +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/doc/conf.py +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/doc/contributing.rst +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/doc/index.rst +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/doc/reference.rst +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/scim2_client/engines/__init__.py +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/scim2_client/engines/httpx.py +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/scim2_client/py.typed +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/tests/__init__.py +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/tests/engines/__init__.py +0 -0
- {scim2_client-0.3.3 → scim2_client-0.4.1}/tests/test_search.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: scim2-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Pythonically build SCIM requests and parse SCIM responses
|
|
5
5
|
Project-URL: documentation, https://scim2-client.readthedocs.io
|
|
6
6
|
Project-URL: repository, https://github.com/python-scim/scim2-client
|
|
@@ -234,7 +234,7 @@ Description-Content-Type: text/markdown
|
|
|
234
234
|
A SCIM client Python library built upon [scim2-models](https://scim2-models.readthedocs.io) ,
|
|
235
235
|
that pythonically build requests and parse responses,
|
|
236
236
|
following the [RFC7643](https://datatracker.ietf.org/doc/html/rfc7643.html) and [RFC7644](https://datatracker.ietf.org/doc/html/rfc7644.html) specifications.
|
|
237
|
-
You can use whatever request engine you prefer to perform network requests, but scim2-
|
|
237
|
+
You can use whatever request engine you prefer to perform network requests, but scim2-client comes with [httpx](https://github.com/encode/httpx) support.
|
|
238
238
|
|
|
239
239
|
It aims to be used in SCIM client applications, or in unit tests for SCIM server applications.
|
|
240
240
|
|
|
@@ -253,21 +253,24 @@ pip install scim2-client[httpx]
|
|
|
253
253
|
|
|
254
254
|
## Usage
|
|
255
255
|
|
|
256
|
-
Check the [tutorial](https://scim2-client.readthedocs.io/en/latest/tutorial.html)
|
|
256
|
+
Check the [tutorial](https://scim2-client.readthedocs.io/en/latest/tutorial.html)
|
|
257
|
+
and the [reference](https://scim2-client.readthedocs.io/en/latest/reference.html) for more details.
|
|
257
258
|
|
|
258
259
|
Here is an example of usage:
|
|
259
260
|
|
|
260
261
|
```python
|
|
261
262
|
import datetime
|
|
262
263
|
from httpx import Client
|
|
263
|
-
from scim2_models import
|
|
264
|
+
from scim2_models import Error
|
|
264
265
|
from scim2_client.engines.httpx import SyncSCIMClient
|
|
265
266
|
|
|
266
267
|
client = Client(base_url="https://auth.example/scim/v2", headers={"Authorization": "Bearer foobar"})
|
|
267
|
-
scim = SyncSCIMClient(client
|
|
268
|
+
scim = SyncSCIMClient(client)
|
|
269
|
+
scim.discover()
|
|
270
|
+
User = scim.get_resource_model("User")
|
|
268
271
|
|
|
269
272
|
# Query resources
|
|
270
|
-
user = scim.query(User
|
|
273
|
+
user = scim.query(User, "2819c223-7f76-453a-919d-413861904646")
|
|
271
274
|
assert user.user_name == "bjensen@example.com"
|
|
272
275
|
assert user.meta.last_updated == datetime.datetime(
|
|
273
276
|
2024, 4, 13, 12, 0, 0, tzinfo=datetime.timezone.utc
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
A SCIM client Python library built upon [scim2-models](https://scim2-models.readthedocs.io) ,
|
|
4
4
|
that pythonically build requests and parse responses,
|
|
5
5
|
following the [RFC7643](https://datatracker.ietf.org/doc/html/rfc7643.html) and [RFC7644](https://datatracker.ietf.org/doc/html/rfc7644.html) specifications.
|
|
6
|
-
You can use whatever request engine you prefer to perform network requests, but scim2-
|
|
6
|
+
You can use whatever request engine you prefer to perform network requests, but scim2-client comes with [httpx](https://github.com/encode/httpx) support.
|
|
7
7
|
|
|
8
8
|
It aims to be used in SCIM client applications, or in unit tests for SCIM server applications.
|
|
9
9
|
|
|
@@ -22,21 +22,24 @@ pip install scim2-client[httpx]
|
|
|
22
22
|
|
|
23
23
|
## Usage
|
|
24
24
|
|
|
25
|
-
Check the [tutorial](https://scim2-client.readthedocs.io/en/latest/tutorial.html)
|
|
25
|
+
Check the [tutorial](https://scim2-client.readthedocs.io/en/latest/tutorial.html)
|
|
26
|
+
and the [reference](https://scim2-client.readthedocs.io/en/latest/reference.html) for more details.
|
|
26
27
|
|
|
27
28
|
Here is an example of usage:
|
|
28
29
|
|
|
29
30
|
```python
|
|
30
31
|
import datetime
|
|
31
32
|
from httpx import Client
|
|
32
|
-
from scim2_models import
|
|
33
|
+
from scim2_models import Error
|
|
33
34
|
from scim2_client.engines.httpx import SyncSCIMClient
|
|
34
35
|
|
|
35
36
|
client = Client(base_url="https://auth.example/scim/v2", headers={"Authorization": "Bearer foobar"})
|
|
36
|
-
scim = SyncSCIMClient(client
|
|
37
|
+
scim = SyncSCIMClient(client)
|
|
38
|
+
scim.discover()
|
|
39
|
+
User = scim.get_resource_model("User")
|
|
37
40
|
|
|
38
41
|
# Query resources
|
|
39
|
-
user = scim.query(User
|
|
42
|
+
user = scim.query(User, "2819c223-7f76-453a-919d-413861904646")
|
|
40
43
|
assert user.user_name == "bjensen@example.com"
|
|
41
44
|
assert user.meta.last_updated == datetime.datetime(
|
|
42
45
|
2024, 4, 13, 12, 0, 0, tzinfo=datetime.timezone.utc
|
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
[0.4.1] - 2024-12-02
|
|
5
|
+
--------------------
|
|
6
|
+
|
|
7
|
+
Added
|
|
8
|
+
^^^^^
|
|
9
|
+
- :class:`~scim2_client.engines.werkzeug.TestSCIMClient` can handle absolute URLs.
|
|
10
|
+
|
|
11
|
+
Changed
|
|
12
|
+
^^^^^^^
|
|
13
|
+
- Avoid to initialize :paramref:`~scim2_client.SCIMClient.resource_models` with configuration resources.
|
|
14
|
+
|
|
15
|
+
[0.4.0] - 2024-12-02
|
|
16
|
+
--------------------
|
|
17
|
+
|
|
18
|
+
.. warning::
|
|
19
|
+
|
|
20
|
+
This version comes with breaking changes:
|
|
21
|
+
|
|
22
|
+
- :class:`~scim2_client.SCIMClient` takes a mandatory :paramref:`~scim2_client.SCIMClient.resource_types` parameter.
|
|
23
|
+
|
|
24
|
+
Added
|
|
25
|
+
^^^^^
|
|
26
|
+
- Implement :meth:`~scim2_client.SCIMClient.register_naive_resource_types`.
|
|
27
|
+
- Implement :meth:`~scim2_client.BaseSyncSCIMClient.discover` methods.
|
|
28
|
+
|
|
4
29
|
[0.3.3] - 2024-11-29
|
|
5
30
|
--------------------
|
|
6
31
|
|
|
@@ -14,9 +39,9 @@ Added
|
|
|
14
39
|
|
|
15
40
|
Added
|
|
16
41
|
^^^^^
|
|
17
|
-
- Implement :class:`~scim2_client.
|
|
18
|
-
:paramref:`~scim2_client.
|
|
19
|
-
:paramref:`~scim2_client.
|
|
42
|
+
- Implement :class:`~scim2_client.SCIMClient` :paramref:`~scim2_client.SCIMClient.check_request_payload`,
|
|
43
|
+
:paramref:`~scim2_client.SCIMClient.check_response_payload` and
|
|
44
|
+
:paramref:`~scim2_client.SCIMClient.raise_scim_errors` paramibutes,
|
|
20
45
|
to keep the same values for all the requests.
|
|
21
46
|
|
|
22
47
|
[0.3.1] - 2024-11-29
|
|
@@ -7,25 +7,70 @@ Initialization
|
|
|
7
7
|
scim2-client depends on request engines such as `httpx <https://github.com/encode/httpx>`_ to perform network requests.
|
|
8
8
|
This tutorial demonstrate how to use scim2-client with httpx, and suppose you have installed the `httpx` extra for example with ``pip install scim2-models[httpx]``.
|
|
9
9
|
|
|
10
|
-
As a start you will need to instantiate a httpx :code:`Client` object that you can parameter as your will, and then pass it to a :class
|
|
10
|
+
As a start you will need to instantiate a httpx :code:`Client` object that you can parameter as your will, and then pass it to a :class:`~scim2_client.SCIMClient` object.
|
|
11
11
|
In addition to your SCIM server root endpoint, you will probably want to provide some authorization headers through the httpx :code:`Client` :code:`headers` parameter:
|
|
12
12
|
|
|
13
13
|
.. code-block:: python
|
|
14
14
|
|
|
15
15
|
from httpx import Client
|
|
16
|
-
from scim2_models import User, EnterpriseUserUser, Group
|
|
17
16
|
from scim2_client.engines.httpx import SyncSCIMClient
|
|
18
17
|
|
|
19
|
-
client = Client(
|
|
20
|
-
|
|
18
|
+
client = Client(
|
|
19
|
+
base_url="https://auth.example/scim/v2",
|
|
20
|
+
headers={"Authorization": "Bearer foobar"},
|
|
21
|
+
)
|
|
22
|
+
scim = SyncSCIMClient(client)
|
|
21
23
|
|
|
22
|
-
You need to give to indicate to :class:`~scim2_client.
|
|
23
|
-
This is needed so scim2-client will be able to guess which resource type to instante when an arbitrary payload is met.
|
|
24
|
+
You need to give to indicate to :class:`~scim2_client.SCIMClient` all the different :class:`~scim2_models.Resource` models that you will need to manipulate, and the matching :class:`~scim2_models.ResourceType` objects to let the client know where to look for resources on the server.
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
You can either provision those objects manually or automatically.
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
Automatic provisioning
|
|
29
|
+
~~~~~~~~~~~~~~~~~~~~~~
|
|
30
|
+
|
|
31
|
+
The easiest way is to let the client discover what configuration and resources are available on the server.
|
|
32
|
+
The :meth:`~scim2_client.BaseSyncSCIMClient.discover` method looks for the server :class:`~scim2_models.ServiceProviderConfig`, :class:`~scim2_models.Schema` and :class:`~scim2_models.ResourceType` endpoints,
|
|
33
|
+
and dynamically generate local Python models based on those schemas.
|
|
34
|
+
They are then available to use with :meth:`~scim2_client.SCIMClient.get_resource_model`.
|
|
35
|
+
|
|
36
|
+
.. code-block:: python
|
|
37
|
+
:caption: Dynamically discover models from the server
|
|
38
|
+
|
|
39
|
+
scim.discover()
|
|
40
|
+
User = scim.get_resource_model("User")
|
|
41
|
+
EnterpriseUser = User.get_extension_model("EnterpriseUser")
|
|
42
|
+
|
|
43
|
+
Manual provisioning
|
|
44
|
+
~~~~~~~~~~~~~~~~~~~
|
|
45
|
+
To manually register models and resource types, you can simply use the :paramref:`~scim2_client.SCIMClient.resource_models` and :paramref:`~scim2_client.SCIMClient.resource_types` arguments.
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
.. code-block:: python
|
|
49
|
+
:caption: Manually registering models and resource types
|
|
50
|
+
|
|
51
|
+
from scim2_models import User, EnterpriseUserUser, Group, ResourceType
|
|
52
|
+
scim = SyncSCIMClient(
|
|
53
|
+
client,
|
|
54
|
+
resource_models=[User[EnterpriseUser], Group],
|
|
55
|
+
resource_types=[ResourceType(id="User", ...), ResourceType(id="Group", ...)],
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
.. tip::
|
|
59
|
+
|
|
60
|
+
If you know that all the resources are hosted at regular server endpoints
|
|
61
|
+
(for instance `/Users` for :class:`~scim2_models.User` etc.),
|
|
62
|
+
you can skip passing the :class:`~scim2_models.ResourceType` objects by hand,
|
|
63
|
+
and simply call :meth:`~scim2_client.SCIMClient.register_naive_resource_types`.
|
|
64
|
+
|
|
65
|
+
.. code-block:: python
|
|
66
|
+
:caption: Manually registering models and resource types
|
|
67
|
+
|
|
68
|
+
from scim2_models import User, EnterpriseUserUser, Group, ResourceType
|
|
69
|
+
scim = SyncSCIMClient(
|
|
70
|
+
client,
|
|
71
|
+
resource_models=[User[EnterpriseUser], Group],
|
|
72
|
+
)
|
|
73
|
+
scim.register_naive_resource_types()
|
|
29
74
|
|
|
30
75
|
Performing actions
|
|
31
76
|
==================
|
|
@@ -60,20 +105,20 @@ Have a look at the :doc:`reference` to see usage examples and the exhaustive set
|
|
|
60
105
|
Request and response validation
|
|
61
106
|
===============================
|
|
62
107
|
|
|
63
|
-
By default, the data passed to the :class:`SCIM client <scim2_client.
|
|
108
|
+
By default, the data passed to the :class:`SCIM client <scim2_client.SCIMClient>` as well as the server response will be validated against the SCIM specifications, and will raise an error if they don't respect them.
|
|
64
109
|
However sometimes you want to accept invalid inputs and outputs.
|
|
65
110
|
To achieve this, all the methods provide the following parameters, all are :data:`True` by default:
|
|
66
111
|
|
|
67
|
-
- :paramref:`~scim2_client.
|
|
112
|
+
- :paramref:`~scim2_client.SCIMClient.check_request_payload`:
|
|
68
113
|
If :data:`True` (the default) a :class:`~pydantic.ValidationError` will be raised if the input does not respect the SCIM standard.
|
|
69
114
|
If :data:`False`, input is expected to be a :data:`dict` that will be passed as-is in the request.
|
|
70
|
-
- :paramref:`~scim2_client.
|
|
115
|
+
- :paramref:`~scim2_client.SCIMClient.check_response_payload`:
|
|
71
116
|
If :data:`True` (the default) a :class:`~pydantic.ValidationError` will be raised if the server response does not respect the SCIM standard.
|
|
72
117
|
If :data:`False` the server response is returned as-is.
|
|
73
118
|
- :code:`expected_status_codes`: The list of expected status codes in the response.
|
|
74
119
|
If :data:`None` any status code is accepted.
|
|
75
120
|
If an unexpected status code is returned, a :class:`~scim2_client.errors.UnexpectedStatusCode` exception is raised.
|
|
76
|
-
- :paramref:`~scim2_client.
|
|
121
|
+
- :paramref:`~scim2_client.SCIMClient.raise_scim_errors`: If :data:`True` (the default) and the server returned an :class:`~scim2_models.Error` object, a :class:`~scim2_client.SCIMResponseErrorObject` exception will be raised.
|
|
77
122
|
If :data:`False` the error object is returned.
|
|
78
123
|
|
|
79
124
|
|
|
@@ -95,7 +140,7 @@ Currently those engines are shipped:
|
|
|
95
140
|
It takes a WSGI app and directly execute the server code instead of performing real HTTP requests.
|
|
96
141
|
This is faster in unit test suites, and helpful to catch the server exceptions.
|
|
97
142
|
|
|
98
|
-
You can easily implement your own engine by inheriting from :class:`~scim2_client.
|
|
143
|
+
You can easily implement your own engine by inheriting from :class:`~scim2_client.SCIMClient`.
|
|
99
144
|
|
|
100
145
|
Additional request parameters
|
|
101
146
|
=============================
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scim2-client"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.1"
|
|
8
8
|
description = "Pythonically build SCIM requests and parse SCIM responses"
|
|
9
9
|
authors = [{name="Yaal Coop", email="contact@yaal.coop"}]
|
|
10
10
|
license = {file = "LICENSE.md"}
|
|
@@ -151,6 +151,7 @@ commands = [
|
|
|
151
151
|
]
|
|
152
152
|
|
|
153
153
|
[tool.tox.env.minversions]
|
|
154
|
+
runner = "uv-venv-lock-runner"
|
|
154
155
|
uv_resolution = "lowest-direct"
|
|
155
156
|
|
|
156
157
|
[tool.tox.env.doc]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from .client import BaseSCIMClient
|
|
2
1
|
from .client import BaseSyncSCIMClient
|
|
2
|
+
from .client import SCIMClient
|
|
3
3
|
from .errors import RequestNetworkError
|
|
4
4
|
from .errors import RequestPayloadValidationError
|
|
5
5
|
from .errors import ResponsePayloadValidationError
|
|
@@ -12,7 +12,7 @@ from .errors import UnexpectedContentType
|
|
|
12
12
|
from .errors import UnexpectedStatusCode
|
|
13
13
|
|
|
14
14
|
__all__ = [
|
|
15
|
-
"
|
|
15
|
+
"SCIMClient",
|
|
16
16
|
"BaseSyncSCIMClient",
|
|
17
17
|
"SCIMClientError",
|
|
18
18
|
"SCIMRequestError",
|