python-open-router 0.4.0__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
  # MIT License
2
2
 
3
- Copyright (c) 2025 Joost Lekkerkerker
3
+ Copyright (c) 2025-2026 Joost Lekkerkerker
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python_open_router
3
- Version: 0.4.0
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)
@@ -121,7 +122,7 @@ check [the contributor's page][contributors].
121
122
 
122
123
  MIT License
123
124
 
124
- Copyright (c) 2025 Joost Lekkerkerker
125
+ Copyright (c) 2025-2026 Joost Lekkerkerker
125
126
 
126
127
  Permission is hereby granted, free of charge, to any person obtaining a copy
127
128
  of this software and associated documentation files (the "Software"), to deal
@@ -151,7 +152,7 @@ SOFTWARE.
151
152
  [joostlek]: https://github.com/joostlek
152
153
  [keepchangelog]: http://keepachangelog.com/en/1.0.0/
153
154
  [license-shield]: https://img.shields.io/github/license/joostlek/python-open-router.svg
154
- [maintenance-shield]: https://img.shields.io/maintenance/yes/2025.svg
155
+ [maintenance-shield]: https://img.shields.io/maintenance/yes/2026.svg
155
156
  [poetry-install]: https://python-poetry.org/docs/#installation
156
157
  [poetry]: https://python-poetry.org
157
158
  [pre-commit]: https://pre-commit.com/
@@ -88,7 +88,7 @@ check [the contributor's page][contributors].
88
88
 
89
89
  MIT License
90
90
 
91
- Copyright (c) 2025 Joost Lekkerkerker
91
+ Copyright (c) 2025-2026 Joost Lekkerkerker
92
92
 
93
93
  Permission is hereby granted, free of charge, to any person obtaining a copy
94
94
  of this software and associated documentation files (the "Software"), to deal
@@ -118,7 +118,7 @@ SOFTWARE.
118
118
  [joostlek]: https://github.com/joostlek
119
119
  [keepchangelog]: http://keepachangelog.com/en/1.0.0/
120
120
  [license-shield]: https://img.shields.io/github/license/joostlek/python-open-router.svg
121
- [maintenance-shield]: https://img.shields.io/maintenance/yes/2025.svg
121
+ [maintenance-shield]: https://img.shields.io/maintenance/yes/2026.svg
122
122
  [poetry-install]: https://python-poetry.org/docs/#installation
123
123
  [poetry]: https://python-poetry.org
124
124
  [pre-commit]: https://pre-commit.com/
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python_open_router"
3
- version = "0.4.0"
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>"]
@@ -32,21 +32,21 @@ mashumaro = "^3.11"
32
32
  orjson = ">=3.9.0"
33
33
 
34
34
  [tool.poetry.group.dev.dependencies]
35
- codespell = "2.4.2"
35
+ codespell = "2.4.3"
36
36
  covdefaults = "2.3.0"
37
- coverage = {version = "7.15.0", extras = ["toml"]}
38
- mypy = "2.2.0"
39
- pre-commit = "4.6.0"
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.6"
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.15.21"
45
+ ruff = "0.17.3"
46
46
  safety = "3.8.1"
47
47
  yamllint = "1.38.0"
48
- syrupy = "5.5.2"
49
- aioresponses = "0.7.9"
48
+ syrupy = "6.1.1"
49
+ aiointercept = "1.0.0"
50
50
 
51
51
  [tool.poetry.urls]
52
52
  "Bug Tracker" = "https://github.com/joostlek/python-open-router/issues"
@@ -137,12 +137,14 @@ asyncio_mode = "auto"
137
137
  ignore = [
138
138
  "ANN401", # Opinioated warning on disallowing dynamically typed expressions
139
139
  "COM812", # Conflicts with other rules
140
+ "CPY001", # No copyright notices used in this project
140
141
  "D203", # Conflicts with other rules
141
142
  "D213", # Conflicts with other rules
142
143
  "D417", # False positives in some occasions
143
144
  "ISC001", # Conflicts with other rules
144
145
  "PLR0912", # Too many branches - legitimate for API client methods
145
146
  "PLR0913", # Too many arguments - legitimate for API client methods
147
+ "PLR0917", # Too many positional arguments - legitimate for API client methods
146
148
  "PLR2004", # Just annoying, not really useful
147
149
  ]
148
150
  select = ["ALL"]
@@ -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
  ]
@@ -128,6 +128,7 @@ class SupportedParameter(StrEnum):
128
128
  SEED = "seed"
129
129
  RESPONSE_FORMAT = "response_format"
130
130
  STRUCTURED_OUTPUTS = "structured_outputs"
131
+ PREDICTION = "prediction"
131
132
  TOOLS = "tools"
132
133
  TOOL_CHOICE = "tool_choice"
133
134
  PARALLEL_TOOL_CALLS = "parallel_tool_calls"
@@ -157,6 +158,18 @@ class Modality(StrEnum):
157
158
  TRANSCRIPTION = "transcription"
158
159
 
159
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
+
160
173
  @dataclass(kw_only=True)
161
174
  class ModelArchitecture(DataClassORJSONMixin):
162
175
  """Model architecture data."""
@@ -210,6 +223,39 @@ class DefaultParameters(DataClassORJSONMixin):
210
223
  repetition_penalty: float | None = None
211
224
 
212
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
+
213
259
  @dataclass(kw_only=True)
214
260
  class PerRequestLimits(DataClassORJSONMixin):
215
261
  """Per-request limits."""
@@ -246,6 +292,7 @@ class Model(DataClassORJSONMixin):
246
292
  supported_voices: list[str] | None = None
247
293
  expiration_date: str | None = None
248
294
  knowledge_cutoff: str | None = None
295
+ reasoning: ModelReasoning | None = None
249
296
 
250
297
  @classmethod
251
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 (