scim2-client 0.2.2__tar.gz → 0.3.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.
Files changed (37) hide show
  1. {scim2_client-0.2.2 → scim2_client-0.3.1}/.github/workflows/tests.yaml +3 -1
  2. {scim2_client-0.2.2 → scim2_client-0.3.1}/.pre-commit-config.yaml +2 -2
  3. {scim2_client-0.2.2 → scim2_client-0.3.1}/PKG-INFO +11 -7
  4. {scim2_client-0.2.2 → scim2_client-0.3.1}/README.md +6 -5
  5. {scim2_client-0.2.2 → scim2_client-0.3.1}/doc/changelog.rst +28 -0
  6. {scim2_client-0.2.2 → scim2_client-0.3.1}/doc/conf.py +1 -0
  7. scim2_client-0.3.1/doc/reference.rst +14 -0
  8. {scim2_client-0.2.2 → scim2_client-0.3.1}/doc/tutorial.rst +27 -11
  9. {scim2_client-0.2.2 → scim2_client-0.3.1}/pyproject.toml +21 -4
  10. {scim2_client-0.2.2 → scim2_client-0.3.1}/scim2_client/__init__.py +4 -2
  11. scim2_client-0.3.1/scim2_client/client.py +995 -0
  12. scim2_client-0.3.1/scim2_client/engines/httpx.py +430 -0
  13. scim2_client-0.3.1/scim2_client/engines/werkzeug.py +245 -0
  14. {scim2_client-0.2.2 → scim2_client-0.3.1}/scim2_client/errors.py +6 -9
  15. scim2_client-0.3.1/tests/__init__.py +0 -0
  16. scim2_client-0.3.1/tests/engines/__init__.py +0 -0
  17. scim2_client-0.3.1/tests/engines/test_httpx.py +111 -0
  18. scim2_client-0.3.1/tests/engines/test_werkzeug.py +63 -0
  19. {scim2_client-0.2.2 → scim2_client-0.3.1}/tests/test_create.py +16 -16
  20. {scim2_client-0.2.2 → scim2_client-0.3.1}/tests/test_delete.py +8 -8
  21. {scim2_client-0.2.2 → scim2_client-0.3.1}/tests/test_query.py +44 -44
  22. {scim2_client-0.2.2 → scim2_client-0.3.1}/tests/test_replace.py +13 -13
  23. {scim2_client-0.2.2 → scim2_client-0.3.1}/tests/test_search.py +12 -12
  24. {scim2_client-0.2.2 → scim2_client-0.3.1}/tests/test_utils.py +2 -2
  25. {scim2_client-0.2.2 → scim2_client-0.3.1}/uv.lock +337 -208
  26. scim2_client-0.2.2/doc/reference.rst +0 -6
  27. scim2_client-0.2.2/scim2_client/client.py +0 -687
  28. {scim2_client-0.2.2 → scim2_client-0.3.1}/.github/FUNDING.yml +0 -0
  29. {scim2_client-0.2.2 → scim2_client-0.3.1}/.github/workflows/release.yml +0 -0
  30. {scim2_client-0.2.2 → scim2_client-0.3.1}/.gitignore +0 -0
  31. {scim2_client-0.2.2 → scim2_client-0.3.1}/.readthedocs.yml +0 -0
  32. {scim2_client-0.2.2 → scim2_client-0.3.1}/LICENSE.md +0 -0
  33. {scim2_client-0.2.2 → scim2_client-0.3.1}/doc/__init__.py +0 -0
  34. {scim2_client-0.2.2 → scim2_client-0.3.1}/doc/contributing.rst +0 -0
  35. {scim2_client-0.2.2 → scim2_client-0.3.1}/doc/index.rst +0 -0
  36. {scim2_client-0.2.2/tests → scim2_client-0.3.1/scim2_client/engines}/__init__.py +0 -0
  37. {scim2_client-0.2.2 → scim2_client-0.3.1}/scim2_client/py.typed +0 -0
@@ -31,6 +31,8 @@ jobs:
31
31
  enable-cache: true
32
32
  - name: Install Python ${{ matrix.python }}
33
33
  run: uv python install ${{ matrix.python }}
34
+ - name: Install dependencies
35
+ run: uv sync --all-extras
34
36
  - name: Run tests
35
37
  run: uv run pytest --showlocals
36
38
 
@@ -44,7 +46,7 @@ jobs:
44
46
  with:
45
47
  enable-cache: true
46
48
  - name: Install minimum dependencies
47
- run: uv sync --resolution=lowest-direct
49
+ run: uv sync --resolution=lowest-direct --all-extras
48
50
  - name: Run tests
49
51
  run: uv run pytest --showlocals
50
52
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  repos:
3
3
  - repo: https://github.com/astral-sh/ruff-pre-commit
