glpi-python-client 0.4.3__py3-none-any.whl → 0.5.0__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.
@@ -20,6 +20,7 @@ from __future__ import annotations
20
20
  from glpi_python_client._async.clients import AsyncGlpiClient
21
21
  from glpi_python_client._errors import (
22
22
  GlpiAuthError,
23
+ GlpiContentError,
23
24
  GlpiError,
24
25
  GlpiNotFoundError,
25
26
  GlpiProtocolError,
@@ -109,7 +110,7 @@ from glpi_python_client.rsql import (
109
110
  date_window,
110
111
  )
111
112
 
112
- __version__ = "0.4.3"
113
+ __version__ = "0.5.0"
113
114
 
114
115
  __all__ = [
115
116
  "AsyncGlpiClient",
@@ -145,6 +146,7 @@ __all__ = [
145
146
  "GetUser",
146
147
  "GlpiAuthError",
147
148
  "GlpiClient",
149
+ "GlpiContentError",
148
150
  "GlpiEnum",
149
151
  "GlpiError",
150
152
  "GlpiGlobalValidation",
@@ -14,6 +14,7 @@ from glpi_python_client.models._base import (
14
14
  SERVER_TIMEZONE_CONTEXT_KEY,
15
15
  GlpiModel,
16
16
  )
17
+ from glpi_python_client.models.api_schema._content import restoring_content_faults
17
18
 
18
19
  ModelT = TypeVar("ModelT", bound=GlpiModel)
19
20
 
@@ -54,12 +55,13 @@ def model_to_payload(
54
55
  if server_timezone is not None
55
56
  else None
56
57
  )
57
- body = model.model_dump(
58
- mode="json",
59
- exclude_none=True,
60
- exclude={"extra_payload"},
61
- context=context,
62
- )
58
+ with restoring_content_faults():
59
+ body = model.model_dump(
60
+ mode="json",
61
+ exclude_none=True,
62
+ exclude={"extra_payload"},
63
+ context=context,
64
+ )
63
65
  if model.extra_payload:
64
66
  body.update(model.extra_payload)
65
67
  return body
@@ -1,10 +1,10 @@
1
1
  """Public exception hierarchy raised by :mod:`glpi_python_client`.
2
2
 
3
3
  Every exception the client raises for a bad argument, an unexpected HTTP
4
- status, an unusable response body, or a network-level fault deliberately
5
- derives from :class:`GlpiError`, so callers can catch the library's failure
6
- surface with a single ``except`` clause and never need to import the
7
- underlying HTTP library.
4
+ status, an unusable response body, a network-level fault, or content it
5
+ cannot convert deliberately derives from :class:`GlpiError`, so callers can
6
+ catch the library's failure surface with a single ``except`` clause and
7
+ never need to import the underlying HTTP library.
8
8
 
9
9
  Two deliberate exceptions to that rule remain:
10
10
 
@@ -17,6 +17,8 @@ Two deliberate exceptions to that rule remain:
17
17
  :class:`GlpiStatusError`, :class:`GlpiValidationError` and
18
18
  :class:`GlpiProtocolError` also inherit :class:`ValueError` so code written
19
19
  against earlier releases — which raised bare ``ValueError`` — keeps working.
20
+ :class:`GlpiContentError` and :class:`GlpiTransportError` do not, for the
21
+ reason given on each: nothing was passed in wrongly.
20
22
  """
21
23
 
22
24
  from __future__ import annotations
@@ -137,6 +139,35 @@ class GlpiProtocolError(GlpiError, ValueError):
137
139
  """
138
140
 
139
141
 
142
+ class GlpiContentError(GlpiError):
143
+ """A rich-text content value could not be converted.
144
+
145
+ Raised when :class:`~glpi_python_client.content.GlpiContentConverter`
146
+ cannot translate a value between GLPI's HTML transport format and the
147
+ package's canonical Markdown — in either direction. The underlying
148
+ fault is always attached as ``__cause__``.
149
+
150
+ This exists so that no failure of the content layer escapes the
151
+ package's taxonomy. The conversion runs third-party parsers
152
+ (``markdownify`` inbound, ``markdown`` outbound), and a parser fault
153
+ used to reach the caller as a bare builtin — most visibly a
154
+ ``RecursionError``, which ``except GlpiError`` does not catch and which
155
+ a caller reading a ticket has no reason to expect from
156
+ ``get_ticket``. Deeply nested HTML is caught and answered with the
157
+ body's text instead of raising at all (see
158
+ :meth:`glpi_python_client.content.conversion.GlpiContentConverter.from_transport`);
159
+ this is the backstop for everything else.
160
+
161
+ Unlike :class:`GlpiStatusError`, :class:`GlpiValidationError` and
162
+ :class:`GlpiProtocolError` this does **not** inherit ``ValueError``.
163
+ Those three do so for back-compatibility with releases that raised
164
+ bare ``ValueError`` at the same sites; there was never a
165
+ ``ValueError`` here to be compatible with, and a parser exhausting the
166
+ interpreter's stack is not a value the caller got wrong. The reasoning
167
+ matches :class:`GlpiTransportError`.
168
+ """
169
+
170
+
140
171
  def status_error_class(status_code: int) -> type[GlpiStatusError]:
141
172
  """Return the most specific status-error class for one status code.
142
173
 
@@ -164,6 +195,7 @@ def status_error_class(status_code: int) -> type[GlpiStatusError]:
164
195
 
165
196
  __all__ = [
166
197
  "GlpiAuthError",
198
+ "GlpiContentError",
167
199
  "GlpiError",
168
200
  "GlpiNotFoundError",
169
201
  "GlpiProtocolError",
@@ -14,6 +14,7 @@ from glpi_python_client.models._base import (
14
14
  SERVER_TIMEZONE_CONTEXT_KEY,
15
15
  GlpiModel,
16
16
  )
17
+ from glpi_python_client.models.api_schema._content import restoring_content_faults
17
18
 
18
19
  ModelT = TypeVar("ModelT", bound=GlpiModel)
19
20
 
@@ -54,12 +55,13 @@ def model_to_payload(
54
55
  if server_timezone is not None
55
56
  else None
56
57
  )
57
- body = model.model_dump(
58
- mode="json",
59
- exclude_none=True,
60
- exclude={"extra_payload"},
61
- context=context,
62
- )
58
+ with restoring_content_faults():
59
+ body = model.model_dump(
60
+ mode="json",
61
+ exclude_none=True,
62
+ exclude={"extra_payload"},
63
+ context=context,
64
+ )
63
65
  if model.extra_payload:
64
66
  body.update(model.extra_payload)
65
67
  return body