spot-sdk-python 2.1.0b3__tar.gz → 2.1.2__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.
Files changed (43) hide show
  1. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/PKG-INFO +1 -1
  2. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/pyproject.toml +1 -1
  3. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/pyproject.toml.orig +1 -1
  4. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/hosting.py +13 -6
  5. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/mime.py +6 -2
  6. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/README.md +0 -0
  7. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/__init__.py +0 -0
  8. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/_json.py +0 -0
  9. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/app.py +0 -0
  10. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/artifacts.py +0 -0
  11. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/clients.py +0 -0
  12. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/config.py +0 -0
  13. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/correlation.py +0 -0
  14. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/email.py +0 -0
  15. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/errors.py +0 -0
  16. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/knowledge.py +0 -0
  17. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/knowledge_tags.py +0 -0
  18. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/llm.py +0 -0
  19. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/logging.py +0 -0
  20. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/manifest.py +0 -0
  21. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/model_input.py +0 -0
  22. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/orchestrator.py +0 -0
  23. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/proxy.py +0 -0
  24. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/py.typed +0 -0
  25. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/retriever.py +0 -0
  26. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/settings.py +0 -0
  27. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/signals.py +0 -0
  28. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/README.md +0 -0
  29. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/__init__.py +0 -0
  30. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/container.py +0 -0
  31. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/contract.py +0 -0
  32. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/corpus.py +0 -0
  33. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/engine.py +0 -0
  34. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/fake_knowledge_client.py +0 -0
  35. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/fake_llm.py +0 -0
  36. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/fake_spot.py +0 -0
  37. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/metrics.py +0 -0
  38. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/report.py +0 -0
  39. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/settings.py +0 -0
  40. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/testing/views.py +0 -0
  41. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/urls.py +0 -0
  42. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/verdict.py +0 -0
  43. {spot_sdk_python-2.1.0b3 → spot_sdk_python-2.1.2}/spot_sdk/workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spot-sdk-python
3
- Version: 2.1.0b3
3
+ Version: 2.1.2
4
4
  Summary: SPOT plugin SDK: the plugin contract, the plugin runtime, its clients and test helpers
5
5
  Author: SPOT Project
6
6
  Author-email: SPOT Project <spot@sonn.lu>
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "spot-sdk-python"
7
- version = "2.1.0b3"
7
+ version = "2.1.2"
8
8
  description = "SPOT plugin SDK: the plugin contract, the plugin runtime, its clients and test helpers"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "spot-sdk-python"
7
- version = "2.1.0b3"
7
+ version = "2.1.2"
8
8
  description = "SPOT plugin SDK: the plugin contract, the plugin runtime, its clients and test helpers"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -44,7 +44,11 @@ could expand past the bound once decoded."""
44
44
 
45
45
 
46
46
  class AnswerRefusedError(Exception):
47
- """A plugin's answer that is not read: encoded, or longer than ``MAX_ANSWER_BYTES``."""
47
+ """A plugin's answer that is not read: encoded, or longer than its bound."""
48
+
49
+
50
+ class AnswerTooLargeError(AnswerRefusedError):
51
+ """An answer longer than its bound, which a caller may treat apart from an encoded one."""
48
52
 
49
53
 
50
54
  class InvalidResponseError(Exception):
@@ -121,11 +125,14 @@ def secrets_archive(secrets: Mapping[str, str]) -> bytes:
121
125
  return buffer.getvalue()
122
126
 
123
127
 
124
- async def read_answer(response: httpx2.Response) -> bytes:
125
- """A streamed answer's body, as sent, read up to ``MAX_ANSWER_BYTES``.
128
+ async def read_answer(
129
+ response: httpx2.Response, max_bytes: int = MAX_ANSWER_BYTES
130
+ ) -> bytes:
131
+ """A streamed answer's body, as sent, read up to ``max_bytes``.
126
132
 
127
133
  Raises:
128
- AnswerRefusedError: the answer is encoded, or longer than ``MAX_ANSWER_BYTES``
134
+ AnswerRefusedError: the answer is encoded
135
+ AnswerTooLargeError: the answer is longer than ``max_bytes``
129
136
  """
130
137
  if (
131
138
  response.headers.get("content-encoding", "identity").strip().lower()
@@ -135,8 +142,8 @@ async def read_answer(response: httpx2.Response) -> bytes:
135
142
  body = bytearray()
136
143
  async for chunk in response.aiter_raw():
137
144
  body += chunk
138
- if len(body) > MAX_ANSWER_BYTES:
139
- raise AnswerRefusedError("response too large")
145
+ if len(body) > max_bytes:
146
+ raise AnswerTooLargeError(f"response too large: over {max_bytes} bytes")
140
147
  return bytes(body)
141
148
 
142
149
 
@@ -1757,8 +1757,12 @@ def _decoded(label: str) -> str:
1757
1757
  def _addresses(value: str, cut: _Cutter, punycode: _Punycode) -> Iterator[Address]:
1758
1758
  """The mailboxes of an address header, each string cut to its budget, each
1759
1759
  domain's A-labels decoded within ``punycode``; a value that does not parse
1760
- is kept whole."""
1761
- mailboxes = getaddresses([value])
1760
+ is kept whole, as is one whose comments or groups nest deeper than
1761
+ ``getaddresses`` can recurse (spot/sdk#33)."""
1762
+ try:
1763
+ mailboxes = getaddresses([value])
1764
+ except RecursionError:
1765
+ mailboxes = []
1762
1766
  if not mailboxes or not all("@" in address for _, address in mailboxes):
1763
1767
  value = value.strip()
1764
1768
  if value: