glpi-python-client 0.2.1__py3-none-any.whl → 0.3.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 (59) hide show
  1. glpi_python_client/__init__.py +15 -5
  2. glpi_python_client/clients/__init__.py +13 -6
  3. glpi_python_client/clients/api/__init__.py +21 -21
  4. glpi_python_client/clients/api/administration/__init__.py +6 -5
  5. glpi_python_client/clients/api/administration/_entity.py +59 -17
  6. glpi_python_client/clients/api/administration/_user.py +63 -16
  7. glpi_python_client/clients/api/assistance/__init__.py +4 -4
  8. glpi_python_client/clients/api/assistance/_team.py +11 -13
  9. glpi_python_client/clients/api/assistance/_ticket.py +67 -17
  10. glpi_python_client/clients/api/assistance/timeline/__init__.py +9 -9
  11. glpi_python_client/clients/api/assistance/timeline/_document.py +16 -16
  12. glpi_python_client/clients/api/assistance/timeline/_followup.py +16 -18
  13. glpi_python_client/clients/api/assistance/timeline/_solution.py +16 -18
  14. glpi_python_client/clients/api/assistance/timeline/_task.py +16 -18
  15. glpi_python_client/clients/api/dropdowns/__init__.py +3 -3
  16. glpi_python_client/clients/api/dropdowns/_location.py +15 -17
  17. glpi_python_client/clients/api/management/__init__.py +3 -3
  18. glpi_python_client/clients/api/management/_document.py +25 -28
  19. glpi_python_client/clients/async_client.py +241 -0
  20. glpi_python_client/clients/commons/_async_bridge.py +174 -0
  21. glpi_python_client/clients/commons/_config.py +2 -1
  22. glpi_python_client/clients/commons/_transport.py +89 -61
  23. glpi_python_client/clients/commons/tests/test_transport.py +136 -0
  24. glpi_python_client/clients/custom/__init__.py +20 -3
  25. glpi_python_client/clients/custom/_statistics.py +442 -32
  26. glpi_python_client/clients/custom/_statistics_async.py +250 -0
  27. glpi_python_client/clients/custom/_ticket_context.py +17 -16
  28. glpi_python_client/clients/custom/_ticket_context_async.py +73 -0
  29. glpi_python_client/clients/custom/tests/test_statistics.py +382 -16
  30. glpi_python_client/clients/custom/tests/test_statistics_async.py +232 -0
  31. glpi_python_client/clients/custom/tests/test_ticket_context.py +57 -0
  32. glpi_python_client/clients/{glpi_client.py → sync_client.py} +55 -54
  33. glpi_python_client/clients/tests/test_api_coverage.py +262 -87
  34. glpi_python_client/clients/tests/test_async_branches.py +195 -0
  35. glpi_python_client/clients/tests/test_async_smoke.py +150 -0
  36. glpi_python_client/clients/tests/test_glpi_client.py +14 -14
  37. glpi_python_client/clients/tests/test_parity.py +70 -0
  38. glpi_python_client/clients/tests/test_smoke.py +28 -28
  39. glpi_python_client/models/__init__.py +5 -1
  40. glpi_python_client/models/api_schema/administration/_entity.py +44 -4
  41. glpi_python_client/models/api_schema/administration/_user.py +237 -12
  42. glpi_python_client/models/api_schema/administration/tests/test_administration_schemas.py +31 -0
  43. glpi_python_client/models/api_schema/assistance/_team.py +36 -11
  44. glpi_python_client/models/api_schema/assistance/_ticket.py +199 -10
  45. glpi_python_client/models/api_schema/assistance/timeline/_document.py +46 -4
  46. glpi_python_client/models/api_schema/assistance/timeline/_followup.py +92 -4
  47. glpi_python_client/models/api_schema/assistance/timeline/_solution.py +84 -4
  48. glpi_python_client/models/api_schema/assistance/timeline/_task.py +117 -4
  49. glpi_python_client/models/api_schema/dropdowns/_location.py +111 -4
  50. glpi_python_client/models/api_schema/management/_document.py +67 -4
  51. glpi_python_client/models/custom_schema/__init__.py +2 -1
  52. glpi_python_client/models/custom_schema/_ticket_context.py +143 -39
  53. glpi_python_client/models/custom_schema/tests/test_ticket_context.py +189 -1
  54. glpi_python_client/testing/fixtures.py +1 -1
  55. glpi_python_client/testing/utils.py +15 -2
  56. {glpi_python_client-0.2.1.dist-info → glpi_python_client-0.3.1.dist-info}/METADATA +58 -36
  57. {glpi_python_client-0.2.1.dist-info → glpi_python_client-0.3.1.dist-info}/RECORD +59 -49
  58. {glpi_python_client-0.2.1.dist-info → glpi_python_client-0.3.1.dist-info}/WHEEL +0 -0
  59. {glpi_python_client-0.2.1.dist-info → glpi_python_client-0.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,13 +1,20 @@
1
1
  """Public import surface for the GLPI Python client package.
2
2
 
3
- The package re-exports the asynchronous :class:`GlpiClient` and the
4
- ``api_schema`` and ``custom_schema`` Pydantic models so downstream users
5
- can import them from a single stable package root.
3
+ The package re-exports two client classes:
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.
9
+
10
+ The ``api_schema`` and ``custom_schema`` Pydantic models are also
11
+ re-exported so downstream users can import them from a single stable
12
+ package root.
6
13
  """
7
14
 
8
15
  from __future__ import annotations
9
16
 
10
- from glpi_python_client.clients import GlpiClient
17
+ from glpi_python_client.clients import AsyncGlpiClient, GlpiClient
11
18
  from glpi_python_client.models import (
12
19
  DeleteDocument,
13
20
  DeleteEntity,
@@ -62,11 +69,13 @@ from glpi_python_client.models import (
62
69
  PostTicketTask,
63
70
  PostTimelineDocument,
64
71
  PostUser,
72
+ TicketMarkdownOptions,
65
73
  )
66
74
 
67
- __version__ = "0.2.1"
75
+ __version__ = "0.3.1"
68
76
 
69
77
  __all__ = [
78
+ "AsyncGlpiClient",
70
79
  "DeleteDocument",
71
80
  "DeleteEntity",
72
81
  "DeleteFollowup",
@@ -121,5 +130,6 @@ __all__ = [
121
130
  "PostTicketTask",
122
131
  "PostTimelineDocument",
123
132
  "PostUser",
133
+ "TicketMarkdownOptions",
124
134
  "__version__",
125
135
  ]
@@ -1,13 +1,20 @@
1
1
  """Public client exports for the GLPI Python package.
2
2
 
3
- Only one client class is supported: the asynchronous
4
- :class:`glpi_python_client.clients.glpi_client.GlpiClient`. The legacy
5
- synchronous and dual-stack clients have been removed in favour of the
6
- async-only design described in ``update.md``.
3
+ The package exposes two client classes:
4
+
5
+ * :class:`GlpiClient` — synchronous, blocking client. The single source
6
+ of truth for endpoint behaviour.
7
+ * :class:`AsyncGlpiClient` — asynchronous facade that wraps every
8
+ synchronous method into a coroutine via
9
+ :class:`~glpi_python_client.clients.commons._async_bridge.AsyncBridge`.
10
+
11
+ Both classes share the same endpoint surface; pick the one matching
12
+ your runtime model.
7
13
  """
8
14
 
9
15
  from __future__ import annotations
10
16
 
11
- from glpi_python_client.clients.glpi_client import GlpiClient
17
+ from glpi_python_client.clients.async_client import AsyncGlpiClient
18
+ from glpi_python_client.clients.sync_client import GlpiClient
12
19
 
13
- __all__ = ["GlpiClient"]
20
+ __all__ = ["AsyncGlpiClient", "GlpiClient"]
@@ -1,7 +1,7 @@
1
1
  """Per-endpoint API mixins backed by the ``api_schema`` Pydantic models.
2
2
 
3
3
  The mixins under this package mirror the endpoints documented in
4
- ``docs/glpi_api_contract.json`` one for one. They wrap the asynchronous
4
+ ``docs/glpi_api_contract.json`` one for one. They wrap the Synchronous
5
5
  transport helpers from :mod:`glpi_python_client.clients.commons` and exchange
6
6
  typed ``Get<Name>``, ``Post<Name>``, ``Patch<Name>``, and ``Delete<Name>``
7
7
  models with the GLPI API.
@@ -10,31 +10,31 @@ models with the GLPI API.
10
10
  from __future__ import annotations
11
11
 
12
12
  from glpi_python_client.clients.api.administration import (
13
- AsyncEntityMixin,
14
- AsyncUserMixin,
13
+ EntityMixin,
14
+ UserMixin,
15
15
  )
16
16
  from glpi_python_client.clients.api.assistance import (
17
- AsyncTeamMemberMixin,
18
- AsyncTicketMixin,
17
+ TeamMemberMixin,
18
+ TicketMixin,
19
19
  )
20
20
  from glpi_python_client.clients.api.assistance.timeline import (
21
- AsyncFollowupMixin,
22
- AsyncSolutionMixin,
23
- AsyncTicketTaskMixin,
24
- AsyncTimelineDocumentMixin,
21
+ FollowupMixin,
22
+ SolutionMixin,
23
+ TicketTaskMixin,
24
+ TimelineDocumentMixin,
25
25
  )
26
- from glpi_python_client.clients.api.dropdowns import AsyncLocationMixin
27
- from glpi_python_client.clients.api.management import AsyncDocumentMixin
26
+ from glpi_python_client.clients.api.dropdowns import LocationMixin
27
+ from glpi_python_client.clients.api.management import DocumentMixin
28
28
 
29
29
  __all__ = [
30
- "AsyncDocumentMixin",
31
- "AsyncEntityMixin",
32
- "AsyncFollowupMixin",
33
- "AsyncLocationMixin",
34
- "AsyncSolutionMixin",
35
- "AsyncTeamMemberMixin",
36
- "AsyncTicketMixin",
37
- "AsyncTicketTaskMixin",
38
- "AsyncTimelineDocumentMixin",
39
- "AsyncUserMixin",
30
+ "DocumentMixin",
31
+ "EntityMixin",
32
+ "FollowupMixin",
33
+ "LocationMixin",
34
+ "SolutionMixin",
35
+ "TeamMemberMixin",
36
+ "TicketMixin",
37
+ "TicketTaskMixin",
38
+ "TimelineDocumentMixin",
39
+ "UserMixin",
40
40
  ]
@@ -1,12 +1,13 @@
1
- """GLPI ``/Administration`` mixins for the asynchronous client.
1
+ """GLPI ``/Administration`` mixins for the Synchronous client.
2
2
 
3
3
  The submodules expose the user and entity mixins used by
4
- :class:`glpi_python_client.clients.glpi_client.GlpiClient`.
4
+ :class:`glpi_python_client.clients.sync_client.GlpiClient` and
5
+ :class:`glpi_python_client.clients.async_client.AsyncGlpiClient`.
5
6
  """
6
7
 
7
8
  from __future__ import annotations
8
9
 
9
- from glpi_python_client.clients.api.administration._entity import AsyncEntityMixin
10
- from glpi_python_client.clients.api.administration._user import AsyncUserMixin
10
+ from glpi_python_client.clients.api.administration._entity import EntityMixin
11
+ from glpi_python_client.clients.api.administration._user import UserMixin
11
12
 
12
- __all__ = ["AsyncEntityMixin", "AsyncUserMixin"]
13
+ __all__ = ["EntityMixin", "UserMixin"]
@@ -1,4 +1,4 @@
1
- """Asynchronous GLPI ``/Administration/Entity`` mixin.
1
+ """Synchronous GLPI ``/Administration/Entity`` mixin.
2
2
 
3
3
  The mixin exposes the search, fetch, create, update, and delete helpers
4
4
  for the GLPI entity resource. Entity calls intentionally bypass the
@@ -7,8 +7,10 @@ client's ``GLPI-Entity`` header so cross-entity lookups remain possible.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
+ from collections.abc import Iterator
11
+
10
12
  from glpi_python_client.clients.commons._constants import ENTITY_ENDPOINT, GlpiId
11
- from glpi_python_client.clients.commons._transport import AsyncTransportMixin
13
+ from glpi_python_client.clients.commons._transport import TransportMixin
12
14
  from glpi_python_client.models.api_schema.administration._entity import (
13
15
  DeleteEntity,
14
16
  GetEntity,
@@ -17,10 +19,10 @@ from glpi_python_client.models.api_schema.administration._entity import (
17
19
  )
18
20
 
19
21
 
20
- class AsyncEntityMixin(AsyncTransportMixin):
21
- """Asynchronous CRUD helpers for ``/Administration/Entity``."""
22
+ class EntityMixin(TransportMixin):
23
+ """Synchronous CRUD helpers for ``/Administration/Entity``."""
22
24
 
23
- async def search_entities(
25
+ def search_entities(
24
26
  self,
25
27
  rsql_filter: str = "",
26
28
  *,
@@ -50,11 +52,53 @@ class AsyncEntityMixin(AsyncTransportMixin):
50
52
  params["limit"] = limit
51
53
  if rsql_filter:
52
54
  params["filter"] = rsql_filter
53
- return await self._resource_list(
55
+ return self._resource_list(
54
56
  ENTITY_ENDPOINT, GetEntity, params=params, skip_entity=True
55
57
  )
56
58
 
57
- async def get_entity(self, entity_id: GlpiId) -> GetEntity:
59
+ def iter_search_entities(
60
+ self,
61
+ rsql_filter: str = "",
62
+ *,
63
+ batch_size: int = 50,
64
+ ) -> Iterator[list[GetEntity]]:
65
+ """Yield successive pages of GLPI entities until exhausted.
66
+
67
+ The generator drives pagination automatically by advancing the
68
+ ``start`` offset after each batch. Iteration stops when the server
69
+ returns fewer items than ``batch_size``, which signals the last page.
70
+ Entity calls bypass the ``GLPI-Entity`` header so cross-entity
71
+ lookups remain possible.
72
+
73
+ Parameters
74
+ ----------
75
+ rsql_filter : str, optional
76
+ Raw RSQL filter forwarded as the ``filter`` query parameter.
77
+ Empty by default, which lists every accessible entity.
78
+ batch_size : int, optional
79
+ Number of records requested per page (default 50).
80
+
81
+ Yields
82
+ ------
83
+ list[GetEntity]
84
+ One page of entities per iteration. The last yielded batch may
85
+ be shorter than ``batch_size``.
86
+ """
87
+
88
+ start = 0
89
+ while True:
90
+ batch = self.search_entities(
91
+ rsql_filter,
92
+ limit=batch_size,
93
+ start=start,
94
+ )
95
+ if batch:
96
+ yield batch
97
+ if len(batch) < batch_size:
98
+ break
99
+ start += batch_size
100
+
101
+ def get_entity(self, entity_id: GlpiId) -> GetEntity:
58
102
  """Fetch one GLPI entity by identifier.
59
103
 
60
104
  Parameters
@@ -73,14 +117,14 @@ class AsyncEntityMixin(AsyncTransportMixin):
73
117
  If the GLPI server returns a non-success HTTP status.
74
118
  """
75
119
 
76
- return await self._resource_get(
120
+ return self._resource_get(
77
121
  f"{ENTITY_ENDPOINT}/{entity_id}",
78
122
  GetEntity,
79
123
  failure_message=f"Failed to get entity {entity_id}",
80
124
  skip_entity=True,
81
125
  )
82
126
 
83
- async def create_entity(self, entity: PostEntity) -> int:
127
+ def create_entity(self, entity: PostEntity) -> int:
84
128
  """Create one GLPI entity.
85
129
 
86
130
  Parameters
@@ -100,7 +144,7 @@ class AsyncEntityMixin(AsyncTransportMixin):
100
144
  non-success HTTP status.
101
145
  """
102
146
 
103
- return await self._resource_create(
147
+ return self._resource_create(
104
148
  ENTITY_ENDPOINT,
105
149
  entity,
106
150
  failure_message="Failed to create entity",
@@ -109,7 +153,7 @@ class AsyncEntityMixin(AsyncTransportMixin):
109
153
  skip_entity=True,
110
154
  )
111
155
 
112
- async def update_entity(self, entity_id: GlpiId, entity: PatchEntity) -> None:
156
+ def update_entity(self, entity_id: GlpiId, entity: PatchEntity) -> None:
113
157
  """Update one GLPI entity with a partial body.
114
158
 
115
159
  Parameters
@@ -129,16 +173,14 @@ class AsyncEntityMixin(AsyncTransportMixin):
129
173
  If the GLPI server returns a non-success HTTP status.
130
174
  """
131
175
 
132
- await self._resource_update(
176
+ self._resource_update(
133
177
  f"{ENTITY_ENDPOINT}/{entity_id}",
134
178
  entity,
135
179
  failure_message=f"Failed to update entity {entity_id}",
136
180
  log_message=f"GLPI API updated entity {entity_id}",
137
181
  )
138
182
 
139
- async def delete_entity(
140
- self, entity_id: GlpiId, *, force: bool | None = None
141
- ) -> None:
183
+ def delete_entity(self, entity_id: GlpiId, *, force: bool | None = None) -> None:
142
184
  """Delete one GLPI entity by identifier.
143
185
 
144
186
  Parameters
@@ -159,7 +201,7 @@ class AsyncEntityMixin(AsyncTransportMixin):
159
201
  If the GLPI server returns a non-success HTTP status.
160
202
  """
161
203
 
162
- await self._resource_delete(
204
+ self._resource_delete(
163
205
  f"{ENTITY_ENDPOINT}/{entity_id}",
164
206
  failure_message=f"Failed to delete entity {entity_id}",
165
207
  log_message=f"GLPI API deleted entity {entity_id}",
@@ -169,4 +211,4 @@ class AsyncEntityMixin(AsyncTransportMixin):
169
211
  )
170
212
 
171
213
 
172
- __all__ = ["AsyncEntityMixin"]
214
+ __all__ = ["EntityMixin"]
@@ -1,15 +1,17 @@
1
- """Asynchronous GLPI ``/Administration/User`` mixin.
1
+ """Synchronous GLPI ``/Administration/User`` mixin.
2
2
 
3
3
  The mixin exposes search, fetch, create, update, and delete helpers for the
4
4
  GLPI user resource. All operations exchange the
5
5
  :mod:`glpi_python_client.models.api_schema.administration` models and rely on
6
- the asynchronous transport mixin for HTTP dispatch.
6
+ the Synchronous transport mixin for HTTP dispatch.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
+ from collections.abc import Iterator
12
+
11
13
  from glpi_python_client.clients.commons._constants import USER_ENDPOINT, GlpiId
12
- from glpi_python_client.clients.commons._transport import AsyncTransportMixin
14
+ from glpi_python_client.clients.commons._transport import TransportMixin
13
15
  from glpi_python_client.models.api_schema.administration._user import (
14
16
  DeleteUser,
15
17
  GetUser,
@@ -18,15 +20,15 @@ from glpi_python_client.models.api_schema.administration._user import (
18
20
  )
19
21
 
20
22
 
21
- class AsyncUserMixin(AsyncTransportMixin):
22
- """Asynchronous CRUD helpers for ``/Administration/User``.
23
+ class UserMixin(TransportMixin):
24
+ """Synchronous CRUD helpers for ``/Administration/User``.
23
25
 
24
26
  The helpers follow the contract-first naming convention and forward all
25
27
  server-side validation to the GLPI API instead of duplicating checks on
26
28
  the client side.
27
29
  """
28
30
 
29
- async def search_users(
31
+ def search_users(
30
32
  self,
31
33
  rsql_filter: str = "",
32
34
  *,
@@ -59,11 +61,56 @@ class AsyncUserMixin(AsyncTransportMixin):
59
61
  params: dict[str, object] = {"limit": limit, "start": start}
60
62
  if rsql_filter:
61
63
  params["filter"] = rsql_filter
62
- return await self._resource_list(
64
+ return self._resource_list(
63
65
  USER_ENDPOINT, GetUser, params=params, skip_entity=skip_entity
64
66
  )
65
67
 
66
- async def get_user(self, user_id: GlpiId) -> GetUser:
68
+ def iter_search_users(
69
+ self,
70
+ rsql_filter: str = "",
71
+ *,
72
+ batch_size: int = 50,
73
+ skip_entity: bool = False,
74
+ ) -> Iterator[list[GetUser]]:
75
+ """Yield successive pages of GLPI users until exhausted.
76
+
77
+ The generator drives pagination automatically by advancing the
78
+ ``start`` offset after each batch. Iteration stops when the server
79
+ returns fewer items than ``batch_size``, which signals the last page.
80
+
81
+ Parameters
82
+ ----------
83
+ rsql_filter : str, optional
84
+ Raw RSQL filter forwarded as the ``filter`` query parameter.
85
+ Empty by default, which lists every visible user.
86
+ batch_size : int, optional
87
+ Number of records requested per page (default 50).
88
+ skip_entity : bool, optional
89
+ When ``True`` the ``GLPI-Entity`` header is omitted so the
90
+ search spans every entity the caller has access to.
91
+
92
+ Yields
93
+ ------
94
+ list[GetUser]
95
+ One page of users per iteration. The last yielded batch may
96
+ be shorter than ``batch_size``.
97
+ """
98
+
99
+ start = 0
100
+ while True:
101
+ batch = self.search_users(
102
+ rsql_filter,
103
+ limit=batch_size,
104
+ start=start,
105
+ skip_entity=skip_entity,
106
+ )
107
+ if batch:
108
+ yield batch
109
+ if len(batch) < batch_size:
110
+ break
111
+ start += batch_size
112
+
113
+ def get_user(self, user_id: GlpiId) -> GetUser:
67
114
  """Fetch one GLPI user by identifier.
68
115
 
69
116
  Parameters
@@ -82,13 +129,13 @@ class AsyncUserMixin(AsyncTransportMixin):
82
129
  If the GLPI server returns a non-success HTTP status.
83
130
  """
84
131
 
85
- return await self._resource_get(
132
+ return self._resource_get(
86
133
  f"{USER_ENDPOINT}/{user_id}",
87
134
  GetUser,
88
135
  failure_message=f"Failed to get user {user_id}",
89
136
  )
90
137
 
91
- async def create_user(self, user: PostUser) -> int:
138
+ def create_user(self, user: PostUser) -> int:
92
139
  """Create one GLPI user.
93
140
 
94
141
  Parameters
@@ -108,7 +155,7 @@ class AsyncUserMixin(AsyncTransportMixin):
108
155
  non-success HTTP status.
109
156
  """
110
157
 
111
- return await self._resource_create(
158
+ return self._resource_create(
112
159
  USER_ENDPOINT,
113
160
  user,
114
161
  failure_message="Failed to create user",
@@ -116,7 +163,7 @@ class AsyncUserMixin(AsyncTransportMixin):
116
163
  log_message_factory=lambda new_id: f"GLPI API created user {new_id}",
117
164
  )
118
165
 
119
- async def update_user(self, user_id: GlpiId, user: PatchUser) -> None:
166
+ def update_user(self, user_id: GlpiId, user: PatchUser) -> None:
120
167
  """Update one GLPI user with a partial body.
121
168
 
122
169
  Parameters
@@ -136,14 +183,14 @@ class AsyncUserMixin(AsyncTransportMixin):
136
183
  If the GLPI server returns a non-success HTTP status.
137
184
  """
138
185
 
139
- await self._resource_update(
186
+ self._resource_update(
140
187
  f"{USER_ENDPOINT}/{user_id}",
141
188
  user,
142
189
  failure_message=f"Failed to update user {user_id}",
143
190
  log_message=f"GLPI API updated user {user_id}",
144
191
  )
145
192
 
146
- async def delete_user(self, user_id: GlpiId, *, force: bool | None = None) -> None:
193
+ def delete_user(self, user_id: GlpiId, *, force: bool | None = None) -> None:
147
194
  """Delete one GLPI user by identifier.
148
195
 
149
196
  Parameters
@@ -164,7 +211,7 @@ class AsyncUserMixin(AsyncTransportMixin):
164
211
  If the GLPI server returns a non-success HTTP status.
165
212
  """
166
213
 
167
- await self._resource_delete(
214
+ self._resource_delete(
168
215
  f"{USER_ENDPOINT}/{user_id}",
169
216
  failure_message=f"Failed to delete user {user_id}",
170
217
  log_message=f"GLPI API deleted user {user_id}",
@@ -173,4 +220,4 @@ class AsyncUserMixin(AsyncTransportMixin):
173
220
  )
174
221
 
175
222
 
176
- __all__ = ["AsyncUserMixin"]
223
+ __all__ = ["UserMixin"]
@@ -1,8 +1,8 @@
1
- """GLPI ``/Assistance`` mixins for the asynchronous client."""
1
+ """GLPI ``/Assistance`` mixins for the Synchronous client."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from glpi_python_client.clients.api.assistance._team import AsyncTeamMemberMixin
6
- from glpi_python_client.clients.api.assistance._ticket import AsyncTicketMixin
5
+ from glpi_python_client.clients.api.assistance._team import TeamMemberMixin
6
+ from glpi_python_client.clients.api.assistance._ticket import TicketMixin
7
7
 
8
- __all__ = ["AsyncTeamMemberMixin", "AsyncTicketMixin"]
8
+ __all__ = ["TeamMemberMixin", "TicketMixin"]
@@ -1,4 +1,4 @@
1
- """Asynchronous GLPI ``/Assistance/Ticket/{id}/TeamMember`` mixin.
1
+ """Synchronous GLPI ``/Assistance/Ticket/{id}/TeamMember`` mixin.
2
2
 
3
3
  The team-member endpoint exposes list, add, and remove operations on a
4
4
  ticket. The mixin uses the ``api_schema`` ``TeamMember`` models and lets
@@ -16,7 +16,7 @@ from glpi_python_client.clients.commons._constants import (
16
16
  )
17
17
  from glpi_python_client.clients.commons._http import ensure_response_status
18
18
  from glpi_python_client.clients.commons._payloads import model_to_payload
19
- from glpi_python_client.clients.commons._transport import AsyncTransportMixin
19
+ from glpi_python_client.clients.commons._transport import TransportMixin
20
20
  from glpi_python_client.models.api_schema.assistance._team import (
21
21
  GetTeamMember,
22
22
  PostTeamMember,
@@ -25,10 +25,10 @@ from glpi_python_client.models.api_schema.assistance._team import (
25
25
  logger = logging.getLogger(__name__)
26
26
 
27
27
 
28
- class AsyncTeamMemberMixin(AsyncTransportMixin):
29
- """Asynchronous helpers for the ticket team-member endpoint."""
28
+ class TeamMemberMixin(TransportMixin):
29
+ """Synchronous helpers for the ticket team-member endpoint."""
30
30
 
31
- async def list_ticket_team_members(self, ticket_id: GlpiId) -> list[GetTeamMember]:
31
+ def list_ticket_team_members(self, ticket_id: GlpiId) -> list[GetTeamMember]:
32
32
  """List the team members currently linked to one ticket.
33
33
 
34
34
  Parameters
@@ -47,15 +47,13 @@ class AsyncTeamMemberMixin(AsyncTransportMixin):
47
47
  If the GLPI server returns a non-success HTTP status.
48
48
  """
49
49
 
50
- return await self._resource_list(
50
+ return self._resource_list(
51
51
  f"{TICKET_ENDPOINT}/{ticket_id}/{TEAM_MEMBER_SUFFIX}",
52
52
  GetTeamMember,
53
53
  failure_message=f"Failed to list ticket team members for {ticket_id}",
54
54
  )
55
55
 
56
- async def add_ticket_team_member(
57
- self, ticket_id: GlpiId, member: PostTeamMember
58
- ) -> None:
56
+ def add_ticket_team_member(self, ticket_id: GlpiId, member: PostTeamMember) -> None:
59
57
  """Add one team member to a ticket.
60
58
 
61
59
  Parameters
@@ -79,7 +77,7 @@ class AsyncTeamMemberMixin(AsyncTransportMixin):
79
77
  """
80
78
 
81
79
  endpoint = f"{TICKET_ENDPOINT}/{ticket_id}/{TEAM_MEMBER_SUFFIX}"
82
- response = await self._post_request(endpoint, model_to_payload(member))
80
+ response = self._post_request(endpoint, model_to_payload(member))
83
81
  ensure_response_status(
84
82
  response,
85
83
  success_statuses=(200, 201),
@@ -87,7 +85,7 @@ class AsyncTeamMemberMixin(AsyncTransportMixin):
87
85
  )
88
86
  logger.info("GLPI API added team member on ticket %s", ticket_id)
89
87
 
90
- async def remove_ticket_team_member(
88
+ def remove_ticket_team_member(
91
89
  self, ticket_id: GlpiId, member: PostTeamMember
92
90
  ) -> None:
93
91
  """Remove one team member from a ticket.
@@ -110,7 +108,7 @@ class AsyncTeamMemberMixin(AsyncTransportMixin):
110
108
  If the GLPI server returns a non-success HTTP status.
111
109
  """
112
110
 
113
- await self._resource_delete(
111
+ self._resource_delete(
114
112
  f"{TICKET_ENDPOINT}/{ticket_id}/{TEAM_MEMBER_SUFFIX}",
115
113
  failure_message=f"Failed to remove team member on ticket {ticket_id}",
116
114
  log_message=f"GLPI API removed team member on ticket {ticket_id}",
@@ -118,4 +116,4 @@ class AsyncTeamMemberMixin(AsyncTransportMixin):
118
116
  )
119
117
 
120
118
 
121
- __all__ = ["AsyncTeamMemberMixin"]
119
+ __all__ = ["TeamMemberMixin"]