glpi-python-client 0.2.0__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.
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/CONTRIBUTING.md +5 -1
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/PKG-INFO +58 -36
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/README.md +57 -35
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/docs/api_reference.rst +20 -2
- glpi_python_client-0.3.0/docs/development.md +109 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/docs/index.rst +1 -0
- glpi_python_client-0.3.0/docs/sponsoring.rst +9 -0
- glpi_python_client-0.3.0/docs/user_guide.rst +1044 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/__init__.py +15 -5
- glpi_python_client-0.3.0/glpi_python_client/clients/__init__.py +20 -0
- glpi_python_client-0.3.0/glpi_python_client/clients/api/__init__.py +40 -0
- glpi_python_client-0.3.0/glpi_python_client/clients/api/administration/__init__.py +13 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/api/administration/_entity.py +15 -17
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/api/administration/_user.py +16 -16
- glpi_python_client-0.3.0/glpi_python_client/clients/api/assistance/__init__.py +8 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/api/assistance/_team.py +11 -13
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/api/assistance/_ticket.py +15 -17
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/api/assistance/timeline/__init__.py +9 -9
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/api/assistance/timeline/_document.py +16 -16
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/api/assistance/timeline/_followup.py +16 -18
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/api/assistance/timeline/_solution.py +16 -18
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/api/assistance/timeline/_task.py +16 -18
- glpi_python_client-0.3.0/glpi_python_client/clients/api/dropdowns/__init__.py +7 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/api/dropdowns/_location.py +15 -17
- glpi_python_client-0.3.0/glpi_python_client/clients/api/management/__init__.py +7 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/api/management/_document.py +25 -28
- glpi_python_client-0.3.0/glpi_python_client/clients/async_client.py +241 -0
- glpi_python_client-0.3.0/glpi_python_client/clients/commons/_async_bridge.py +118 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/_config.py +2 -1
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/_transport.py +89 -61
- glpi_python_client-0.3.0/glpi_python_client/clients/commons/tests/test_transport.py +136 -0
- glpi_python_client-0.3.0/glpi_python_client/clients/custom/__init__.py +32 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/custom/_statistics.py +11 -14
- glpi_python_client-0.3.0/glpi_python_client/clients/custom/_statistics_async.py +69 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/custom/_ticket_context.py +17 -16
- glpi_python_client-0.3.0/glpi_python_client/clients/custom/_ticket_context_async.py +73 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/custom/tests/test_statistics.py +14 -16
- glpi_python_client-0.3.0/glpi_python_client/clients/custom/tests/test_ticket_context.py +57 -0
- glpi_python_client-0.2.0/glpi_python_client/clients/glpi_client.py → glpi_python_client-0.3.0/glpi_python_client/clients/sync_client.py +55 -54
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/tests/test_api_coverage.py +87 -87
- glpi_python_client-0.3.0/glpi_python_client/clients/tests/test_async_branches.py +137 -0
- glpi_python_client-0.3.0/glpi_python_client/clients/tests/test_async_smoke.py +150 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/tests/test_glpi_client.py +14 -14
- glpi_python_client-0.3.0/glpi_python_client/clients/tests/test_parity.py +64 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/tests/test_smoke.py +28 -28
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/__init__.py +5 -1
- glpi_python_client-0.3.0/glpi_python_client/models/api_schema/administration/_entity.py +95 -0
- glpi_python_client-0.3.0/glpi_python_client/models/api_schema/administration/_user.py +357 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/administration/tests/test_administration_schemas.py +31 -0
- glpi_python_client-0.3.0/glpi_python_client/models/api_schema/assistance/_team.py +84 -0
- glpi_python_client-0.3.0/glpi_python_client/models/api_schema/assistance/_ticket.py +345 -0
- glpi_python_client-0.3.0/glpi_python_client/models/api_schema/assistance/timeline/_document.py +102 -0
- glpi_python_client-0.3.0/glpi_python_client/models/api_schema/assistance/timeline/_followup.py +166 -0
- glpi_python_client-0.3.0/glpi_python_client/models/api_schema/assistance/timeline/_solution.py +156 -0
- glpi_python_client-0.3.0/glpi_python_client/models/api_schema/assistance/timeline/_task.py +210 -0
- glpi_python_client-0.3.0/glpi_python_client/models/api_schema/dropdowns/_location.py +193 -0
- glpi_python_client-0.3.0/glpi_python_client/models/api_schema/management/_document.py +130 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/custom_schema/__init__.py +2 -1
- glpi_python_client-0.3.0/glpi_python_client/models/custom_schema/_ticket_context.py +343 -0
- glpi_python_client-0.3.0/glpi_python_client/models/custom_schema/tests/test_ticket_context.py +398 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/testing/fixtures.py +1 -1
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/testing/utils.py +15 -2
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/pyproject.toml +1 -1
- glpi_python_client-0.3.0/skills/glpi-client-setup/SKILL.md +157 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/skills/glpi-document-workflow/SKILL.md +3 -2
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/skills/glpi-reporting-and-context/SKILL.md +3 -2
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/skills/glpi-team-members/SKILL.md +3 -2
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/skills/glpi-ticket-timeline/SKILL.md +3 -2
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/skills/glpi-ticket-workflow/SKILL.md +3 -2
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/skills/glpi-user-location-provisioning/SKILL.md +3 -2
- glpi_python_client-0.2.0/docs/development.md +0 -96
- glpi_python_client-0.2.0/docs/usage.md +0 -381
- glpi_python_client-0.2.0/docs/user_guide.rst +0 -536
- glpi_python_client-0.2.0/glpi_python_client/clients/__init__.py +0 -13
- glpi_python_client-0.2.0/glpi_python_client/clients/api/__init__.py +0 -40
- glpi_python_client-0.2.0/glpi_python_client/clients/api/administration/__init__.py +0 -12
- glpi_python_client-0.2.0/glpi_python_client/clients/api/assistance/__init__.py +0 -8
- glpi_python_client-0.2.0/glpi_python_client/clients/api/dropdowns/__init__.py +0 -7
- glpi_python_client-0.2.0/glpi_python_client/clients/api/management/__init__.py +0 -7
- glpi_python_client-0.2.0/glpi_python_client/clients/custom/__init__.py +0 -15
- glpi_python_client-0.2.0/glpi_python_client/models/api_schema/administration/_entity.py +0 -55
- glpi_python_client-0.2.0/glpi_python_client/models/api_schema/administration/_user.py +0 -132
- glpi_python_client-0.2.0/glpi_python_client/models/api_schema/assistance/_team.py +0 -59
- glpi_python_client-0.2.0/glpi_python_client/models/api_schema/assistance/_ticket.py +0 -156
- glpi_python_client-0.2.0/glpi_python_client/models/api_schema/assistance/timeline/_document.py +0 -60
- glpi_python_client-0.2.0/glpi_python_client/models/api_schema/assistance/timeline/_followup.py +0 -78
- glpi_python_client-0.2.0/glpi_python_client/models/api_schema/assistance/timeline/_solution.py +0 -76
- glpi_python_client-0.2.0/glpi_python_client/models/api_schema/assistance/timeline/_task.py +0 -97
- glpi_python_client-0.2.0/glpi_python_client/models/api_schema/dropdowns/_location.py +0 -86
- glpi_python_client-0.2.0/glpi_python_client/models/api_schema/management/_document.py +0 -67
- glpi_python_client-0.2.0/glpi_python_client/models/custom_schema/_ticket_context.py +0 -53
- glpi_python_client-0.2.0/glpi_python_client/models/custom_schema/tests/test_ticket_context.py +0 -40
- glpi_python_client-0.2.0/skills/glpi-client-setup/SKILL.md +0 -90
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/.gitignore +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/.pre-commit-config.yaml +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/.readthedocs.yaml +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/LICENSE +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/docs/_static/.gitkeep +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/docs/conf.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/docs/development_rtd.rst +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/docs/glpi_api_contract.json +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/docs/installation.rst +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/docs/publishing.md +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/docs/publishing_rtd.rst +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/auth/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/auth/_v1_session.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/auth/auth.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/auth/tests/test_auth.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/auth/tests/test_v1_session.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/_constants.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/_errors.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/_filters.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/_http.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/_payloads.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/tests/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/tests/test_errors.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/tests/test_filters.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/tests/test_http.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/commons/tests/test_payloads.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/clients/tests/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/content/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/content/conversion.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/content/tests/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/content/tests/test_conversion.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/_base.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/_common.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/_content.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/administration/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/administration/tests/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/assistance/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/assistance/tests/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/assistance/tests/test_assistance_schemas.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/assistance/tests/test_content_roundtrip.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/assistance/timeline/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/assistance/timeline/tests/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/assistance/timeline/tests/test_timeline_schemas.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/dropdowns/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/dropdowns/tests/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/dropdowns/tests/test_dropdowns_schemas.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/enums.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/management/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/management/tests/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/api_schema/management/tests/test_management_schemas.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/models/custom_schema/tests/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/py.typed +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/glpi_python_client/testing/__init__.py +0 -0
- {glpi_python_client-0.2.0 → glpi_python_client-0.3.0}/skills/README.md +0 -0
|
@@ -50,7 +50,11 @@ python -m sphinx -W --keep-going -b html docs docs/_build/html
|
|
|
50
50
|
|
|
51
51
|
## Design Guidelines
|
|
52
52
|
|
|
53
|
-
- Keep API calls behind `GlpiClient` methods.
|
|
53
|
+
- Keep API calls behind `GlpiClient` / `AsyncGlpiClient` methods. Add
|
|
54
|
+
new endpoints to a sync endpoint mixin only; `AsyncGlpiClient`
|
|
55
|
+
exposes them as coroutines automatically through `AsyncBridge`. Only
|
|
56
|
+
add a dedicated async override when the method needs concurrent
|
|
57
|
+
fan-out via `asyncio.gather`.
|
|
54
58
|
- Prefer field-validated Pydantic models for request and response payloads.
|
|
55
59
|
- Avoid organization-specific category, entity, or profile defaults in the
|
|
56
60
|
library core.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: glpi-python-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A typed Python client for GLPI ITSM APIs.
|
|
5
5
|
Project-URL: Homepage, https://github.com/baraline/glpi_python_client
|
|
6
6
|
Project-URL: Documentation, https://glpi-python-client.readthedocs.io/en/latest/
|
|
@@ -62,7 +62,7 @@ Description-Content-Type: text/markdown
|
|
|
62
62
|
[](https://github.com/baraline/glpi_python_client)
|
|
63
63
|
[](https://glpi-python-client.readthedocs.io/en/latest/)
|
|
64
64
|
|
|
65
|
-
`glpi-python-client` is a typed Python client for GLPI
|
|
65
|
+
`glpi-python-client` is a typed Python client for the GLPI REST API.
|
|
66
66
|
|
|
67
67
|
The goal is to let GLPI integrations work with domain objects instead of raw
|
|
68
68
|
JSON payloads. The package exposes Pydantic models for tickets, users,
|
|
@@ -70,8 +70,16 @@ followups, documents, locations, and related records, while converting GLPI
|
|
|
70
70
|
HTML content into Markdown for Python-side workflows and rendering Markdown
|
|
71
71
|
back to HTML for outgoing payloads.
|
|
72
72
|
|
|
73
|
-
It currently focuses on ticket-centric workflows and exposes
|
|
74
|
-
|
|
73
|
+
It currently focuses on ticket-centric workflows and exposes two high-level
|
|
74
|
+
clients built on top of the GLPI v2 REST API:
|
|
75
|
+
|
|
76
|
+
- `GlpiClient` — synchronous, blocking client (single source of truth for
|
|
77
|
+
endpoint behaviour).
|
|
78
|
+
- `AsyncGlpiClient` — asynchronous facade that wraps every synchronous
|
|
79
|
+
method into a coroutine and dispatches it to a worker thread.
|
|
80
|
+
|
|
81
|
+
Note that all integration tests using this package are made on GLPI 11.
|
|
82
|
+
I cannot make any guarantee of the behaviour on previous versions.
|
|
75
83
|
|
|
76
84
|
While the package is preparing for 1.0, alot of potential breaking change might happen between versions. A deprecation policy will be put in place once 1.0 is out and the package have been stabilized.
|
|
77
85
|
|
|
@@ -96,14 +104,38 @@ Create a client with your GLPI v2 API URL and at least one complete auth pair:
|
|
|
96
104
|
- `username` and `password`
|
|
97
105
|
- both pairs together
|
|
98
106
|
|
|
107
|
+
### Synchronous client
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from glpi_python_client import GlpiClient, PostTicket
|
|
111
|
+
|
|
112
|
+
with GlpiClient(
|
|
113
|
+
glpi_api_url="https://glpi.example.com/api.php/v2",
|
|
114
|
+
client_id="oauth-client-id",
|
|
115
|
+
client_secret="oauth-client-secret",
|
|
116
|
+
username="api-user",
|
|
117
|
+
password="api-password",
|
|
118
|
+
) as glpi:
|
|
119
|
+
ticket_id = glpi.create_ticket(
|
|
120
|
+
PostTicket(
|
|
121
|
+
name="Printer issue",
|
|
122
|
+
content="The printer is not reachable from the office network.",
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
ticket = glpi.get_ticket(ticket_id)
|
|
126
|
+
print(ticket.id, ticket.name)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Asynchronous client
|
|
130
|
+
|
|
99
131
|
```python
|
|
100
132
|
import asyncio
|
|
101
133
|
|
|
102
|
-
from glpi_python_client import
|
|
134
|
+
from glpi_python_client import AsyncGlpiClient, PostTicket
|
|
103
135
|
|
|
104
136
|
|
|
105
137
|
async def main() -> None:
|
|
106
|
-
async with
|
|
138
|
+
async with AsyncGlpiClient(
|
|
107
139
|
glpi_api_url="https://glpi.example.com/api.php/v2",
|
|
108
140
|
client_id="oauth-client-id",
|
|
109
141
|
client_secret="oauth-client-secret",
|
|
@@ -123,38 +155,22 @@ async def main() -> None:
|
|
|
123
155
|
asyncio.run(main())
|
|
124
156
|
```
|
|
125
157
|
|
|
126
|
-
|
|
127
|
-
|
|
158
|
+
`GlpiClient.from_env()` and `AsyncGlpiClient.from_env()` are also available
|
|
159
|
+
when the credentials are already exposed as `GLPI_`-prefixed environment
|
|
160
|
+
variables.
|
|
128
161
|
|
|
129
|
-
###
|
|
162
|
+
### Sync or async?
|
|
130
163
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
async def _run() -> list[int]:
|
|
142
|
-
async with GlpiClient.from_env() as glpi:
|
|
143
|
-
tickets = await glpi.search_tickets("status==1", limit=10)
|
|
144
|
-
return [ticket.id for ticket in tickets]
|
|
145
|
-
|
|
146
|
-
return asyncio.run(_run())
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if __name__ == "__main__":
|
|
150
|
-
print(fetch_open_tickets())
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
For long-lived sync services that need many calls, run a dedicated
|
|
154
|
-
event loop on a background thread and dispatch with
|
|
155
|
-
`asyncio.run_coroutine_threadsafe`. See the
|
|
156
|
-
[user guide](https://glpi-python-client.readthedocs.io/en/latest/user_guide.html#calling-the-client-from-synchronous-code)
|
|
157
|
-
for the full pattern.
|
|
164
|
+
Both clients expose the exact same endpoint surface and accept the same
|
|
165
|
+
constructor arguments. The async client is a thin facade that wraps each
|
|
166
|
+
synchronous method into a coroutine dispatched to a worker thread via
|
|
167
|
+
`asyncio.to_thread` (or a caller-supplied `concurrent.futures.Executor`).
|
|
168
|
+
A shared `threading.Lock` serialises OAuth token acquisition so concurrent
|
|
169
|
+
`asyncio.gather(...)` fan-outs cannot race. Pick `GlpiClient` for plain
|
|
170
|
+
scripts, CLI tools, and synchronous services; pick `AsyncGlpiClient` when
|
|
171
|
+
your application already runs an event loop or when you need concurrent
|
|
172
|
+
fan-out (the aggregated `get_ticket_context` and per-ticket
|
|
173
|
+
`get_task_statistics` helpers use `asyncio.gather` on the async client).
|
|
158
174
|
|
|
159
175
|
## Documentation
|
|
160
176
|
|
|
@@ -169,3 +185,9 @@ To build the Sphinx documentation locally:
|
|
|
169
185
|
python -m pip install -e .[docs]
|
|
170
186
|
python -m sphinx -b html docs docs/_build/html
|
|
171
187
|
```
|
|
188
|
+
|
|
189
|
+
## Sponsoring & Professional services
|
|
190
|
+
The development of this package is indirectly supported by [Novahé](https://www.novahe.fr/) & [Constellation](https://www.constellation.fr/).
|
|
191
|
+
|
|
192
|
+
If you need professional help or services around GLPI, we offer consulting and engineering services to install, maintain or upgarde GLPI instance, as an [official GLPI partner](https://www.glpi-project.org/fr/new-glpi-silver-partner-in-france-novahe/).
|
|
193
|
+
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](https://github.com/baraline/glpi_python_client)
|
|
7
7
|
[](https://glpi-python-client.readthedocs.io/en/latest/)
|
|
8
8
|
|
|
9
|
-
`glpi-python-client` is a typed Python client for GLPI
|
|
9
|
+
`glpi-python-client` is a typed Python client for the GLPI REST API.
|
|
10
10
|
|
|
11
11
|
The goal is to let GLPI integrations work with domain objects instead of raw
|
|
12
12
|
JSON payloads. The package exposes Pydantic models for tickets, users,
|
|
@@ -14,8 +14,16 @@ followups, documents, locations, and related records, while converting GLPI
|
|
|
14
14
|
HTML content into Markdown for Python-side workflows and rendering Markdown
|
|
15
15
|
back to HTML for outgoing payloads.
|
|
16
16
|
|
|
17
|
-
It currently focuses on ticket-centric workflows and exposes
|
|
18
|
-
|
|
17
|
+
It currently focuses on ticket-centric workflows and exposes two high-level
|
|
18
|
+
clients built on top of the GLPI v2 REST API:
|
|
19
|
+
|
|
20
|
+
- `GlpiClient` — synchronous, blocking client (single source of truth for
|
|
21
|
+
endpoint behaviour).
|
|
22
|
+
- `AsyncGlpiClient` — asynchronous facade that wraps every synchronous
|
|
23
|
+
method into a coroutine and dispatches it to a worker thread.
|
|
24
|
+
|
|
25
|
+
Note that all integration tests using this package are made on GLPI 11.
|
|
26
|
+
I cannot make any guarantee of the behaviour on previous versions.
|
|
19
27
|
|
|
20
28
|
While the package is preparing for 1.0, alot of potential breaking change might happen between versions. A deprecation policy will be put in place once 1.0 is out and the package have been stabilized.
|
|
21
29
|
|
|
@@ -40,14 +48,38 @@ Create a client with your GLPI v2 API URL and at least one complete auth pair:
|
|
|
40
48
|
- `username` and `password`
|
|
41
49
|
- both pairs together
|
|
42
50
|
|
|
51
|
+
### Synchronous client
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from glpi_python_client import GlpiClient, PostTicket
|
|
55
|
+
|
|
56
|
+
with GlpiClient(
|
|
57
|
+
glpi_api_url="https://glpi.example.com/api.php/v2",
|
|
58
|
+
client_id="oauth-client-id",
|
|
59
|
+
client_secret="oauth-client-secret",
|
|
60
|
+
username="api-user",
|
|
61
|
+
password="api-password",
|
|
62
|
+
) as glpi:
|
|
63
|
+
ticket_id = glpi.create_ticket(
|
|
64
|
+
PostTicket(
|
|
65
|
+
name="Printer issue",
|
|
66
|
+
content="The printer is not reachable from the office network.",
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
ticket = glpi.get_ticket(ticket_id)
|
|
70
|
+
print(ticket.id, ticket.name)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Asynchronous client
|
|
74
|
+
|
|
43
75
|
```python
|
|
44
76
|
import asyncio
|
|
45
77
|
|
|
46
|
-
from glpi_python_client import
|
|
78
|
+
from glpi_python_client import AsyncGlpiClient, PostTicket
|
|
47
79
|
|
|
48
80
|
|
|
49
81
|
async def main() -> None:
|
|
50
|
-
async with
|
|
82
|
+
async with AsyncGlpiClient(
|
|
51
83
|
glpi_api_url="https://glpi.example.com/api.php/v2",
|
|
52
84
|
client_id="oauth-client-id",
|
|
53
85
|
client_secret="oauth-client-secret",
|
|
@@ -67,38 +99,22 @@ async def main() -> None:
|
|
|
67
99
|
asyncio.run(main())
|
|
68
100
|
```
|
|
69
101
|
|
|
70
|
-
|
|
71
|
-
|
|
102
|
+
`GlpiClient.from_env()` and `AsyncGlpiClient.from_env()` are also available
|
|
103
|
+
when the credentials are already exposed as `GLPI_`-prefixed environment
|
|
104
|
+
variables.
|
|
72
105
|
|
|
73
|
-
###
|
|
106
|
+
### Sync or async?
|
|
74
107
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
async def _run() -> list[int]:
|
|
86
|
-
async with GlpiClient.from_env() as glpi:
|
|
87
|
-
tickets = await glpi.search_tickets("status==1", limit=10)
|
|
88
|
-
return [ticket.id for ticket in tickets]
|
|
89
|
-
|
|
90
|
-
return asyncio.run(_run())
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if __name__ == "__main__":
|
|
94
|
-
print(fetch_open_tickets())
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
For long-lived sync services that need many calls, run a dedicated
|
|
98
|
-
event loop on a background thread and dispatch with
|
|
99
|
-
`asyncio.run_coroutine_threadsafe`. See the
|
|
100
|
-
[user guide](https://glpi-python-client.readthedocs.io/en/latest/user_guide.html#calling-the-client-from-synchronous-code)
|
|
101
|
-
for the full pattern.
|
|
108
|
+
Both clients expose the exact same endpoint surface and accept the same
|
|
109
|
+
constructor arguments. The async client is a thin facade that wraps each
|
|
110
|
+
synchronous method into a coroutine dispatched to a worker thread via
|
|
111
|
+
`asyncio.to_thread` (or a caller-supplied `concurrent.futures.Executor`).
|
|
112
|
+
A shared `threading.Lock` serialises OAuth token acquisition so concurrent
|
|
113
|
+
`asyncio.gather(...)` fan-outs cannot race. Pick `GlpiClient` for plain
|
|
114
|
+
scripts, CLI tools, and synchronous services; pick `AsyncGlpiClient` when
|
|
115
|
+
your application already runs an event loop or when you need concurrent
|
|
116
|
+
fan-out (the aggregated `get_ticket_context` and per-ticket
|
|
117
|
+
`get_task_statistics` helpers use `asyncio.gather` on the async client).
|
|
102
118
|
|
|
103
119
|
## Documentation
|
|
104
120
|
|
|
@@ -113,3 +129,9 @@ To build the Sphinx documentation locally:
|
|
|
113
129
|
python -m pip install -e .[docs]
|
|
114
130
|
python -m sphinx -b html docs docs/_build/html
|
|
115
131
|
```
|
|
132
|
+
|
|
133
|
+
## Sponsoring & Professional services
|
|
134
|
+
The development of this package is indirectly supported by [Novahé](https://www.novahe.fr/) & [Constellation](https://www.constellation.fr/).
|
|
135
|
+
|
|
136
|
+
If you need professional help or services around GLPI, we offer consulting and engineering services to install, maintain or upgarde GLPI instance, as an [official GLPI partner](https://www.glpi-project.org/fr/new-glpi-silver-partner-in-france-novahe/).
|
|
137
|
+
|
|
@@ -7,14 +7,27 @@ underscore-prefixed helpers are intentionally omitted.
|
|
|
7
7
|
|
|
8
8
|
.. currentmodule:: glpi_python_client
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
Clients
|
|
11
|
+
-------
|
|
12
|
+
|
|
13
|
+
The package exposes two clients with identical endpoint surfaces. The
|
|
14
|
+
synchronous one is the single source of truth for endpoint behaviour;
|
|
15
|
+
the asynchronous one wraps each synchronous method into a coroutine.
|
|
12
16
|
|
|
13
17
|
.. autoclass:: GlpiClient
|
|
14
18
|
:members:
|
|
15
19
|
:inherited-members:
|
|
16
20
|
:show-inheritance:
|
|
17
21
|
|
|
22
|
+
.. autoclass:: AsyncGlpiClient
|
|
23
|
+
:members:
|
|
24
|
+
:inherited-members:
|
|
25
|
+
:show-inheritance:
|
|
26
|
+
|
|
27
|
+
.. autoclass:: glpi_python_client.clients.commons._async_bridge.AsyncBridge
|
|
28
|
+
:members:
|
|
29
|
+
:show-inheritance:
|
|
30
|
+
|
|
18
31
|
Aggregated Models
|
|
19
32
|
-----------------
|
|
20
33
|
|
|
@@ -23,6 +36,11 @@ Aggregated Models
|
|
|
23
36
|
:undoc-members:
|
|
24
37
|
:show-inheritance:
|
|
25
38
|
|
|
39
|
+
.. autoclass:: TicketMarkdownOptions
|
|
40
|
+
:members:
|
|
41
|
+
:undoc-members:
|
|
42
|
+
:show-inheritance:
|
|
43
|
+
|
|
26
44
|
Common Reference Models
|
|
27
45
|
-----------------------
|
|
28
46
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Development Guide
|
|
2
|
+
|
|
3
|
+
## Local Setup
|
|
4
|
+
|
|
5
|
+
Create a virtual environment and install the package with development dependencies:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
python -m venv .venv
|
|
9
|
+
.venv\Scripts\activate
|
|
10
|
+
python -m pip install --upgrade pip
|
|
11
|
+
python -m pip install -e .[dev]
|
|
12
|
+
python -m pre_commit install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The repository ships a root `.pre-commit-config.yaml` that runs Ruff on each
|
|
16
|
+
commit. The lint hook applies safe fixes first, then Ruff formats the touched
|
|
17
|
+
files.
|
|
18
|
+
|
|
19
|
+
## Checks
|
|
20
|
+
|
|
21
|
+
Run these before publishing or opening a pull request:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
python -m pre_commit run --all-files
|
|
25
|
+
python -m pytest
|
|
26
|
+
python -m ruff check .
|
|
27
|
+
python -m mypy glpi_python_client
|
|
28
|
+
python -m sphinx -b html docs docs/_build/html
|
|
29
|
+
python -m build
|
|
30
|
+
python -m vulture glpi_python_client --min-confidence 80
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If your global Python environment has broken pytest plugins, run the suite with
|
|
34
|
+
plugin autoload disabled:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
$env:PYTEST_DISABLE_PLUGIN_AUTOLOAD = "1"
|
|
38
|
+
python -m pytest
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Package Layout
|
|
42
|
+
|
|
43
|
+
- `glpi_python_client.__init__` exposes the public import surface,
|
|
44
|
+
including both client classes and the Pydantic models.
|
|
45
|
+
- `glpi_python_client.clients.sync_client.GlpiClient` is the
|
|
46
|
+
synchronous, blocking client. It is the single source of truth for
|
|
47
|
+
endpoint behaviour: each public method lives on one of the sync
|
|
48
|
+
endpoint mixins under `glpi_python_client.clients.api.*` and
|
|
49
|
+
`glpi_python_client.clients.custom.*`.
|
|
50
|
+
- `glpi_python_client.clients.async_client.AsyncGlpiClient` is the
|
|
51
|
+
asynchronous facade. It inherits the same endpoint mixins and uses
|
|
52
|
+
`glpi_python_client.clients.commons._async_bridge.AsyncBridge` to wrap
|
|
53
|
+
every inherited public sync method into a coroutine dispatched on a
|
|
54
|
+
worker thread (`asyncio.to_thread` by default, or a caller-supplied
|
|
55
|
+
`concurrent.futures.Executor`).
|
|
56
|
+
- `glpi_python_client.clients.commons` holds the reusable building
|
|
57
|
+
blocks shared by every endpoint mixin: configuration helpers
|
|
58
|
+
(`_config`), constants (`_constants`), errors (`_errors`), filters
|
|
59
|
+
(`_filters`), HTTP helpers (`_http`), payload builders (`_payloads`),
|
|
60
|
+
the synchronous `TransportMixin` (`_transport`), and the
|
|
61
|
+
`AsyncBridge` (`_async_bridge`). A shared `threading.Lock` in the
|
|
62
|
+
transport serialises OAuth token acquisition so concurrent
|
|
63
|
+
`asyncio.gather` fan-outs on the async client cannot race.
|
|
64
|
+
- `glpi_python_client.clients.api.*` contains the contract-aligned
|
|
65
|
+
synchronous endpoint mixins, grouped by GLPI subtree (administration,
|
|
66
|
+
assistance, assistance/timeline, dropdowns, management).
|
|
67
|
+
- `glpi_python_client.clients.custom` contains custom helpers built on
|
|
68
|
+
top of the API mixins. Each helper has a synchronous implementation
|
|
69
|
+
(`_ticket_context.py`, `_statistics.py`) plus an optional async
|
|
70
|
+
override (`_ticket_context_async.py`, `_statistics_async.py`) that
|
|
71
|
+
fans the underlying calls out concurrently with `asyncio.gather`.
|
|
72
|
+
- `glpi_python_client.auth._v1_session` contains the legacy v1
|
|
73
|
+
session used for binary document uploads.
|
|
74
|
+
- `glpi_python_client.models` contains typed request and response
|
|
75
|
+
models.
|
|
76
|
+
- `glpi_python_client.content` handles HTML/Markdown conversion for
|
|
77
|
+
ticket descriptions, followups, tasks, and solutions.
|
|
78
|
+
- `glpi_python_client.testing` exposes `make_client` and
|
|
79
|
+
`make_async_client` factories that produce in-memory clients with no
|
|
80
|
+
real HTTP plumbing for downstream test suites.
|
|
81
|
+
- `docs` contains the Read the Docs/Sphinx documentation source.
|
|
82
|
+
- `skills` contains contributor-facing Agent Skills for repository
|
|
83
|
+
workflows. The source distribution includes them for source consumers
|
|
84
|
+
and contributors, but the wheel still installs only the
|
|
85
|
+
`glpi_python_client` runtime package.
|
|
86
|
+
|
|
87
|
+
## Adding Endpoints
|
|
88
|
+
|
|
89
|
+
1. Add or extend a model in `glpi_python_client.models`.
|
|
90
|
+
2. Add the client method on the matching **synchronous** endpoint mixin
|
|
91
|
+
under `glpi_python_client.clients.api.*` (or
|
|
92
|
+
`glpi_python_client.clients.custom.*` for derived helpers). The
|
|
93
|
+
async client picks the new method up automatically through the
|
|
94
|
+
`AsyncBridge` — do not duplicate the method on a parallel async
|
|
95
|
+
mixin unless you genuinely need concurrent fan-out (`asyncio.gather`)
|
|
96
|
+
inside the method body.
|
|
97
|
+
3. Put reusable endpoint names, payload builders, response handling, or
|
|
98
|
+
pagination logic in the focused
|
|
99
|
+
`glpi_python_client.clients.commons` helper module named for that
|
|
100
|
+
responsibility.
|
|
101
|
+
4. Add unit tests for payload serialization, response parsing, and
|
|
102
|
+
client behavior. The parity test in
|
|
103
|
+
`glpi_python_client/clients/tests/test_parity.py` will fail if the
|
|
104
|
+
sync and async surfaces diverge.
|
|
105
|
+
5. Document the new workflow in `docs/user_guide.rst` or the README.
|
|
106
|
+
|
|
107
|
+
Keep organization-specific defaults outside the package core.
|
|
108
|
+
Applications can map their own entities, profiles, and categories
|
|
109
|
+
before calling the client.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Sponsoring & Professional Services
|
|
2
|
+
===================================
|
|
3
|
+
|
|
4
|
+
The development of this package is indirectly supported by
|
|
5
|
+
`Novahé <https://www.novahe.fr/>`_ & `Constellation <https://www.constellation.fr/>`_.
|
|
6
|
+
|
|
7
|
+
If you need professional help or services around GLPI, we offer consulting and
|
|
8
|
+
engineering services to install, maintain, or upgrade GLPI instances, as an
|
|
9
|
+
`official GLPI partner <https://www.glpi-project.org/fr/new-glpi-silver-partner-in-france-novahe/>`_.
|