glpi-python-client 0.3.3__py3-none-any.whl → 0.4.1__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.
Files changed (155) hide show
  1. glpi_python_client/__init__.py +64 -6
  2. glpi_python_client/_async/__init__.py +15 -0
  3. glpi_python_client/_async/_concurrency.py +59 -0
  4. glpi_python_client/_async/_testing.py +146 -0
  5. glpi_python_client/{auth → _async/auth}/__init__.py +3 -3
  6. glpi_python_client/_async/auth/_v1_session.py +466 -0
  7. glpi_python_client/_async/auth/auth.py +417 -0
  8. glpi_python_client/_async/clients/__init__.py +17 -0
  9. glpi_python_client/{clients/sync_client.py → _async/clients/_base_client.py} +25 -111
  10. glpi_python_client/_async/clients/api/__init__.py +54 -0
  11. glpi_python_client/_async/clients/api/administration/__init__.py +13 -0
  12. glpi_python_client/_async/clients/api/administration/_entity.py +217 -0
  13. glpi_python_client/_async/clients/api/administration/_user.py +224 -0
  14. glpi_python_client/_async/clients/api/assistance/__init__.py +8 -0
  15. glpi_python_client/_async/clients/api/assistance/_team.py +121 -0
  16. glpi_python_client/_async/clients/api/assistance/_ticket.py +238 -0
  17. glpi_python_client/_async/clients/api/assistance/timeline/__init__.py +23 -0
  18. glpi_python_client/_async/clients/api/assistance/timeline/_document.py +225 -0
  19. glpi_python_client/_async/clients/api/assistance/timeline/_followup.py +204 -0
  20. glpi_python_client/_async/clients/api/assistance/timeline/_solution.py +201 -0
  21. glpi_python_client/_async/clients/api/assistance/timeline/_task.py +194 -0
  22. glpi_python_client/_async/clients/api/dropdowns/__init__.py +7 -0
  23. glpi_python_client/_async/clients/api/dropdowns/_location.py +170 -0
  24. glpi_python_client/_async/clients/api/knowledgebase/__init__.py +21 -0
  25. glpi_python_client/_async/clients/api/knowledgebase/_article.py +214 -0
  26. glpi_python_client/_async/clients/api/knowledgebase/_category.py +120 -0
  27. glpi_python_client/_async/clients/api/knowledgebase/_comment.py +109 -0
  28. glpi_python_client/_async/clients/api/knowledgebase/_revision.py +70 -0
  29. glpi_python_client/_async/clients/api/management/__init__.py +7 -0
  30. glpi_python_client/_async/clients/api/management/_document.py +280 -0
  31. glpi_python_client/_async/clients/api/plugins/__init__.py +10 -0
  32. glpi_python_client/_async/clients/api/plugins/_fields.py +426 -0
  33. glpi_python_client/_async/clients/client.py +135 -0
  34. glpi_python_client/_async/clients/commons/__init__.py +9 -0
  35. glpi_python_client/_async/clients/commons/_config.py +317 -0
  36. glpi_python_client/{clients → _async/clients}/commons/_constants.py +10 -0
  37. glpi_python_client/{clients → _async/clients}/commons/_filters.py +12 -1
  38. glpi_python_client/_async/clients/commons/_http.py +394 -0
  39. glpi_python_client/_async/clients/commons/_transport.py +573 -0
  40. glpi_python_client/_async/clients/custom/__init__.py +23 -0
  41. glpi_python_client/_async/clients/custom/_statistics.py +973 -0
  42. glpi_python_client/_async/clients/custom/_ticket_context.py +75 -0
  43. glpi_python_client/_errors.py +176 -0
  44. glpi_python_client/_sync/__init__.py +15 -0
  45. glpi_python_client/_sync/_concurrency.py +41 -0
  46. glpi_python_client/_sync/_testing.py +146 -0
  47. glpi_python_client/_sync/auth/__init__.py +13 -0
  48. glpi_python_client/_sync/auth/_v1_session.py +466 -0
  49. glpi_python_client/{auth → _sync/auth}/auth.py +162 -55
  50. glpi_python_client/_sync/clients/__init__.py +17 -0
  51. glpi_python_client/_sync/clients/_base_client.py +177 -0
  52. glpi_python_client/_sync/clients/api/__init__.py +54 -0
  53. glpi_python_client/_sync/clients/api/administration/__init__.py +13 -0
  54. glpi_python_client/{clients → _sync/clients}/api/administration/_entity.py +14 -11
  55. glpi_python_client/{clients → _sync/clients}/api/administration/_user.py +12 -11
  56. glpi_python_client/_sync/clients/api/assistance/__init__.py +8 -0
  57. glpi_python_client/{clients → _sync/clients}/api/assistance/_team.py +12 -10
  58. glpi_python_client/{clients → _sync/clients}/api/assistance/_ticket.py +14 -11
  59. glpi_python_client/_sync/clients/api/assistance/timeline/__init__.py +23 -0
  60. glpi_python_client/{clients → _sync/clients}/api/assistance/timeline/_document.py +14 -11
  61. glpi_python_client/{clients → _sync/clients}/api/assistance/timeline/_followup.py +15 -12
  62. glpi_python_client/{clients → _sync/clients}/api/assistance/timeline/_solution.py +15 -12
  63. glpi_python_client/{clients → _sync/clients}/api/assistance/timeline/_task.py +15 -12
  64. glpi_python_client/_sync/clients/api/dropdowns/__init__.py +7 -0
  65. glpi_python_client/{clients → _sync/clients}/api/dropdowns/_location.py +17 -11
  66. glpi_python_client/_sync/clients/api/knowledgebase/__init__.py +21 -0
  67. glpi_python_client/_sync/clients/api/knowledgebase/_article.py +214 -0
  68. glpi_python_client/_sync/clients/api/knowledgebase/_category.py +120 -0
  69. glpi_python_client/_sync/clients/api/knowledgebase/_comment.py +109 -0
  70. glpi_python_client/_sync/clients/api/knowledgebase/_revision.py +70 -0
  71. glpi_python_client/_sync/clients/api/management/__init__.py +7 -0
  72. glpi_python_client/{clients → _sync/clients}/api/management/_document.py +23 -26
  73. glpi_python_client/_sync/clients/api/plugins/__init__.py +10 -0
  74. glpi_python_client/_sync/clients/api/plugins/_fields.py +426 -0
  75. glpi_python_client/_sync/clients/client.py +135 -0
  76. glpi_python_client/_sync/clients/commons/__init__.py +9 -0
  77. glpi_python_client/{clients → _sync/clients}/commons/_config.py +130 -47
  78. glpi_python_client/_sync/clients/commons/_constants.py +60 -0
  79. glpi_python_client/_sync/clients/commons/_filters.py +105 -0
  80. glpi_python_client/_sync/clients/commons/_http.py +394 -0
  81. glpi_python_client/_sync/clients/commons/_payloads.py +42 -0
  82. glpi_python_client/{clients → _sync/clients}/commons/_transport.py +132 -81
  83. glpi_python_client/_sync/clients/custom/__init__.py +23 -0
  84. glpi_python_client/{clients → _sync/clients}/custom/_statistics.py +340 -46
  85. glpi_python_client/_sync/clients/custom/_ticket_context.py +75 -0
  86. glpi_python_client/models/__init__.py +38 -0
  87. glpi_python_client/models/api_schema/_content.py +1 -1
  88. glpi_python_client/models/api_schema/enums.py +18 -1
  89. glpi_python_client/models/api_schema/knowledgebase/__init__.py +45 -0
  90. glpi_python_client/models/api_schema/knowledgebase/_article.py +123 -0
  91. glpi_python_client/models/api_schema/knowledgebase/_category.py +78 -0
  92. glpi_python_client/models/api_schema/knowledgebase/_comment.py +77 -0
  93. glpi_python_client/models/api_schema/knowledgebase/_revision.py +35 -0
  94. glpi_python_client/models/api_schema/plugins/__init__.py +19 -0
  95. glpi_python_client/models/api_schema/plugins/_fields.py +177 -0
  96. glpi_python_client/testing/__init__.py +2 -0
  97. glpi_python_client/testing/fixtures.py +9 -0
  98. glpi_python_client/testing/utils.py +19 -5
  99. {glpi_python_client-0.3.3.dist-info → glpi_python_client-0.4.1.dist-info}/METADATA +23 -17
  100. glpi_python_client-0.4.1.dist-info/RECORD +126 -0
  101. {glpi_python_client-0.3.3.dist-info → glpi_python_client-0.4.1.dist-info}/WHEEL +1 -1
  102. glpi_python_client/auth/_v1_session.py +0 -291
  103. glpi_python_client/auth/tests/test_auth.py +0 -189
  104. glpi_python_client/auth/tests/test_v1_session.py +0 -283
  105. glpi_python_client/clients/__init__.py +0 -20
  106. glpi_python_client/clients/api/__init__.py +0 -40
  107. glpi_python_client/clients/api/administration/__init__.py +0 -13
  108. glpi_python_client/clients/api/assistance/__init__.py +0 -8
  109. glpi_python_client/clients/api/assistance/timeline/__init__.py +0 -23
  110. glpi_python_client/clients/api/dropdowns/__init__.py +0 -7
  111. glpi_python_client/clients/api/management/__init__.py +0 -7
  112. glpi_python_client/clients/async_client.py +0 -243
  113. glpi_python_client/clients/commons/__init__.py +0 -9
  114. glpi_python_client/clients/commons/_async_bridge.py +0 -191
  115. glpi_python_client/clients/commons/_errors.py +0 -27
  116. glpi_python_client/clients/commons/_http.py +0 -240
  117. glpi_python_client/clients/commons/tests/__init__.py +0 -5
  118. glpi_python_client/clients/commons/tests/test_errors.py +0 -41
  119. glpi_python_client/clients/commons/tests/test_filters.py +0 -49
  120. glpi_python_client/clients/commons/tests/test_http.py +0 -131
  121. glpi_python_client/clients/commons/tests/test_payloads.py +0 -64
  122. glpi_python_client/clients/commons/tests/test_transport.py +0 -136
  123. glpi_python_client/clients/custom/__init__.py +0 -34
  124. glpi_python_client/clients/custom/_pagination_async.py +0 -164
  125. glpi_python_client/clients/custom/_statistics_async.py +0 -500
  126. glpi_python_client/clients/custom/_ticket_context.py +0 -67
  127. glpi_python_client/clients/custom/_ticket_context_async.py +0 -73
  128. glpi_python_client/clients/custom/tests/test_statistics.py +0 -562
  129. glpi_python_client/clients/custom/tests/test_statistics_async.py +0 -232
  130. glpi_python_client/clients/custom/tests/test_ticket_context.py +0 -57
  131. glpi_python_client/clients/tests/__init__.py +0 -1
  132. glpi_python_client/clients/tests/test_api_coverage.py +0 -882
  133. glpi_python_client/clients/tests/test_async_branches.py +0 -701
  134. glpi_python_client/clients/tests/test_async_smoke.py +0 -150
  135. glpi_python_client/clients/tests/test_glpi_client.py +0 -266
  136. glpi_python_client/clients/tests/test_parity.py +0 -70
  137. glpi_python_client/clients/tests/test_smoke.py +0 -259
  138. glpi_python_client/content/tests/__init__.py +0 -5
  139. glpi_python_client/content/tests/test_conversion.py +0 -13
  140. glpi_python_client/models/api_schema/administration/tests/__init__.py +0 -1
  141. glpi_python_client/models/api_schema/administration/tests/test_administration_schemas.py +0 -145
  142. glpi_python_client/models/api_schema/assistance/tests/__init__.py +0 -1
  143. glpi_python_client/models/api_schema/assistance/tests/test_assistance_schemas.py +0 -108
  144. glpi_python_client/models/api_schema/assistance/tests/test_content_roundtrip.py +0 -102
  145. glpi_python_client/models/api_schema/assistance/timeline/tests/__init__.py +0 -1
  146. glpi_python_client/models/api_schema/assistance/timeline/tests/test_timeline_schemas.py +0 -147
  147. glpi_python_client/models/api_schema/dropdowns/tests/__init__.py +0 -1
  148. glpi_python_client/models/api_schema/dropdowns/tests/test_dropdowns_schemas.py +0 -61
  149. glpi_python_client/models/api_schema/management/tests/__init__.py +0 -1
  150. glpi_python_client/models/api_schema/management/tests/test_management_schemas.py +0 -50
  151. glpi_python_client/models/custom_schema/tests/__init__.py +0 -1
  152. glpi_python_client/models/custom_schema/tests/test_ticket_context.py +0 -398
  153. glpi_python_client-0.3.3.dist-info/RECORD +0 -104
  154. /glpi_python_client/{clients → _async/clients}/commons/_payloads.py +0 -0
  155. {glpi_python_client-0.3.3.dist-info → glpi_python_client-0.4.1.dist-info}/licenses/LICENSE +0 -0
