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
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
A SCIM client Python library built upon [scim2-models](https://scim2-models.readthedocs.io) ,
that pythonically build requests and parse responses,
following the [RFC7643](https://datatracker.ietf.org/doc/html/rfc7643.html) and [RFC7644](https://datatracker.ietf.org/doc/html/rfc7644.html) specifications.
You can use whatever request engine you prefer to perform network requests, but scim2-client comes with [httpx](https://github.com/encode/httpx) support.
You can use whatever request engine you prefer to perform network requests, but scim2-client comes with [httpx2](https://github.com/pydantic/httpx2) support.

It aims to be used in SCIM client applications, or in unit tests for SCIM server applications.

Expand All @@ -21,14 +21,14 @@ It allows users and groups creations, modifications and deletions to be synchron
- **Server Discovery**: Automatic retrieval of `ServiceProviderConfig`, `ResourceTypes` and `Schemas`
- **Search & Filtering**: Support for SCIM filters, sorting, pagination and attribute selection
- **Sync & Async**: Both synchronous and asynchronous clients available
- **Multiple HTTP Engines**: Built-in support for [httpx](https://github.com/encode/httpx) (sync/async) and [werkzeug](https://werkzeug.palletsprojects.com/) (testing). Adaptable to any network engine.
- **Multiple HTTP Engines**: Built-in support for [httpx2](https://github.com/pydantic/httpx2) (sync/async) and [werkzeug](https://werkzeug.palletsprojects.com/) (testing). Adaptable to any network engine.
- **Request & Response Validation**: Automatic payload validation against SCIM schemas
- **Error Handling**: Structured exceptions for network, request and response errors

## Installation

```shell
pip install scim2-client[httpx]
pip install scim2-client[httpx2]
```

## Usage
Expand All @@ -40,9 +40,9 @@ Here is an example of usage:

```python
import datetime
from httpx import Client
from httpx2 import Client
from scim2_client import SCIMResponseErrorObject
from scim2_client.engines.httpx import SyncSCIMClient
from scim2_client.engines.httpx2 import SyncSCIMClient

client = Client(base_url="https://auth.example/scim/v2", headers={"Authorization": "Bearer foobar"})
scim = SyncSCIMClient(client)
Expand Down
18 changes: 18 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
Changelog
=========

[Unreleased]
------------

Added
^^^^^
- The network request engines are built upon `httpx2 <https://github.com/pydantic/httpx2>`_,
which is maintained, and live in ``scim2_client.engines.httpx2``.
They are shipped in the ``httpx2`` packaging extra.
`httpx <https://github.com/encode/httpx>`_ is still used when httpx2 is not installed.

Deprecated
^^^^^^^^^^
- The ``httpx`` packaging extra, in favor of the ``httpx2`` extra. Will be removed in 0.9.
- The ``scim2_client.engines.httpx`` module, in favor of ``scim2_client.engines.httpx2``.
Will be removed in 0.9.
- Passing a :code:`httpx.Client` or a :code:`httpx.AsyncClient` to the request engines,
in favor of their httpx2 counterparts. Will be removed in 0.9.

[0.7.5] - 2026-04-02
--------------------

Expand Down
2 changes: 1 addition & 1 deletion doc/reference.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Reference
=========

.. automodule:: scim2_client.engines.httpx
.. automodule:: scim2_client.engines.httpx2
:members:
:member-order: bysource

Expand Down
27 changes: 17 additions & 10 deletions doc/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@ Tutorial
Initialization
==============

scim2-client depends on request engines such as `httpx <https://github.com/encode/httpx>`_ to perform network requests.
This tutorial demonstrate how to use scim2-client with httpx, and suppose you have installed the `httpx` extra for example with ``pip install scim2-client[httpx]``.
scim2-client depends on request engines such as `httpx2 <https://github.com/pydantic/httpx2>`_ to perform network requests.
This tutorial demonstrate how to use scim2-client with httpx2, and suppose you have installed the `httpx2` extra for example with ``pip install scim2-client[httpx2]``.

As a start you will need to instantiate a httpx :code:`Client` (or :code:`AsyncClient`) object that you can parameter as your will, and then pass it to a :class:`~scim2_client.SCIMClient` object.
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:
.. note::

The engines still work with `httpx <https://github.com/encode/httpx>`_, shipped in the deprecated `httpx` extra.
It is used when httpx2 is not installed, and both its extra and its support will be removed in 0.9.
Applications that cannot migrate all their dependencies at once can call :code:`httpx2.alias_httpx()`
at the very top of their entrypoint, so that :code:`import httpx` resolves to httpx2 process-wide.

As a start you will need to instantiate a httpx2 :code:`Client` (or :code:`AsyncClient`) object that you can parameter as your will, and then pass it to a :class:`~scim2_client.SCIMClient` object.
In addition to your SCIM server root endpoint, you will probably want to provide some authorization headers through the httpx2 :code:`Client` :code:`headers` parameter:

.. tab-set::
:class: outline
Expand All @@ -18,8 +25,8 @@ In addition to your SCIM server root endpoint, you will probably want to provide

.. code-block:: python

from httpx import Client
from scim2_client.engines.httpx import SyncSCIMClient
from httpx2 import Client
from scim2_client.engines.httpx2 import SyncSCIMClient

client = Client(
base_url="https://auth.example/scim/v2",
Expand All @@ -32,8 +39,8 @@ In addition to your SCIM server root endpoint, you will probably want to provide

.. code-block:: python

from httpx import AsyncClient
from scim2_client.engines.httpx import AsyncSCIMClient
from httpx2 import AsyncClient
from scim2_client.engines.httpx2 import AsyncSCIMClient

client = AsyncClient(
base_url="https://auth.example/scim/v2",
Expand Down Expand Up @@ -392,8 +399,8 @@ Engines
scim2-client comes with a light abstraction layers that allows for different requests engines.
Currently those engines are shipped:

- :class:`~scim2_client.engines.httpx.SyncSCIMClient`: A synchronous engine using `httpx <https://github.com/encode/httpx>`_ to perform the HTTP requests.
- :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.
- :class:`~scim2_client.engines.httpx2.SyncSCIMClient`: A synchronous engine using `httpx2 <https://github.com/pydantic/httpx2>`_ to perform the HTTP requests.
- :class:`~scim2_client.engines.httpx2.AsyncSCIMClient`: An asynchronous engine using `httpx2 <https://github.com/pydantic/httpx2>`_ to perform the HTTP requests. It has the very same API than its synchronous version, except it is asynchronous.
- :class:`~scim2_client.engines.werkzeug.TestSCIMClient`: A test engine for development purposes.
It takes a WSGI app and directly execute the server code instead of performing real HTTP requests.
This is faster in unit test suites, and helpful to catch the server exceptions.
Expand Down
14 changes: 12 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ description = "Pythonically build SCIM requests and parse SCIM responses"
authors = [{name="Yaal Coop", email="contact@yaal.coop"}]
license = {file = "LICENSE.md"}
readme = "README.md"
keywords = ["scim", "scim2", "provisioning", "rfc7643", "rfc7644", "httpx", "api"]
keywords = ["scim", "scim2", "provisioning", "rfc7643", "rfc7644", "httpx2", "api"]
classifiers = [
"Intended Audience :: Developers",
"Development Status :: 3 - Alpha",
Expand All @@ -31,6 +31,11 @@ dependencies = [
]

[project.optional-dependencies]
httpx2 = [
"httpx2>=2.12",
]

# Deprecated, will be removed in 0.9.
httpx = [
"httpx>=0.28.0",
]
Expand All @@ -50,6 +55,7 @@ module-root = ""

[dependency-groups]
dev = [
"httpx>=0.28.0",
"mypy>=1.13.0",
"portpicker>=1.6.0",
"prek>=0.1.0",
Expand Down Expand Up @@ -139,13 +145,14 @@ env_list = [
"py312",
"py313",
"py314",
"legacy",
"minversions",
"doc",
"coverage",
]

[tool.tox.env_run_base]
extras = ["httpx", "werkzeug"]
extras = ["httpx2", "werkzeug"]
runner = "uv-venv-lock-runner"
dependency_groups = ["dev"]
commands = [
Expand All @@ -158,6 +165,9 @@ commands = [
["prek", "run", "--all-files", "--show-diff-on-failure"],
]

[tool.tox.env.legacy]
extras = ["httpx", "werkzeug"]

[tool.tox.env.minversions]
runner = "uv-venv-runner"
uv_resolution = "lowest-direct"
Expand Down
Loading
Loading