glpi-python-client 0.3.4__py3-none-any.whl → 0.4.2__py3-none-any.whl
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/__init__.py +56 -6
- glpi_python_client/_async/__init__.py +15 -0
- glpi_python_client/_async/_concurrency.py +59 -0
- glpi_python_client/_async/_testing.py +146 -0
- glpi_python_client/{auth → _async/auth}/__init__.py +3 -3
- glpi_python_client/_async/auth/_v1_session.py +466 -0
- glpi_python_client/_async/auth/auth.py +417 -0
- glpi_python_client/_async/clients/__init__.py +17 -0
- glpi_python_client/{clients → _async/clients}/_base_client.py +12 -13
- glpi_python_client/_async/clients/api/__init__.py +54 -0
- glpi_python_client/_async/clients/api/administration/__init__.py +13 -0
- glpi_python_client/_async/clients/api/administration/_entity.py +217 -0
- glpi_python_client/_async/clients/api/administration/_user.py +224 -0
- glpi_python_client/_async/clients/api/assistance/__init__.py +8 -0
- glpi_python_client/_async/clients/api/assistance/_team.py +121 -0
- glpi_python_client/_async/clients/api/assistance/_ticket.py +238 -0
- glpi_python_client/_async/clients/api/assistance/timeline/__init__.py +23 -0
- glpi_python_client/_async/clients/api/assistance/timeline/_document.py +225 -0
- glpi_python_client/_async/clients/api/assistance/timeline/_followup.py +204 -0
- glpi_python_client/_async/clients/api/assistance/timeline/_solution.py +201 -0
- glpi_python_client/_async/clients/api/assistance/timeline/_task.py +194 -0
- glpi_python_client/_async/clients/api/dropdowns/__init__.py +7 -0
- glpi_python_client/_async/clients/api/dropdowns/_location.py +170 -0
- glpi_python_client/_async/clients/api/knowledgebase/__init__.py +21 -0
- glpi_python_client/_async/clients/api/knowledgebase/_article.py +214 -0
- glpi_python_client/_async/clients/api/knowledgebase/_category.py +120 -0
- glpi_python_client/_async/clients/api/knowledgebase/_comment.py +109 -0
- glpi_python_client/_async/clients/api/knowledgebase/_revision.py +70 -0
- glpi_python_client/_async/clients/api/management/__init__.py +7 -0
- glpi_python_client/_async/clients/api/management/_document.py +280 -0
- glpi_python_client/_async/clients/api/plugins/__init__.py +10 -0
- glpi_python_client/_async/clients/api/plugins/_fields.py +426 -0
- glpi_python_client/_async/clients/client.py +135 -0
- glpi_python_client/_async/clients/commons/__init__.py +9 -0
- glpi_python_client/_async/clients/commons/_config.py +317 -0
- glpi_python_client/{clients → _async/clients}/commons/_constants.py +10 -0
- glpi_python_client/{clients → _async/clients}/commons/_filters.py +12 -1
- glpi_python_client/_async/clients/commons/_http.py +394 -0
- glpi_python_client/_async/clients/commons/_transport.py +573 -0
- glpi_python_client/_async/clients/custom/__init__.py +23 -0
- glpi_python_client/_async/clients/custom/_statistics.py +973 -0
- glpi_python_client/_async/clients/custom/_ticket_context.py +75 -0
- glpi_python_client/_errors.py +176 -0
- glpi_python_client/_sync/__init__.py +15 -0
- glpi_python_client/_sync/_concurrency.py +41 -0
- glpi_python_client/_sync/_testing.py +146 -0
- glpi_python_client/_sync/auth/__init__.py +13 -0
- glpi_python_client/{auth → _sync/auth}/_v1_session.py +86 -35
- glpi_python_client/{auth → _sync/auth}/auth.py +162 -55
- glpi_python_client/_sync/clients/__init__.py +17 -0
- glpi_python_client/_sync/clients/_base_client.py +177 -0
- glpi_python_client/_sync/clients/api/__init__.py +54 -0
- glpi_python_client/_sync/clients/api/administration/__init__.py +13 -0
- glpi_python_client/{clients → _sync/clients}/api/administration/_entity.py +14 -11
- glpi_python_client/{clients → _sync/clients}/api/administration/_user.py +12 -11
- glpi_python_client/_sync/clients/api/assistance/__init__.py +8 -0
- glpi_python_client/{clients → _sync/clients}/api/assistance/_team.py +12 -10
- glpi_python_client/{clients → _sync/clients}/api/assistance/_ticket.py +14 -11
- glpi_python_client/_sync/clients/api/assistance/timeline/__init__.py +23 -0
- glpi_python_client/{clients → _sync/clients}/api/assistance/timeline/_document.py +14 -11
- glpi_python_client/{clients → _sync/clients}/api/assistance/timeline/_followup.py +15 -12
- glpi_python_client/{clients → _sync/clients}/api/assistance/timeline/_solution.py +15 -12
- glpi_python_client/{clients → _sync/clients}/api/assistance/timeline/_task.py +15 -12
- glpi_python_client/_sync/clients/api/dropdowns/__init__.py +7 -0
- glpi_python_client/{clients → _sync/clients}/api/dropdowns/_location.py +17 -11
- glpi_python_client/_sync/clients/api/knowledgebase/__init__.py +21 -0
- glpi_python_client/_sync/clients/api/knowledgebase/_article.py +214 -0
- glpi_python_client/_sync/clients/api/knowledgebase/_category.py +120 -0
- glpi_python_client/_sync/clients/api/knowledgebase/_comment.py +109 -0
- glpi_python_client/_sync/clients/api/knowledgebase/_revision.py +70 -0
- glpi_python_client/_sync/clients/api/management/__init__.py +7 -0
- glpi_python_client/{clients → _sync/clients}/api/management/_document.py +22 -19
- glpi_python_client/{clients → _sync/clients}/api/plugins/__init__.py +2 -2
- glpi_python_client/{clients → _sync/clients}/api/plugins/_fields.py +35 -20
- glpi_python_client/{clients/sync_client.py → _sync/clients/client.py} +33 -27
- glpi_python_client/_sync/clients/commons/__init__.py +9 -0
- glpi_python_client/{clients → _sync/clients}/commons/_config.py +129 -46
- glpi_python_client/_sync/clients/commons/_constants.py +60 -0
- glpi_python_client/_sync/clients/commons/_filters.py +105 -0
- glpi_python_client/{clients → _sync/clients}/commons/_http.py +165 -25
- glpi_python_client/_sync/clients/commons/_payloads.py +42 -0
- glpi_python_client/{clients → _sync/clients}/commons/_transport.py +103 -81
- glpi_python_client/_sync/clients/custom/__init__.py +23 -0
- glpi_python_client/{clients → _sync/clients}/custom/_statistics.py +340 -46
- glpi_python_client/_sync/clients/custom/_ticket_context.py +75 -0
- glpi_python_client/models/__init__.py +28 -0
- glpi_python_client/models/api_schema/_content.py +1 -1
- glpi_python_client/models/api_schema/enums.py +18 -1
- glpi_python_client/models/api_schema/knowledgebase/__init__.py +45 -0
- glpi_python_client/models/api_schema/knowledgebase/_article.py +123 -0
- glpi_python_client/models/api_schema/knowledgebase/_category.py +78 -0
- glpi_python_client/models/api_schema/knowledgebase/_comment.py +77 -0
- glpi_python_client/models/api_schema/knowledgebase/_revision.py +35 -0
- glpi_python_client/models/api_schema/plugins/_fields.py +2 -2
- glpi_python_client/testing/__init__.py +2 -0
- glpi_python_client/testing/fixtures.py +9 -0
- glpi_python_client/testing/utils.py +17 -5
- {glpi_python_client-0.3.4.dist-info → glpi_python_client-0.4.2.dist-info}/METADATA +24 -17
- glpi_python_client-0.4.2.dist-info/RECORD +126 -0
- {glpi_python_client-0.3.4.dist-info → glpi_python_client-0.4.2.dist-info}/WHEEL +1 -1
- glpi_python_client/auth/tests/test_auth.py +0 -189
- glpi_python_client/auth/tests/test_v1_session.py +0 -446
- glpi_python_client/clients/__init__.py +0 -20
- glpi_python_client/clients/api/__init__.py +0 -42
- glpi_python_client/clients/api/administration/__init__.py +0 -13
- glpi_python_client/clients/api/assistance/__init__.py +0 -8
- glpi_python_client/clients/api/assistance/timeline/__init__.py +0 -23
- glpi_python_client/clients/api/dropdowns/__init__.py +0 -7
- glpi_python_client/clients/api/management/__init__.py +0 -7
- glpi_python_client/clients/api/plugins/tests/__init__.py +0 -0
- glpi_python_client/clients/api/plugins/tests/test_fields_mixin.py +0 -377
- glpi_python_client/clients/async_client.py +0 -167
- glpi_python_client/clients/commons/__init__.py +0 -9
- glpi_python_client/clients/commons/_async_bridge.py +0 -191
- glpi_python_client/clients/commons/_errors.py +0 -27
- glpi_python_client/clients/commons/tests/__init__.py +0 -5
- glpi_python_client/clients/commons/tests/test_errors.py +0 -41
- glpi_python_client/clients/commons/tests/test_filters.py +0 -49
- glpi_python_client/clients/commons/tests/test_http.py +0 -131
- glpi_python_client/clients/commons/tests/test_payloads.py +0 -64
- glpi_python_client/clients/commons/tests/test_transport.py +0 -136
- glpi_python_client/clients/custom/__init__.py +0 -34
- glpi_python_client/clients/custom/_pagination_async.py +0 -164
- glpi_python_client/clients/custom/_statistics_async.py +0 -500
- glpi_python_client/clients/custom/_ticket_context.py +0 -67
- glpi_python_client/clients/custom/_ticket_context_async.py +0 -73
- glpi_python_client/clients/custom/tests/test_statistics.py +0 -562
- glpi_python_client/clients/custom/tests/test_statistics_async.py +0 -232
- glpi_python_client/clients/custom/tests/test_ticket_context.py +0 -57
- glpi_python_client/clients/tests/__init__.py +0 -1
- glpi_python_client/clients/tests/test_api_coverage.py +0 -882
- glpi_python_client/clients/tests/test_async_branches.py +0 -701
- glpi_python_client/clients/tests/test_async_smoke.py +0 -150
- glpi_python_client/clients/tests/test_glpi_client.py +0 -266
- glpi_python_client/clients/tests/test_parity.py +0 -70
- glpi_python_client/clients/tests/test_smoke.py +0 -259
- glpi_python_client/content/tests/__init__.py +0 -5
- glpi_python_client/content/tests/test_conversion.py +0 -13
- glpi_python_client/models/api_schema/administration/tests/__init__.py +0 -1
- glpi_python_client/models/api_schema/administration/tests/test_administration_schemas.py +0 -145
- glpi_python_client/models/api_schema/assistance/tests/__init__.py +0 -1
- glpi_python_client/models/api_schema/assistance/tests/test_assistance_schemas.py +0 -108
- glpi_python_client/models/api_schema/assistance/tests/test_content_roundtrip.py +0 -102
- glpi_python_client/models/api_schema/assistance/timeline/tests/__init__.py +0 -1
- glpi_python_client/models/api_schema/assistance/timeline/tests/test_timeline_schemas.py +0 -147
- glpi_python_client/models/api_schema/dropdowns/tests/__init__.py +0 -1
- glpi_python_client/models/api_schema/dropdowns/tests/test_dropdowns_schemas.py +0 -61
- glpi_python_client/models/api_schema/management/tests/__init__.py +0 -1
- glpi_python_client/models/api_schema/management/tests/test_management_schemas.py +0 -50
- glpi_python_client/models/api_schema/plugins/tests/__init__.py +0 -0
- glpi_python_client/models/api_schema/plugins/tests/test_fields_schemas.py +0 -82
- glpi_python_client/models/custom_schema/tests/__init__.py +0 -1
- glpi_python_client/models/custom_schema/tests/test_ticket_context.py +0 -398
- glpi_python_client-0.3.4.dist-info/RECORD +0 -113
- /glpi_python_client/{clients → _async/clients}/commons/_payloads.py +0 -0
- {glpi_python_client-0.3.4.dist-info → glpi_python_client-0.4.2.dist-info}/licenses/LICENSE +0 -0
glpi_python_client/__init__.py
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
The package re-exports two client classes:
|
|
4
4
|
|
|
5
|
-
* :class:`GlpiClient` — synchronous, blocking client
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
* :class:`GlpiClient` — synchronous, blocking client.
|
|
6
|
+
* :class:`AsyncGlpiClient` — asynchronous client doing real
|
|
7
|
+
non-blocking I/O on the event loop.
|
|
8
|
+
|
|
9
|
+
They expose identical endpoint surfaces because they are the same
|
|
10
|
+
code: the async tree is hand-written and the sync one is generated
|
|
11
|
+
from it. Neither is a wrapper around the other.
|
|
9
12
|
|
|
10
13
|
The ``api_schema`` and ``custom_schema`` Pydantic models are also
|
|
11
14
|
re-exported so downstream users can import them from a single stable
|
|
@@ -14,11 +17,26 @@ package root.
|
|
|
14
17
|
|
|
15
18
|
from __future__ import annotations
|
|
16
19
|
|
|
17
|
-
from glpi_python_client.clients import AsyncGlpiClient
|
|
20
|
+
from glpi_python_client._async.clients import AsyncGlpiClient
|
|
21
|
+
from glpi_python_client._errors import (
|
|
22
|
+
GlpiAuthError,
|
|
23
|
+
GlpiError,
|
|
24
|
+
GlpiNotFoundError,
|
|
25
|
+
GlpiProtocolError,
|
|
26
|
+
GlpiServerError,
|
|
27
|
+
GlpiStatusError,
|
|
28
|
+
GlpiTimeoutError,
|
|
29
|
+
GlpiTransportError,
|
|
30
|
+
GlpiValidationError,
|
|
31
|
+
)
|
|
32
|
+
from glpi_python_client._sync.clients import GlpiClient
|
|
18
33
|
from glpi_python_client.models import (
|
|
19
34
|
DeleteDocument,
|
|
20
35
|
DeleteEntity,
|
|
21
36
|
DeleteFollowup,
|
|
37
|
+
DeleteKBArticle,
|
|
38
|
+
DeleteKBArticleComment,
|
|
39
|
+
DeleteKBCategory,
|
|
22
40
|
DeleteLocation,
|
|
23
41
|
DeleteSolution,
|
|
24
42
|
DeleteTeamMember,
|
|
@@ -29,6 +47,10 @@ from glpi_python_client.models import (
|
|
|
29
47
|
GetDocument,
|
|
30
48
|
GetEntity,
|
|
31
49
|
GetFollowup,
|
|
50
|
+
GetKBArticle,
|
|
51
|
+
GetKBArticleComment,
|
|
52
|
+
GetKBArticleRevision,
|
|
53
|
+
GetKBCategory,
|
|
32
54
|
GetLocation,
|
|
33
55
|
GetPluginFieldsContainer,
|
|
34
56
|
GetPluginFieldsField,
|
|
@@ -55,6 +77,9 @@ from glpi_python_client.models import (
|
|
|
55
77
|
PatchDocument,
|
|
56
78
|
PatchEntity,
|
|
57
79
|
PatchFollowup,
|
|
80
|
+
PatchKBArticle,
|
|
81
|
+
PatchKBArticleComment,
|
|
82
|
+
PatchKBCategory,
|
|
58
83
|
PatchLocation,
|
|
59
84
|
PatchSolution,
|
|
60
85
|
PatchTeamMember,
|
|
@@ -65,6 +90,9 @@ from glpi_python_client.models import (
|
|
|
65
90
|
PostDocument,
|
|
66
91
|
PostEntity,
|
|
67
92
|
PostFollowup,
|
|
93
|
+
PostKBArticle,
|
|
94
|
+
PostKBArticleComment,
|
|
95
|
+
PostKBCategory,
|
|
68
96
|
PostLocation,
|
|
69
97
|
PostPluginFieldsValueRow,
|
|
70
98
|
PostSolution,
|
|
@@ -76,13 +104,16 @@ from glpi_python_client.models import (
|
|
|
76
104
|
TicketMarkdownOptions,
|
|
77
105
|
)
|
|
78
106
|
|
|
79
|
-
__version__ = "0.
|
|
107
|
+
__version__ = "0.4.2"
|
|
80
108
|
|
|
81
109
|
__all__ = [
|
|
82
110
|
"AsyncGlpiClient",
|
|
83
111
|
"DeleteDocument",
|
|
84
112
|
"DeleteEntity",
|
|
85
113
|
"DeleteFollowup",
|
|
114
|
+
"DeleteKBArticle",
|
|
115
|
+
"DeleteKBArticleComment",
|
|
116
|
+
"DeleteKBCategory",
|
|
86
117
|
"DeleteLocation",
|
|
87
118
|
"DeleteSolution",
|
|
88
119
|
"DeleteTeamMember",
|
|
@@ -93,6 +124,10 @@ __all__ = [
|
|
|
93
124
|
"GetDocument",
|
|
94
125
|
"GetEntity",
|
|
95
126
|
"GetFollowup",
|
|
127
|
+
"GetKBArticle",
|
|
128
|
+
"GetKBArticleComment",
|
|
129
|
+
"GetKBArticleRevision",
|
|
130
|
+
"GetKBCategory",
|
|
96
131
|
"GetLocation",
|
|
97
132
|
"GetPluginFieldsContainer",
|
|
98
133
|
"GetPluginFieldsField",
|
|
@@ -103,23 +138,35 @@ __all__ = [
|
|
|
103
138
|
"GetTicketTask",
|
|
104
139
|
"GetTimelineDocument",
|
|
105
140
|
"GetUser",
|
|
141
|
+
"GlpiAuthError",
|
|
106
142
|
"GlpiClient",
|
|
107
143
|
"GlpiEnum",
|
|
144
|
+
"GlpiError",
|
|
108
145
|
"GlpiGlobalValidation",
|
|
146
|
+
"GlpiNotFoundError",
|
|
109
147
|
"GlpiPriority",
|
|
148
|
+
"GlpiProtocolError",
|
|
149
|
+
"GlpiServerError",
|
|
110
150
|
"GlpiSolutionStatus",
|
|
151
|
+
"GlpiStatusError",
|
|
111
152
|
"GlpiTaskState",
|
|
112
153
|
"GlpiTicketContext",
|
|
113
154
|
"GlpiTicketStatus",
|
|
114
155
|
"GlpiTicketType",
|
|
115
156
|
"GlpiTimelinePosition",
|
|
157
|
+
"GlpiTimeoutError",
|
|
158
|
+
"GlpiTransportError",
|
|
116
159
|
"GlpiUserAuthType",
|
|
160
|
+
"GlpiValidationError",
|
|
117
161
|
"IdNameCompletenameRef",
|
|
118
162
|
"IdNameRef",
|
|
119
163
|
"IdRef",
|
|
120
164
|
"PatchDocument",
|
|
121
165
|
"PatchEntity",
|
|
122
166
|
"PatchFollowup",
|
|
167
|
+
"PatchKBArticle",
|
|
168
|
+
"PatchKBArticleComment",
|
|
169
|
+
"PatchKBCategory",
|
|
123
170
|
"PatchLocation",
|
|
124
171
|
"PatchSolution",
|
|
125
172
|
"PatchTeamMember",
|
|
@@ -130,6 +177,9 @@ __all__ = [
|
|
|
130
177
|
"PostDocument",
|
|
131
178
|
"PostEntity",
|
|
132
179
|
"PostFollowup",
|
|
180
|
+
"PostKBArticle",
|
|
181
|
+
"PostKBArticleComment",
|
|
182
|
+
"PostKBCategory",
|
|
133
183
|
"PostLocation",
|
|
134
184
|
"PostPluginFieldsValueRow",
|
|
135
185
|
"PostSolution",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Hand-written client tree.
|
|
2
|
+
|
|
3
|
+
This package is the single source of truth for client code. Its sibling
|
|
4
|
+
``glpi_python_client._sync`` is generated from it by ``unasync_build.py``
|
|
5
|
+
and checked in; CI regenerates and diffs to keep the two from drifting.
|
|
6
|
+
|
|
7
|
+
Prose written here is copied verbatim into the generated tree -- the
|
|
8
|
+
codegen rewrites tokens, not sentences. Docstrings under this package are
|
|
9
|
+
therefore worded so they read correctly on both surfaces: describe *what* a
|
|
10
|
+
helper does, and leave whether it blocks or awaits to the signature.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
__all__: list[str] = []
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Asyncio concurrency primitives for the async client tree.
|
|
2
|
+
|
|
3
|
+
This module and its ``_sync`` twin are the only files maintained by hand on
|
|
4
|
+
both sides of the codegen. Everything else under ``_sync/`` is generated
|
|
5
|
+
from ``_async/`` by :mod:`unasync`, which rewrites tokens and strips
|
|
6
|
+
``async``/``await``. That works for syntax; it cannot work here, because the
|
|
7
|
+
two surfaces need genuinely *different primitives*, not differently-spelled
|
|
8
|
+
ones:
|
|
9
|
+
|
|
10
|
+
* A fan-out is :func:`asyncio.gather` on this side and plain sequential
|
|
11
|
+
evaluation on the other. ``unasync`` leaves ``asyncio.gather`` untouched,
|
|
12
|
+
so a generated twin would call it from synchronous code and break.
|
|
13
|
+
* The auth lock must be an :class:`asyncio.Lock` here and a
|
|
14
|
+
:class:`threading.Lock` there -- see :data:`Lock` for why substituting one
|
|
15
|
+
for the other is wrong in *both* directions.
|
|
16
|
+
|
|
17
|
+
Keeping both twins tiny is deliberate: hand-maintained duplication is a
|
|
18
|
+
liability, so it is confined to the smallest possible surface.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import asyncio
|
|
24
|
+
from typing import Any
|
|
25
|
+
|
|
26
|
+
#: Lock type guarding OAuth token acquisition on the async surface.
|
|
27
|
+
#:
|
|
28
|
+
#: An :class:`asyncio.Lock`, and the ``_sync`` twin uses a
|
|
29
|
+
#: :class:`threading.Lock`. Neither choice is substitutable for the other,
|
|
30
|
+
#: which is exactly why this is hand-written:
|
|
31
|
+
#:
|
|
32
|
+
#: * A :class:`threading.Lock` here would **deadlock**. The lock is held
|
|
33
|
+
#: across an ``await``, so a second task blocking on it blocks the whole
|
|
34
|
+
#: event loop -- and the task holding it can then never resume to release
|
|
35
|
+
#: it. A single-threaded loop has no way out of that.
|
|
36
|
+
#: * An :class:`asyncio.Lock` on the sync side would be worse than useless:
|
|
37
|
+
#: it is bound to the loop that first contends it, so sharing one client
|
|
38
|
+
#: across threads raises ``RuntimeError: ... bound to a different event
|
|
39
|
+
#: loop`` and can deadlock a thread permanently. The failure is latent --
|
|
40
|
+
#: ``acquire()`` only looks up the loop on the *contended* path, so
|
|
41
|
+
#: uncontended use passes and tests stay green.
|
|
42
|
+
Lock = asyncio.Lock
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
async def gather(*awaitables: Any) -> list[Any]:
|
|
46
|
+
"""Run ``awaitables`` concurrently and return their results in order.
|
|
47
|
+
|
|
48
|
+
The ``_sync`` twin takes already-computed values and simply returns
|
|
49
|
+
them. That is not a stub: once ``unasync`` strips the ``await`` from a
|
|
50
|
+
call site, each argument expression evaluates eagerly at the point it is
|
|
51
|
+
written, which *is* sequential execution. So the same call shape --
|
|
52
|
+
``await gather(self.a(), self.b())`` -- means "concurrently" here and
|
|
53
|
+
"one after the other" there, with no change to the calling code.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
return list(await asyncio.gather(*awaitables))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
__all__ = ["Lock", "gather"]
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""In-memory client factory and transport stubs for this tree's unit tests.
|
|
2
|
+
|
|
3
|
+
One of a generated pair: the module is written once and
|
|
4
|
+
``unasync_build.py`` transforms it into its twin in the other tree.
|
|
5
|
+
``AsyncGlpiClient`` is already a substitution key, so each copy returns
|
|
6
|
+
the client of the tree it lands in while the factory stays spelled
|
|
7
|
+
``make_client`` on both sides -- call sites read identically wherever
|
|
8
|
+
they are. The same holds for the two recorder classes: each replaces a
|
|
9
|
+
client's four transport helpers with stubs that capture the call and hand
|
|
10
|
+
back a fixed response, so a mixin test can assert the endpoint, verb and
|
|
11
|
+
serialised body without any HTTP plumbing.
|
|
12
|
+
|
|
13
|
+
It lives beside the tree rather than in ``glpi_python_client.testing``
|
|
14
|
+
because that module is a published downstream helper whose factories must
|
|
15
|
+
keep their current names; this one has to change its return type when the
|
|
16
|
+
tree is transformed.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
from glpi_python_client import AsyncGlpiClient
|
|
24
|
+
from glpi_python_client.testing.utils import DEFAULT_CLIENT_CONFIG, FakeResponse
|
|
25
|
+
|
|
26
|
+
__all__ = ["FailingTransportRecorder", "TransportRecorder", "make_client"]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def make_client(**overrides: object) -> AsyncGlpiClient:
|
|
30
|
+
"""Return a test client with no real HTTP plumbing.
|
|
31
|
+
|
|
32
|
+
Any constructor keyword can be overridden while the rest of the shared
|
|
33
|
+
base configuration is reused.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
config = dict(DEFAULT_CLIENT_CONFIG)
|
|
37
|
+
config.update(overrides)
|
|
38
|
+
return AsyncGlpiClient(**config) # type: ignore[arg-type]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class TransportRecorder:
|
|
42
|
+
"""Capture the four transport calls and answer with fixed responses.
|
|
43
|
+
|
|
44
|
+
Installed over the client's request helpers so a mixin test can assert
|
|
45
|
+
the endpoint, verb and serialised body without any HTTP plumbing.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
*,
|
|
51
|
+
get_payload: Any = None,
|
|
52
|
+
get_status: int = 200,
|
|
53
|
+
get_content: bytes | None = None,
|
|
54
|
+
post_payload: Any = None,
|
|
55
|
+
post_status: int = 201,
|
|
56
|
+
patch_status: int = 204,
|
|
57
|
+
delete_status: int = 204,
|
|
58
|
+
) -> None:
|
|
59
|
+
self.calls: list[dict[str, Any]] = []
|
|
60
|
+
self._get_payload = get_payload if get_payload is not None else []
|
|
61
|
+
self._get_status = get_status
|
|
62
|
+
self._get_content = get_content
|
|
63
|
+
self._post_payload = post_payload if post_payload is not None else {"id": 999}
|
|
64
|
+
self._post_status = post_status
|
|
65
|
+
self._patch_status = patch_status
|
|
66
|
+
self._delete_status = delete_status
|
|
67
|
+
|
|
68
|
+
def install(self, client: AsyncGlpiClient) -> None:
|
|
69
|
+
"""Replace the four transport helpers with capturing stubs."""
|
|
70
|
+
|
|
71
|
+
async def _get(
|
|
72
|
+
endpoint: str,
|
|
73
|
+
params: dict[str, Any] | None = None,
|
|
74
|
+
skip_entity: bool = False,
|
|
75
|
+
) -> FakeResponse:
|
|
76
|
+
self.calls.append(
|
|
77
|
+
{
|
|
78
|
+
"method": "GET",
|
|
79
|
+
"endpoint": endpoint,
|
|
80
|
+
"params": params,
|
|
81
|
+
"skip_entity": skip_entity,
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
return FakeResponse(
|
|
85
|
+
status_code=self._get_status,
|
|
86
|
+
payload=self._get_payload,
|
|
87
|
+
content=self._get_content,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
async def _post(
|
|
91
|
+
endpoint: str,
|
|
92
|
+
json_body: dict[str, Any] | None = None,
|
|
93
|
+
skip_entity: bool = False,
|
|
94
|
+
) -> FakeResponse:
|
|
95
|
+
self.calls.append(
|
|
96
|
+
{
|
|
97
|
+
"method": "POST",
|
|
98
|
+
"endpoint": endpoint,
|
|
99
|
+
"json": json_body,
|
|
100
|
+
"skip_entity": skip_entity,
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
return FakeResponse(
|
|
104
|
+
status_code=self._post_status, payload=self._post_payload
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
async def _patch(
|
|
108
|
+
endpoint: str, json_body: dict[str, Any] | None = None
|
|
109
|
+
) -> FakeResponse:
|
|
110
|
+
self.calls.append(
|
|
111
|
+
{"method": "PATCH", "endpoint": endpoint, "json": json_body}
|
|
112
|
+
)
|
|
113
|
+
return FakeResponse(status_code=self._patch_status, payload={})
|
|
114
|
+
|
|
115
|
+
async def _delete(
|
|
116
|
+
endpoint: str,
|
|
117
|
+
json_body: dict[str, Any] | None = None,
|
|
118
|
+
skip_entity: bool = False,
|
|
119
|
+
) -> FakeResponse:
|
|
120
|
+
self.calls.append(
|
|
121
|
+
{
|
|
122
|
+
"method": "DELETE",
|
|
123
|
+
"endpoint": endpoint,
|
|
124
|
+
"json": json_body,
|
|
125
|
+
"skip_entity": skip_entity,
|
|
126
|
+
}
|
|
127
|
+
)
|
|
128
|
+
return FakeResponse(status_code=self._delete_status, payload={})
|
|
129
|
+
|
|
130
|
+
client._get_request = _get # type: ignore[method-assign, assignment]
|
|
131
|
+
client._post_request = _post # type: ignore[method-assign, assignment]
|
|
132
|
+
client._update_request = _patch # type: ignore[method-assign, assignment]
|
|
133
|
+
client._delete_request = _delete # type: ignore[method-assign, assignment]
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class FailingTransportRecorder(TransportRecorder):
|
|
137
|
+
"""Answer every verb with one fixed non-success status."""
|
|
138
|
+
|
|
139
|
+
def __init__(self, status: int) -> None:
|
|
140
|
+
super().__init__(
|
|
141
|
+
get_status=status,
|
|
142
|
+
get_payload={"err": "x"},
|
|
143
|
+
post_status=status,
|
|
144
|
+
patch_status=status,
|
|
145
|
+
delete_status=status,
|
|
146
|
+
)
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"""Public authentication exports for the GLPI client package.
|
|
2
2
|
|
|
3
3
|
The authentication package owns the OAuth2 token manager used by the
|
|
4
|
-
|
|
4
|
+
GLPI client and the legacy v1 session wrapper used solely by
|
|
5
5
|
the management document upload mixin.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
from glpi_python_client.auth._v1_session import GLPIV1Session
|
|
11
|
-
from glpi_python_client.auth.auth import GLPITokenManager
|
|
10
|
+
from glpi_python_client._async.auth._v1_session import GLPIV1Session
|
|
11
|
+
from glpi_python_client._async.auth.auth import GLPITokenManager
|
|
12
12
|
|
|
13
13
|
__all__ = ["GLPITokenManager", "GLPIV1Session"]
|