4
- rev: 'v0.6.9'
4
+ rev: 'v0.8.0'
5
5
  hooks:
6
6
  - id: ruff
7
7
  args: [--fix, --exit-non-zero-on-fix]
@@ -16,7 +16,7 @@ repos:
16
16
  exclude: "\\.svg$|\\.map$|\\.min\\.css$|\\.min\\.js$|\\.po$|\\.pot$"
17
17
  - id: check-toml
18
18
  - repo: https://github.com/pre-commit/mirrors-mypy
19
- rev: v1.11.2
19
+ rev: v1.13.0
20
20
  hooks:
21
21
  - id: mypy
22
22
  additional_dependencies: [pydantic]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: scim2-client
3
- Version: 0.2.2
3
+ Version: 0.3.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
@@ -222,15 +222,19 @@ Classifier: Programming Language :: Python :: 3.12
222
222
  Classifier: Programming Language :: Python :: 3.13
223
223
  Classifier: Programming Language :: Python :: Implementation :: CPython
224
224
  Requires-Python: >=3.9
225
- Requires-Dist: httpx>=0.24.0
226
225
  Requires-Dist: scim2-models>=0.2.0
226
+ Provides-Extra: httpx
227
+ Requires-Dist: httpx>=0.28.0; extra == 'httpx'
228
+ Provides-Extra: werkzeug
229
+ Requires-Dist: werkzeug>=3.1.3; extra == 'werkzeug'
227
230
  Description-Content-Type: text/markdown
228
231
 
229
232
  # scim2-client
230
233
 