@@ -2,10 +2,13 @@
2
2
 
3
3
  The package re-exports two client classes:
4
4
 
5
- * :class:`GlpiClient` — synchronous, blocking client (single source of
6
- truth for endpoint behaviour).
7
- * :class:`AsyncGlpiClient` — asynchronous facade that wraps each
8
- synchronous method into a coroutine.
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, GlpiClient
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,7 +47,14 @@ 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,
55
+ GetPluginFieldsContainer,
56
+ GetPluginFieldsField,
57
+ GetPluginFieldsValueRow,
33
58
  GetSolution,
34
59
  GetTeamMember,
35
60
  GetTicket,
@@ -52,6 +77,9 @@ from glpi_python_client.models import (
52
77
  PatchDocument,
53
78
  PatchEntity,
54
79
  PatchFollowup,
80
+ PatchKBArticle,
81
+ PatchKBArticleComment,
82
+ PatchKBCategory,
55
83
  PatchLocation,
56
84
  PatchSolution,
57
85
  PatchTeamMember,
@@ -62,7 +90,11 @@ from glpi_python_client.models import (
62
90
  PostDocument,
63
91
  PostEntity,
64
92
  PostFollowup,
93
+ PostKBArticle,
94
+ PostKBArticleComment,
95
+ PostKBCategory,
65
96
  PostLocation,
97
+ PostPluginFieldsValueRow,
66
98
  PostSolution,
67
99
  PostTeamMember,
68
100
  PostTicket,
@@ -72,13 +104,16 @@ from glpi_python_client.models import (
72
104
  TicketMarkdownOptions,
73
105
  )
74
106
 
75
- __version__ = "0.3.3"
107
+ __version__ = "0.4.1"
76
108
 
77
109
  __all__ = [
78
110
  "AsyncGlpiClient",
79
111
  "DeleteDocument",
80
112
  "DeleteEntity",
81
113
  "DeleteFollowup",
114
+ "DeleteKBArticle",
115
+ "DeleteKBArticleComment",
116
+ "DeleteKBCategory",
82
117
  "DeleteLocation",
83
118
  "DeleteSolution",
84
119
  "DeleteTeamMember",
@@ -89,30 +124,49 @@ __all__ = [
89
124
  "GetDocument",
90
125
  "GetEntity",
91
126
  "GetFollowup",
127
+ "GetKBArticle",
128
+ "GetKBArticleComment",
129
+ "GetKBArticleRevision",
130
+ "GetKBCategory",
92
131
  "GetLocation",
132
+ "GetPluginFieldsContainer",
133
+ "GetPluginFieldsField",
134
+ "GetPluginFieldsValueRow",
93
135
  "GetSolution",
94
136
  "GetTeamMember",
95
137
  "GetTicket",
96
138
  "GetTicketTask",
97
139
  "GetTimelineDocument",
98
140
  "GetUser",
141
+ "GlpiAuthError",
99
142
  "GlpiClient",
100
143
  "GlpiEnum",
144
+ "GlpiError",
101
145
  "GlpiGlobalValidation",
146
+ "GlpiNotFoundError",
102
147
  "GlpiPriority",
148
+ "GlpiProtocolError",
149
+ "GlpiServerError",
103
150
  "GlpiSolutionStatus",
151
+ "GlpiStatusError",
104
152
  "GlpiTaskState",
105
153
  "GlpiTicketContext",
106
154
  "GlpiTicketStatus",
107
155
  "GlpiTicketType",
108
156
  "GlpiTimelinePosition",
157
+ "GlpiTimeoutError",
158
+ "GlpiTransportError",
109
159
  "GlpiUserAuthType",
160
+ "GlpiValidationError",
110
161
  "IdNameCompletenameRef",
111
162
  "IdNameRef",
112
163
  "IdRef",
113
164
  "PatchDocument",
114
165
  "PatchEntity",
115
166
  "PatchFollowup",
167
+ "PatchKBArticle",
168
+ "PatchKBArticleComment",
169
+ "PatchKBCategory",
116
170
  "PatchLocation",
117
171
  "PatchSolution",
118
172
  "PatchTeamMember",
@@ -123,7 +177,11 @@ __all__ = [
123
177
  "PostDocument",
124
178
  "PostEntity",
125
179
  "PostFollowup",
180
+ "PostKBArticle",
181
+ "PostKBArticleComment",
182
+ "PostKBCategory",
126
183
  "PostLocation",
184
+ "PostPluginFieldsValueRow",
127
185
  "PostSolution",
128
186
  "PostTeamMember",
129
187
  "PostTicket",
@@ -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
- asynchronous ``GlpiClient`` and the legacy v1 session wrapper used solely by
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"]