scim2-client 0.2.1__tar.gz → 0.3.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.2.1 → scim2_client-0.3.0}/.github/workflows/release.yml +1 -1
  2. {scim2_client-0.2.1 → scim2_client-0.3.0}/.github/workflows/tests.yaml +3 -1
  3. {scim2_client-0.2.1 → scim2_client-0.3.0}/.pre-commit-config.yaml +6 -1
  4. {scim2_client-0.2.1 → scim2_client-0.3.0}/PKG-INFO +11 -8
  5. {scim2_client-0.2.1 → scim2_client-0.3.0}/README.md +6 -5
  6. {scim2_client-0.2.1 → scim2_client-0.3.0}/doc/changelog.rst +30 -2
  7. {scim2_client-0.2.1 → scim2_client-0.3.0}/doc/conf.py +1 -1
  8. scim2_client-0.3.0/doc/reference.rst +14 -0
  9. {scim2_client-0.2.1 → scim2_client-0.3.0}/doc/tutorial.rst +27 -11
  10. {scim2_client-0.2.1 → scim2_client-0.3.0}/pyproject.toml +26 -4
  11. {scim2_client-0.2.1 → scim2_client-0.3.0}/scim2_client/__init__.py +4 -2
  12. scim2_client-0.3.0/scim2_client/client.py +995 -0
  13. scim2_client-0.3.0/scim2_client/engines/httpx.py +430 -0
  14. scim2_client-0.3.0/scim2_client/engines/werkzeug.py +245 -0
  15. {scim2_client-0.2.1 → scim2_client-0.3.0}/scim2_client/errors.py +8 -5
  16. scim2_client-0.3.0/scim2_client/py.typed +0 -0
  17. scim2_client-0.3.0/tests/__init__.py +0 -0
  18. scim2_client-0.3.0/tests/engines/__init__.py +0 -0
  19. scim2_client-0.3.0/tests/engines/test_httpx.py +111 -0
  20. scim2_client-0.3.0/tests/engines/test_werkzeug.py +63 -0
  21. {scim2_client-0.2.1 → scim2_client-0.3.0}/tests/test_create.py +16 -16
  22. {scim2_client-0.2.1 → scim2_client-0.3.0}/tests/test_delete.py +8 -8
  23. {scim2_client-0.2.1 → scim2_client-0.3.0}/tests/test_query.py +44 -44
  24. {scim2_client-0.2.1 → scim2_client-0.3.0}/tests/test_replace.py +13 -13
  25. {scim2_client-0.2.1 → scim2_client-0.3.0}/tests/test_search.py +12 -12
  26. {scim2_client-0.2.1 → scim2_client-0.3.0}/tests/test_utils.py +2 -2
  27. {scim2_client-0.2.1 → scim2_client-0.3.0}/uv.lock +387 -208
  28. scim2_client-0.2.1/doc/reference.rst +0 -6
  29. scim2_client-0.2.1/scim2_client/client.py +0 -685
  30. {scim2_client-0.2.1 → scim2_client-0.3.0}/.github/FUNDING.yml +0 -0
  31. {scim2_client-0.2.1 → scim2_client-0.3.0}/.gitignore +0 -0
  32. {scim2_client-0.2.1 → scim2_client-0.3.0}/.readthedocs.yml +0 -0
  33. {scim2_client-0.2.1 → scim2_client-0.3.0}/LICENSE.md +0 -0
  34. {scim2_client-0.2.1 → scim2_client-0.3.0}/doc/__init__.py +0 -0
  35. {scim2_client-0.2.1 → scim2_client-0.3.0}/doc/contributing.rst +0 -0
  36. {scim2_client-0.2.1 → scim2_client-0.3.0}/doc/index.rst +0 -0
  37. {scim2_client-0.2.1/tests → scim2_client-0.3.0/scim2_client/engines}/__init__.py +0 -0
@@ -37,7 +37,7 @@ jobs:
37
37
 
38
38
  environment:
39
39
  name: pypi-release
40
- url: https://pypi.org/project/scim2-models/
40
+ url: https://pypi.org/project/scim2-client/
41
41
  permissions:
42
42
  id-token: write
43
43
 
@@ -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]
@@ -15,6 +15,11 @@ repos:
15
15
  - id: end-of-file-fixer
16
16
  exclude: "\\.svg$|\\.map$|\\.min\\.css$|\\.min\\.js$|\\.po$|\\.pot$"
17
17
  - id: check-toml
18
+ - repo: https://github.com/pre-commit/mirrors-mypy
19
+ rev: v1.13.0
20
+ hooks:
21
+ - id: mypy
22
+ additional_dependencies: [pydantic]
18
23
  - repo: https://github.com/codespell-project/codespell
19
24
  rev: v2.3.0
20
25
  hooks:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: scim2-client
3
- Version: 0.2.1
3
+ Version: 0.3.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
@@ -208,7 +208,6 @@ License: Apache License
208
208
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
209
209
  See the License for the specific language governing permissions and
210
210
  limitations under the License.
211
- License-File: LICENSE.md
212
211
  Keywords: api,httpx,provisioning,rfc7643,rfc7644,scim,scim2
