scim2-client 0.3.3__tar.gz → 0.4.0__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.
Files changed (37) hide show
  1. {scim2_client-0.3.3 → scim2_client-0.4.0}/PKG-INFO +9 -6
  2. {scim2_client-0.3.3 → scim2_client-0.4.0}/README.md +8 -5
  3. {scim2_client-0.3.3 → scim2_client-0.4.0}/doc/changelog.rst +17 -3
  4. {scim2_client-0.3.3 → scim2_client-0.4.0}/doc/tutorial.rst +59 -14
  5. {scim2_client-0.3.3 → scim2_client-0.4.0}/pyproject.toml +2 -1
  6. {scim2_client-0.3.3 → scim2_client-0.4.0}/scim2_client/__init__.py +2 -2
  7. {scim2_client-0.3.3 → scim2_client-0.4.0}/scim2_client/client.py +143 -57
  8. {scim2_client-0.3.3 → scim2_client-0.4.0}/scim2_client/engines/werkzeug.py +3 -0
  9. {scim2_client-0.3.3 → scim2_client-0.4.0}/scim2_client/errors.py +1 -1
  10. scim2_client-0.4.0/tests/conftest.py +17 -0
  11. {scim2_client-0.3.3 → scim2_client-0.4.0}/tests/engines/test_httpx.py +17 -14
  12. {scim2_client-0.3.3 → scim2_client-0.4.0}/tests/engines/test_werkzeug.py +10 -14
  13. {scim2_client-0.3.3 → scim2_client-0.4.0}/tests/test_create.py +32 -51
  14. {scim2_client-0.3.3 → scim2_client-0.4.0}/tests/test_delete.py +11 -23
  15. {scim2_client-0.3.3 → scim2_client-0.4.0}/tests/test_query.py +65 -154
  16. {scim2_client-0.3.3 → scim2_client-0.4.0}/tests/test_replace.py +25 -43
  17. scim2_client-0.4.0/tests/test_utils.py +49 -0
  18. {scim2_client-0.3.3 → scim2_client-0.4.0}/uv.lock +7 -7
  19. scim2_client-0.3.3/tests/test_utils.py +0 -16
  20. {scim2_client-0.3.3 → scim2_client-0.4.0}/.github/FUNDING.yml +0 -0
  21. {scim2_client-0.3.3 → scim2_client-0.4.0}/.github/workflows/release.yml +0 -0
  22. {scim2_client-0.3.3 → scim2_client-0.4.0}/.github/workflows/tests.yaml +0 -0
  23. {scim2_client-0.3.3 → scim2_client-0.4.0}/.gitignore +0 -0
  24. {scim2_client-0.3.3 → scim2_client-0.4.0}/.pre-commit-config.yaml +0 -0
  25. {scim2_client-0.3.3 → scim2_client-0.4.0}/.readthedocs.yml +0 -0
  26. {scim2_client-0.3.3 → scim2_client-0.4.0}/LICENSE.md +0 -0
  27. {scim2_client-0.3.3 → scim2_client-0.4.0}/doc/__init__.py +0 -0
  28. {scim2_client-0.3.3 → scim2_client-0.4.0}/doc/conf.py +0 -0
  29. {scim2_client-0.3.3 → scim2_client-0.4.0}/doc/contributing.rst +0 -0
  30. {scim2_client-0.3.3 → scim2_client-0.4.0}/doc/index.rst +0 -0
  31. {scim2_client-0.3.3 → scim2_client-0.4.0}/doc/reference.rst +0 -0
  32. {scim2_client-0.3.3 → scim2_client-0.4.0}/scim2_client/engines/__init__.py +0 -0
  33. {scim2_client-0.3.3 → scim2_client-0.4.0}/scim2_client/engines/httpx.py +0 -0
  34. {scim2_client-0.3.3 → scim2_client-0.4.0}/scim2_client/py.typed +0 -0
  35. {scim2_client-0.3.3 → scim2_client-0.4.0}/tests/__init__.py +0 -0
  36. {scim2_client-0.3.3 → scim2_client-0.4.0}/tests/engines/__init__.py +0 -0
  37. {scim2_client-0.3.3 → scim2_client-0.4.0}/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.3
3
+ Version: 0.4.0
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-models comes with [httpx](https://github.com/encode/httpx) support.
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) and the [reference](https://scim2-client.readthedocs.io/en/latest/reference.html) for more details.
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 User, EnterpriseUser, Group, Error
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, resource_types=(User[EnterpriseUser], Group))
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[EnterpriseUser], "2819c223-7f76-453a-919d-413861904646")
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-models comes with [httpx](https://github.com/encode/httpx) support.
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) and the [reference](https://scim2-client.readthedocs.io/en/latest/reference.html) for more details.
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 User, EnterpriseUser, Group, Error
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, resource_types=(User[EnterpriseUser], Group))
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[EnterpriseUser], "2819c223-7f76-453a-919d-413861904646")
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,20 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ [0.4.0] - 2024-12-02
5
+ --------------------
6
+
7
+ .. warning::
8
+
9
+ This version comes with breaking changes:
10
+
11
+ - :class:`~scim2_client.SCIMClient` takes a mandatory :paramref:`~scim2_client.SCIMClient.resource_types` parameter.
12
+
13
+ Added
14
+ ^^^^^
15
+ - Implement :meth:`~scim2_client.SCIMClient.register_naive_resource_types`.
16
+ - Implement :meth:`~scim2_client.BaseSyncSCIMClient.discover` methods.
17
+
4
18
  [0.3.3] - 2024-11-29
5
19
  --------------------
6
20
 
@@ -14,9 +28,9 @@ Added
14
28
 
15
29
  Added
16
30
  ^^^^^
17
- - Implement :class:`~scim2_client.BaseSCIMClient` :paramref:`~scim2_client.BaseSCIMClient.check_request_payload`,
18
- :paramref:`~scim2_client.BaseSCIMClient.check_response_payload` and
19
- :paramref:`~scim2_client.BaseSCIMClient.raise_scim_errors` paramibutes,
31
+ - Implement :class:`~scim2_client.SCIMClient` :paramref:`~scim2_client.SCIMClient.check_request_payload`,
32
+ :paramref:`~scim2_client.SCIMClient.check_response_payload` and
33
+ :paramref:`~scim2_client.SCIMClient.raise_scim_errors` paramibutes,
20
34
  to keep the same values for all the requests.
21
35
 
22
36
  [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:`SCIM client <scim2_client.BaseSCIMClient>` object.
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(base_url="https://auth.example/scim/v2", headers={"Authorization": "Bearer foobar"})
20
- scim = SyncSCIMClient(client, resource_models=(User[EnterpriseUser], Group))
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.BaseSCIMClient` all the different :class:`~scim2_models.Resource` types that you will need to manipulate with the :code:`resource_models` parameter.
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
- .. todo::
26
+ You can either provision those objects manually or automatically.
26
27
 
27
- We plan to implement the automatic discovery of SCIM server resources,
28
- so they can dynamically be used without explicitly passing them with the :code:`resource_models` parameter.
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.BaseSCIMClient>` as well as the server response will be validated against the SCIM specifications, and will raise an error if they don't respect them.
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.BaseSCIMClient.check_request_payload`:
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.BaseSCIMClient.check_response_payload`:
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.BaseSCIMClient.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.
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.BaseSCIMClient`.
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.3.3"
7
+ version = "0.4.0"
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
- "BaseSCIMClient",
15
+ "SCIMClient",
16
16
  "BaseSyncSCIMClient",
17
17
  "SCIMClientError",
18
18
  "SCIMRequestError",