231
- A SCIM client Python library built upon [scim2-models](https://scim2-models.readthedocs.io) and [httpx](https://github.com/encode/httpx),
234
+ A SCIM client Python library built upon [scim2-models](https://scim2-models.readthedocs.io) ,
232
235
  that pythonically build requests and parse responses,
233
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.
234
238
 
235
239
  It aims to be used in SCIM client applications, or in unit tests for SCIM server applications.
236
240
 
@@ -244,7 +248,7 @@ It allows users and groups creations, modifications and deletions to be synchron
244
248
  ## Installation
245
249
 
246
250
  ```shell
247
- pip install scim2-client
251
+ pip install scim2-client[httpx]
248
252
  ```
249
253
 
250
254
  ## Usage
@@ -257,10 +261,10 @@ Here is an example of usage:
257
261
  import datetime
258
262
  from httpx import Client
259
263
  from scim2_models import User, EnterpriseUser, Group, Error
260
- from scim2_client import SCIMClient
264
+ from scim2_client.engines.httpx import SyncSCIMClient
261
265
 
262
- client = Client(base_url=f"https://auth.example/scim/v2", headers={"Authorization": "Bearer foobar"})
263
- scim = SCIMClient(client, resource_types=(User[EnterpriseUser], Group))
266
+ client = Client(base_url="https://auth.example/scim/v2", headers={"Authorization": "Bearer foobar"})
267
+ scim = SyncSCIMClient(client, resource_types=(User[EnterpriseUser], Group))
264
268
 
265
269
  # Query resources
266
270
  user = scim.query(User[EnterpriseUser], "2819c223-7f76-453a-919d-413861904646")
@@ -1,8 +1,9 @@
1
1
  # scim2-client
2
2
 
3
- A SCIM client Python library built upon [scim2-models](https://scim2-models.readthedocs.io) and [httpx](https://github.com/encode/httpx),
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
7
 
7
8
  It aims to be used in SCIM client applications, or in unit tests for SCIM server applications.
8
9
 
@@ -16,7 +17,7 @@ It allows users and groups creations, modifications and deletions to be synchron
16
17
  ## Installation
17
18
 
18
19
  ```shell
19
- pip install scim2-client
20
+ pip install scim2-client[httpx]
20
21
  ```
21
22
 
22
23
  ## Usage
@@ -29,10 +30,10 @@ Here is an example of usage:
29
30
  import datetime
30
31
  from httpx import Client
31
32
  from scim2_models import User, EnterpriseUser, Group, Error
32
- from scim2_client import SCIMClient
33
+ from scim2_client.engines.httpx import SyncSCIMClient
33
34
 
34
- client = Client(base_url=f"https://auth.example/scim/v2", headers={"Authorization": "Bearer foobar"})
35
- scim = SCIMClient(client, resource_types=(User[EnterpriseUser], Group))
35
+ client = Client(base_url="https://auth.example/scim/v2", headers={"Authorization": "Bearer foobar"})
36
+ scim = SyncSCIMClient(client, resource_types=(User[EnterpriseUser], Group))
36
37
 
37
38
  # Query resources
38
39
  user = scim.query(User[EnterpriseUser], "2819c223-7f76-453a-919d-413861904646")
@@ -1,6 +1,34 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ [0.3.1] - 2024-11-29
5
+ --------------------
6
+
7
+ Fixed
8
+ ^^^^^
9
+ - Some variables were missing from the SCIM exception classes.
10
+
11
+ [0.3.0] - 2024-11-29
12
+ --------------------
13
+
14
+ .. warning::
15
+
16
+ This version comes with breaking changes:
17
+
18
+ - `httpx` is no longer a direct dependency, it is shipped in the `httpx` packaging extra.
19
+ - ``scim2_client.SCIMClient`` has moved to ``scim2_client.engines.httpx.SyncSCIMClient``.
20
+ - The ``resource_types`` parameters has been renamed ``resource_models``.
21
+
22
+ Added
23
+ ^^^^^
24
+ - The `Unknown resource type` request error keeps a reference to the faulty payload.
25
+ - New `werkzeug` request engine for application development purpose.
26
+ - New `AsyncSCIMClient` request engine. :issue:`1`
27
+
28
+ Changed
29
+ ^^^^^^^
30
+ - Separate httpx network code and SCIM code in separate file as a basis for async support (and maybe other request engines).
31
+
4
32
  [0.2.2] - 2024-11-12
5
33
  --------------------
6
34
 
@@ -42,6 +42,7 @@ toctree_collapse = False
42
42
  intersphinx_mapping = {
43
43
  "python": ("https://docs.python.org/3", None),
44
44
  "scim2_models": ("https://scim2-models.readthedocs.io/en/latest/", None),
45
+ "werkzeug": ("https://werkzeug.palletsprojects.com", None),
45
46
  }
46
47
 
47
48
  # -- Options for HTML output ----------------------------------------------
@@ -0,0 +1,14 @@
1
+ Reference
2
+ =========
3
+
4
+ .. automodule:: scim2_client.engines.httpx
5
+ :members:
6
+ :member-order: bysource
7
+
8
+ .. automodule:: scim2_client.engines.werkzeug
9
+ :members:
10
+ :member-order: bysource
11
+
12
+ .. automodule:: scim2_client
13
+ :members:
14
+ :member-order: bysource
@@ -4,18 +4,20 @@ Tutorial
4
4
  Initialization
5
5
  ==============
6
6
 
7
- scim2-client depends on `httpx <https://github.com/encode/httpx>`_ to perform network requests.
8
- 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.
7
+ scim2-client depends on request engines such as `httpx <https://github.com/encode/httpx>`_ to perform network requests.
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
+
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.
9
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:
10
12
 
11
13
  .. code-block:: python
12
14
 
13
15
  from httpx import Client
14
16
  from scim2_models import User, EnterpriseUserUser, Group
15
- from scim2_client import SCIMClient
17
+ from scim2_client.engines.httpx import SyncSCIMClient
16
18
 
17
19
  client = Client(base_url="https://auth.example/scim/v2", headers={"Authorization": "Bearer foobar"})
18
- scim = SCIMClient(client, resource_types=(User[EnterpriseUser], Group))
20
+ scim = SyncSCIMClient(client, resource_types=(User[EnterpriseUser], Group))
19
21
 
20
22
  You need to give to indicate to :class:`~scim2_client.SCIMClient` all the different :class:`~scim2_models.Resource` types that you will need to manipulate with the :code:`resource_types` parameter.
21
23
  This is needed so scim2-client will be able to guess which resource type to instante when an arbitrary payload is met.
@@ -31,11 +33,11 @@ Performing actions
31
33
  scim2-client allows your application to interact with a SCIM server as described in :rfc:`RFC7644 §3 <7644#section-3>`, so you can read and manage the resources.
32
34
  The following actions are available:
33
35
 
34
- - :meth:`~scim2_client.SCIMClient.create`
35
- - :meth:`~scim2_client.SCIMClient.query`
36
- - :meth:`~scim2_client.SCIMClient.replace`
37
- - :meth:`~scim2_client.SCIMClient.delete`
38
- - :meth:`~scim2_client.SCIMClient.search`
36
+ - :meth:`~scim2_client.BaseSCIMClient.create`
37
+ - :meth:`~scim2_client.BaseSCIMClient.query`
38
+ - :meth:`~scim2_client.BaseSCIMClient.replace`
39
+ - :meth:`~scim2_client.BaseSCIMClient.delete`
40
+ - :meth:`~scim2_client.BaseSCIMClient.search`
39
41
 
40
42
  Have a look at the :doc:`reference` to see usage examples and the exhaustive set of parameters, but generally it looks like this:
41
43
 
@@ -58,7 +60,7 @@ Have a look at the :doc:`reference` to see usage examples and the exhaustive set
58
60
  Request and response validation
59
61
  ===============================
60
62
 
61
- By default, the data passed to the :class:`~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.
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.
62
64
  However sometimes you want to accept invalid inputs and outputs.
63
65
  To achieve this, all the methods provide the following parameters, all are :data:`True` by default:
64
66
 
@@ -81,10 +83,24 @@ To achieve this, all the methods provide the following parameters, all are :data
81
83
  which value will excluded from the request payload, and which values are
82
84
  expected in the response payload.
83
85
 
86
+ Engines
87
+ =======
88
+
89
+ scim2-client comes with a light abstraction layers that allows for different requests engines.
90
+ Currently those engines are shipped:
91
+
92
+ - :class:`~scim2_client.engines.httpx.SyncSCIMClient`: A synchronous engine using `httpx <https://github.com/encode/httpx>`_ to perform the HTTP requests.
93
+ - :class:`~scim2_client.engines.httpx.AsyncSCIMClient`: An asynchronous engine using `httpx <https://github.com/encode/httpx>`_ to perform the HTTP requests. It has the very same API than its synchronous version, except it is asynchronous.
94
+ - :class:`~scim2_client.engines.werkzeug.TestSCIMClient`: A test engine for development purposes.
95
+ It takes a WSGI app and directly execute the server code instead of performing real HTTP requests.
96
+ This is faster in unit test suites, and helpful to catch the server exceptions.
97
+
98
+ You can easily implement your own engine by inheriting from :class:`~scim2_client.BaseSCIMClient`.
99
+
84
100
  Additional request parameters
85
101
  =============================
86
102
 
87
- Any additional parameter will be passed to the underlying httpx methods.
103
+ Any additional parameter will be passed to the underlying engine methods.
88
104
  This can be useful if you need to explicitly pass a certain URL for example:
89
105
 
90
106
  .. code-block:: python
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "scim2-client"
7
- version = "0.2.2"
7
+ version = "0.3.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"}
@@ -27,10 +27,18 @@ classifiers = [
27
27
 
28
28
  requires-python = ">= 3.9"
29
29
  dependencies = [
30
- "httpx>=0.24.0",
31
30
  "scim2-models>=0.2.0",
32
31
  ]
33
32
 
33
+ [project.optional-dependencies]
34
+ httpx = [
35
+ "httpx>=0.28.0",
36
+ ]
37
+
38
+ werkzeug = [
39
+ "werkzeug>=3.1.3",
40
+ ]
41
+
34
42
  [project.urls]
35
43
  documentation = "https://scim2-client.readthedocs.io"
36
44
  repository = "https://github.com/python-scim/scim2-client"
@@ -39,12 +47,16 @@ funding = "https://github.com/sponsors/python-scim"
39
47
 
40
48
  [dependency-groups]
41
49
  dev = [
50
+ "mypy>=1.13.0",
51
+ "portpicker>=1.6.0",
42
52
  "pre-commit-uv>=4.1.4",
43
53
  "pytest>=8.2.1",
54
+ "pytest-asyncio>=0.24.0",
44
55
  "pytest-coverage>=0.0",
45
- "pytest-httpserver>=1.0.10",
56
+ "pytest-httpserver>=1.1.0",
57
+ "scim2-server >= 0.1.2; python_version>='3.10'",
46
58
  "tox-uv>=1.16.0",
47
- "mypy>=1.13.0",
59
+ "werkzeug>=3.1.3",
48
60
  ]
49
61
  doc = [
50
62
  "autodoc-pydantic>=2.2.0",
@@ -105,6 +117,10 @@ plugins = [
105
117
  "pydantic.mypy"
106
118
  ]
107
119
 
120
+ [tool.pytest.ini_options]
121
+ asyncio_mode="auto"
122
+ asyncio_default_fixture_loop_scope = "function"
123
+
108
124
  [tool.tox]
109
125
  requires = ["tox>=4.19"]
110
126
  env_list = [
@@ -120,6 +136,7 @@ env_list = [
120
136
  ]
121
137
 
122
138
  [tool.tox.env_run_base]
139
+ extras = ["httpx", "werkzeug"]
123
140
  runner = "uv-venv-lock-runner"
124
141
  dependency_groups = ["dev"]
125
142
  commands = [
@@ -1,4 +1,5 @@
1
- from .client import SCIMClient
1
+ from .client import BaseSCIMClient
2
+ from .client import BaseSyncSCIMClient
2
3
  from .errors import RequestNetworkError
3
4
  from .errors import RequestPayloadValidationError
4
5
  from .errors import ResponsePayloadValidationError
@@ -11,7 +12,8 @@ from .errors import UnexpectedContentType
11
12
  from .errors import UnexpectedStatusCode
12
13
 
13
14
  __all__ = [
14
- "SCIMClient",
15
+ "BaseSCIMClient",
16
+ "BaseSyncSCIMClient",
15
17
  "SCIMClientError",
16
18
  "SCIMRequestError",
17
19
  "SCIMResponseError",