213
212
  Classifier: Development Status :: 3 - Alpha
214
213
  Classifier: Environment :: Web Environment
@@ -223,15 +222,19 @@ Classifier: Programming Language :: Python :: 3.12
223
222
  Classifier: Programming Language :: Python :: 3.13
224
223
  Classifier: Programming Language :: Python :: Implementation :: CPython
225
224
  Requires-Python: >=3.9
226
- Requires-Dist: httpx>=0.24.0
227
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'
228
230
  Description-Content-Type: text/markdown
229
231
 
230
232
  # scim2-client
231
233
 
232
- 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) ,
233
235
  that pythonically build requests and parse responses,
234
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.
235
238
 
236
239
  It aims to be used in SCIM client applications, or in unit tests for SCIM server applications.
237
240
 
@@ -245,7 +248,7 @@ It allows users and groups creations, modifications and deletions to be synchron
245
248
  ## Installation
246
249
 
247
250
  ```shell
248
- pip install scim2-client
251
+ pip install scim2-client[httpx]
249
252
  ```
250
253
 
251
254
  ## Usage
@@ -258,10 +261,10 @@ Here is an example of usage:
258
261
  import datetime
259
262
  from httpx import Client
260
263
  from scim2_models import User, EnterpriseUser, Group, Error
261
- from scim2_client import SCIMClient
264
+ from scim2_client.engines.httpx import SyncSCIMClient
262
265
 
263
- client = Client(base_url=f"https://auth.example/scim/v2", headers={"Authorization": "Bearer foobar"})
264
- 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))
265
268
 
266
269
  # Query resources
267
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,8 +1,36 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ [0.3.0] - 2024-11-29
5
+ --------------------
6
+
7
+ .. warning::
8
+
9
+ This version comes with breaking changes:
10
+
11
+ - `httpx` is no longer a direct dependency, it is shipped in the `httpx` packaging extra.
12
+ - ``scim2_client.SCIMClient`` has moved to ``scim2_client.engines.httpx.SyncSCIMClient``.
13
+ - The ``resource_types`` parameters has been renamed ``resource_models``.
14
+
15
+ Added
16
+ ^^^^^
17
+ - The `Unknown resource type` request error keeps a reference to the faulty payload.
18
+ - New `werkzeug` request engine for application development purpose.
19
+ - New `AsyncSCIMClient` request engine. :issue:`1`
20
+
21
+ Changed
22
+ ^^^^^^^
23
+ - Separate httpx network code and SCIM code in separate file as a basis for async support (and maybe other request engines).
24
+
25
+ [0.2.2] - 2024-11-12
26
+ --------------------
27
+
28
+ Added
29
+ ^^^^^
30
+ - Mypy type checking and py.typed file :pr:`25`
31
+
4
32
  [0.2.1] - 2024-11-07
5
- ---------------------
33
+ --------------------
6
34
 
7
35
  Added
8
36
  ^^^^^
@@ -14,7 +42,7 @@ Fixed
14
42
  - Don't crash when servers don't return content type headers. :pr:`22,24`
15
43
 
16
44
  [0.2.0] - 2024-09-01
17
- ---------------------
45
+ --------------------
18
46
 
19
47
  Added
20
48
  ^^^^^
@@ -35,7 +35,6 @@ source_suffix = {
35
35
 
36
36
  version = metadata.version("scim2_client")
37
37
  language = "en"
38
- exclude_patterns = []
39
38
  pygments_style = "sphinx"
40
39
  todo_include_todos = True
41
40
  toctree_collapse = False
@@ -43,6 +42,7 @@ toctree_collapse = False
43
42
  intersphinx_mapping = {
44
43
  "python": ("https://docs.python.org/3", None),
45
44
  "scim2_models": ("https://scim2-models.readthedocs.io/en/latest/", None),
45
+ "werkzeug": ("https://werkzeug.palletsprojects.com", None),
46
46
  }
47
47
 
48
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.1"
7
+ version = "0.3.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"}
@@ -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,13 +47,17 @@ 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",
59
+ "werkzeug>=3.1.3",
47
60
  ]
48
-
49
61
  doc = [
50
62
  "autodoc-pydantic>=2.2.0",
51
63
  "myst-parser>=3.0.1",
@@ -100,6 +112,15 @@ force-single-line = true
100
112
  [tool.ruff.format]
101
113
  docstring-code-format = true
102
114
 
115
+ [tool.mypy]
116
+ plugins = [
117
+ "pydantic.mypy"
118
+ ]
119
+
120
+ [tool.pytest.ini_options]
121
+ asyncio_mode="auto"
122
+ asyncio_default_fixture_loop_scope = "function"
123
+
103
124
  [tool.tox]
104
125
  requires = ["tox>=4.19"]
105
126
  env_list = [
@@ -115,6 +136,7 @@ env_list = [
115
136
  ]
116
137
 
117
138
  [tool.tox.env_run_base]
139
+ extras = ["httpx", "werkzeug"]
118
140
  runner = "uv-venv-lock-runner"
119
141
  dependency_groups = ["dev"]
120
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",