python-open-router 0.4.1__tar.gz → 0.5.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python_open_router
3
- Version: 0.4.1
3
+ Version: 0.5.0
4
4
  Summary: Asynchronous Python client for Open Router.
5
5
  License: MIT
6
6
  License-File: LICENSE.md
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3
19
19
  Classifier: Programming Language :: Python :: 3.12
20
20
  Classifier: Programming Language :: Python :: 3.13
21
21
  Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Programming Language :: Python :: 3.15
22
23
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
24
  Requires-Dist: aiohttp (>=3.0.0)
24
25
  Requires-Dist: mashumaro (>=3.11,<4.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python_open_router"
3
- version = "0.4.1"
3
+ version = "0.5.0"
4
4
  description = "Asynchronous Python client for Open Router."
5
5
  authors = ["Joost Lekkerkerker <joostlek@outlook.com>"]
6
6
  maintainers = ["Joost Lekkerkerker <joostlek@outlook.com>"]
@@ -34,19 +34,19 @@ orjson = ">=3.9.0"
34
34
  [tool.poetry.group.dev.dependencies]
35
35
  codespell = "2.4.3"
36
36
  covdefaults = "2.3.0"
37
- coverage = {version = "7.16.1", extras = ["toml"]}
38
- mypy = "2.3.1"
39
- pre-commit = "4.6.2"
37
+ coverage = {version = "7.17.0", extras = ["toml"]}
38
+ mypy = "2.4.0"
39
+ pre-commit = "4.7.0"
40
40
  pre-commit-hooks = "6.0.0"
41
- pylint = "4.0.8"
41
+ pylint = "4.1.3"
42
42
  pytest = "9.1.1"
43
- pytest-asyncio = "1.4.0"
43
+ pytest-asyncio = "1.4.1"
44
44
  pytest-cov = "7.1.0"
45
- ruff = "0.16.8"
45
+ ruff = "0.17.3"
46
46
  safety = "3.8.1"
47
47
  yamllint = "1.38.0"
48
48
  syrupy = "6.1.1"
49
- aiointercept = "0.1.10"
49
+ aiointercept = "1.0.0"
50
50
 
51
51
  [tool.poetry.urls]
52
52
  "Bug Tracker" = "https://github.com/joostlek/python-open-router/issues"
@@ -18,10 +18,12 @@ from python_open_router.models import (
18
18
  Model,
19
19
  ModelArchitecture,
20
20
  ModelLinks,
21
+ ModelReasoning,
21
22
  ModelResponseWrapper,
22
23
  ModelsDataWrapper,
23
24
  PerRequestLimits,
24
25
  PublicPricing,
26
+ ReasoningEffort,
25
27
  SupportedParameter,
26
28
  TopProviderInfo,
27
29
  )
@@ -40,6 +42,7 @@ __all__ = [
40
42
  "Model",
41
43
  "ModelArchitecture",
42
44
  "ModelLinks",
45
+ "ModelReasoning",
43
46
  "ModelResponseWrapper",
44
47
  "ModelsDataWrapper",
45
48
  "OpenRouterAuthenticationError",
@@ -48,6 +51,7 @@ __all__ = [
48
51
  "OpenRouterError",
49
52
  "PerRequestLimits",
50
53
  "PublicPricing",
54
+ "ReasoningEffort",
51
55
  "SupportedParameter",
52
56
  "TopProviderInfo",
53
57
  ]
@@ -158,6 +158,18 @@ class Modality(StrEnum):
158
158
  TRANSCRIPTION = "transcription"
159
159
 
160
160
 
161
+ class ReasoningEffort(StrEnum):
162
+ """Reasoning effort levels."""
163
+
164
+ MAX = "max"
165
+ XHIGH = "xhigh"
166
+ HIGH = "high"
167
+ MEDIUM = "medium"
168
+ LOW = "low"
169
+ MINIMAL = "minimal"
170
+ NONE = "none"
171
+
172
+
161
173
  @dataclass(kw_only=True)
162
174
  class ModelArchitecture(DataClassORJSONMixin):
163
175
  """Model architecture data."""
@@ -211,6 +223,39 @@ class DefaultParameters(DataClassORJSONMixin):
211
223
  repetition_penalty: float | None = None
212
224
 
213
225
 
226
+ @dataclass(kw_only=True)
227
+ class ModelReasoning(DataClassORJSONMixin):
228
+ """Model reasoning options."""
229
+
230
+ mandatory: bool
231
+ supported_efforts: list[ReasoningEffort] | None = None
232
+ default_effort: ReasoningEffort | None = None
233
+ default_enabled: bool | None = None
234
+ supports_max_tokens: bool = False
235
+
236
+ @classmethod
237
+ def __pre_deserialize__(cls, d: dict[str, Any]) -> dict[str, Any]:
238
+ """Pre deserialize hook."""
239
+ supported = set(ReasoningEffort)
240
+ if "supported_efforts" in d and d["supported_efforts"] is None:
241
+ # Null means every effort is accepted, unlike an omitted field,
242
+ # which means the model has no effort selection.
243
+ d["supported_efforts"] = list(ReasoningEffort)
244
+ efforts = d.get("supported_efforts")
245
+ default = d.get("default_effort")
246
+ for effort in [*(efforts or []), default]:
247
+ if effort is not None and effort not in supported:
248
+ _LOGGER.warning(
249
+ "Unsupported reasoning effort: %s. Please report at https://github.com/joostlek/python-open-router/issues.",
250
+ effort,
251
+ )
252
+ if efforts is not None:
253
+ d["supported_efforts"] = [e for e in efforts if e in supported]
254
+ if default not in supported:
255
+ d["default_effort"] = None
256
+ return d
257
+
258
+
214
259
  @dataclass(kw_only=True)
215
260
  class PerRequestLimits(DataClassORJSONMixin):
216
261
  """Per-request limits."""
@@ -247,6 +292,7 @@ class Model(DataClassORJSONMixin):
247
292
  supported_voices: list[str] | None = None
248
293
  expiration_date: str | None = None
249
294
  knowledge_cutoff: str | None = None
295
+ reasoning: ModelReasoning | None = None
250
296
 
251
297
  @classmethod
252
298
  def __pre_deserialize__(cls, d: dict[str, Any]) -> dict[str, Any]:
@@ -31,7 +31,7 @@ from python_open_router.models import (
31
31
  )
32
32
 
33
33
  if TYPE_CHECKING:
34
- from typing_extensions import Self
34
+ from typing import Self
35
35
 
36
36
 
37
37
  VERSION = metadata.version(__package__)
@@ -77,7 +77,7 @@ class OpenRouterClient:
77
77
  headers=headers,
78
78
  json=data,
79
79
  )
80
- except asyncio.TimeoutError as exception:
80
+ except TimeoutError as exception:
81
81
  msg = "Timeout occurred while connecting to the service"
82
82
  raise OpenRouterConnectionError(msg) from exception
83
83
  except (