python-open-router 0.1.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.
@@ -0,0 +1,15 @@
1
+ """Asynchronous Python client for Open Router."""
2
+
3
+ from python_open_router.exceptions import (
4
+ OpenRouterAuthenticationError,
5
+ OpenRouterConnectionError,
6
+ OpenRouterError,
7
+ )
8
+ from python_open_router.open_router import OpenRouterClient
9
+
10
+ __all__ = [
11
+ "OpenRouterAuthenticationError",
12
+ "OpenRouterClient",
13
+ "OpenRouterConnectionError",
14
+ "OpenRouterError",
15
+ ]
@@ -0,0 +1,13 @@
1
+ """Asynchronous Python client for OpenRouter."""
2
+
3
+
4
+ class OpenRouterError(Exception):
5
+ """Generic exception."""
6
+
7
+
8
+ class OpenRouterConnectionError(OpenRouterError):
9
+ """OpenRouter connection exception."""
10
+
11
+
12
+ class OpenRouterAuthenticationError(OpenRouterError):
13
+ """OpenRouter authentication exception."""
@@ -0,0 +1,25 @@
1
+ """Models for OpenRouter."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from mashumaro.mixins.orjson import DataClassORJSONMixin
8
+
9
+
10
+ @dataclass
11
+ class KeyDataWrapper(DataClassORJSONMixin):
12
+ """Wrapper for OpenRouter key data."""
13
+
14
+ data: KeyData
15
+
16
+
17
+ @dataclass
18
+ class KeyData(DataClassORJSONMixin):
19
+ """The OpenRouter key data."""
20
+
21
+ label: str
22
+ usage: int
23
+ is_provisioning_key: bool
24
+ limit_remaining: int | None
25
+ is_free_tier: bool
@@ -0,0 +1,115 @@
1
+ """Asynchronous Python client for Open Router."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from dataclasses import dataclass
7
+ from importlib import metadata
8
+ import socket
9
+ from typing import TYPE_CHECKING, Any
10
+
11
+ from aiohttp import ClientError, ClientResponseError, ClientSession
12
+ from aiohttp.hdrs import METH_GET
13
+ from yarl import URL
14
+
15
+ from python_open_router.exceptions import OpenRouterConnectionError
16
+ from python_open_router.models import KeyData, KeyDataWrapper
17
+
18
+ if TYPE_CHECKING:
19
+ from typing_extensions import Self
20
+
21
+
22
+ VERSION = metadata.version(__package__)
23
+ HOST = "openrouter.ai"
24
+
25
+
26
+ @dataclass
27
+ class OpenRouterClient:
28
+ """Main class for handling connections with OpenRouter."""
29
+
30
+ api_key: str
31
+ session: ClientSession | None = None
32
+ request_timeout: int = 10
33
+ _close_session: bool = False
34
+
35
+ async def _request(
36
+ self,
37
+ method: str,
38
+ uri: str,
39
+ *,
40
+ params: dict[str, Any] | None = None,
41
+ data: dict[str, Any] | None = None,
42
+ ) -> str:
43
+ """Handle a request to OpenRouter."""
44
+ url = URL.build(host=HOST, scheme="https").joinpath(f"api/v1/{uri}")
45
+
46
+ headers = {
47
+ "User-Agent": f"PythonOpenRouter/{VERSION}",
48
+ "Accept": "application/json",
49
+ "Authorization": f"Bearer {self.api_key}",
50
+ }
51
+
52
+ if self.session is None:
53
+ self.session = ClientSession()
54
+ self._close_session = True
55
+
56
+ try:
57
+ async with asyncio.timeout(self.request_timeout):
58
+ response = await self.session.request(
59
+ method,
60
+ url,
61
+ params=params,
62
+ headers=headers,
63
+ json=data,
64
+ )
65
+ except asyncio.TimeoutError as exception:
66
+ msg = "Timeout occurred while connecting to the service"
67
+ raise OpenRouterConnectionError(msg) from exception
68
+ except (
69
+ ClientError,
70
+ ClientResponseError,
71
+ socket.gaierror,
72
+ ) as exception:
73
+ msg = "Error occurred while communicating with the service"
74
+ raise OpenRouterConnectionError(msg) from exception
75
+
76
+ if response.status >= 400:
77
+ content_type = response.headers.get("Content-Type", "")
78
+ text = await response.text()
79
+ msg = "Unexpected response from OpenRouter"
80
+ raise OpenRouterConnectionError(
81
+ msg,
82
+ {"Content-Type": content_type, "response": text},
83
+ )
84
+
85
+ return await response.text()
86
+
87
+ async def get_key_data(self) -> KeyData:
88
+ """Get key data for API key."""
89
+ response = await self._request(METH_GET, "key")
90
+ return KeyDataWrapper.from_json(response).data
91
+
92
+ async def close(self) -> None:
93
+ """Close open client session."""
94
+ if self.session and self._close_session:
95
+ await self.session.close()
96
+
97
+ async def __aenter__(self) -> Self:
98
+ """Async enter.
99
+
100
+ Returns
101
+ -------
102
+ The OpenRouterClient object.
103
+
104
+ """
105
+ return self
106
+
107
+ async def __aexit__(self, *_exc_info: object) -> None:
108
+ """Async exit.
109
+
110
+ Args:
111
+ ----
112
+ _exc_info: Exec type.
113
+
114
+ """
115
+ await self.close()
File without changes
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2025 Joost Lekkerkerker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.3
2
+ Name: python_open_router
3
+ Version: 0.1.0
4
+ Summary: Asynchronous Python client for Open Router.
5
+ License: MIT
6
+ Keywords: OpenRouter,api,async,client
7
+ Author: Joost Lekkerkerker
8
+ Author-email: joostlek@outlook.com
9
+ Maintainer: Joost Lekkerkerker
10
+ Maintainer-email: joostlek@outlook.com
11
+ Requires-Python: >=3.11,<4.0
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Framework :: AsyncIO
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Natural Language :: English
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Dist: aiohttp (>=3.0.0)
23
+ Requires-Dist: mashumaro (>=3.11,<4.0)
24
+ Requires-Dist: orjson (>=3.9.0)
25
+ Requires-Dist: yarl (>=1.6.0)
26
+ Project-URL: Bug Tracker, https://github.com/joostlek/python-open-router/issues
27
+ Project-URL: Changelog, https://github.com/joostlek/python-open-router/releases
28
+ Project-URL: Documentation, https://github.com/joostlek/python-open-router
29
+ Project-URL: Homepage, https://github.com/joostlek/python-open-router
30
+ Project-URL: Repository, https://github.com/joostlek/python-open-router
31
+ Description-Content-Type: text/markdown
32
+
33
+ # Python: Open Router
34
+
35
+ [![GitHub Release][releases-shield]][releases]
36
+ [![Python Versions][python-versions-shield]][pypi]
37
+ ![Project Stage][project-stage-shield]
38
+ ![Project Maintenance][maintenance-shield]
39
+ [![License][license-shield]](LICENSE.md)
40
+
41
+ [![Build Status][build-shield]][build]
42
+ [![Code Coverage][codecov-shield]][codecov]
43
+
44
+ Asynchronous Python client for Open Router.
45
+
46
+ ## About
47
+
48
+ This package allows you to fetch data from Open Router.
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install python-open-router
54
+ ```
55
+
56
+
57
+ ## Changelog & Releases
58
+
59
+ This repository keeps a change log using [GitHub's releases][releases]
60
+ functionality. The format of the log is based on
61
+ [Keep a Changelog][keepchangelog].
62
+
63
+ Releases are based on [Semantic Versioning][semver], and use the format
64
+ of ``MAJOR.MINOR.PATCH``. In a nutshell, the version will be incremented
65
+ based on the following:
66
+
67
+ - ``MAJOR``: Incompatible or major changes.
68
+ - ``MINOR``: Backwards-compatible new features and enhancements.
69
+ - ``PATCH``: Backwards-compatible bugfixes and package updates.
70
+
71
+ ## Contributing
72
+
73
+ This is an active open-source project. We are always open to people who want to
74
+ use the code or contribute to it.
75
+
76
+ We've set up a separate document for our
77
+ [contribution guidelines](.github/CONTRIBUTING.md).
78
+
79
+ Thank you for being involved! :heart_eyes:
80
+
81
+ ## Setting up development environment
82
+
83
+ This Python project is fully managed using the [Poetry][poetry] dependency manager. But also relies on the use of NodeJS for certain checks during development.
84
+
85
+ You need at least:
86
+
87
+ - Python 3.11+
88
+ - [Poetry][poetry-install]
89
+ - NodeJS 12+ (including NPM)
90
+
91
+ To install all packages, including all development requirements:
92
+
93
+ ```bash
94
+ npm install
95
+ poetry install
96
+ ```
97
+
98
+ As this repository uses the [pre-commit][pre-commit] framework, all changes
99
+ are linted and tested with each commit. You can run all checks and tests
100
+ manually, using the following command:
101
+
102
+ ```bash
103
+ poetry run pre-commit run --all-files
104
+ ```
105
+
106
+ To run just the Python tests:
107
+
108
+ ```bash
109
+ poetry run pytest
110
+ ```
111
+
112
+ ## Authors & contributors
113
+
114
+ The content is by [Joost Lekkerkerker][joostlek].
115
+
116
+ For a full list of all authors and contributors,
117
+ check [the contributor's page][contributors].
118
+
119
+ ## License
120
+
121
+ MIT License
122
+
123
+ Copyright (c) 2025 Joost Lekkerkerker
124
+
125
+ Permission is hereby granted, free of charge, to any person obtaining a copy
126
+ of this software and associated documentation files (the "Software"), to deal
127
+ in the Software without restriction, including without limitation the rights
128
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
129
+ copies of the Software, and to permit persons to whom the Software is
130
+ furnished to do so, subject to the following conditions:
131
+
132
+ The above copyright notice and this permission notice shall be included in all
133
+ copies or substantial portions of the Software.
134
+
135
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
136
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
137
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
138
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
139
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
140
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
141
+ SOFTWARE.
142
+
143
+ [build-shield]: https://github.com/joostlek/python-open-router/actions/workflows/tests.yaml/badge.svg
144
+ [build]: https://github.com/joostlek/python-open-router/actions
145
+ [codecov-shield]: https://codecov.io/gh/joostlek/python-open-router/branch/master/graph/badge.svg
146
+ [codecov]: https://codecov.io/gh/joostlek/python-open-router
147
+ [commits-shield]: https://img.shields.io/github/commit-activity/y/joostlek/python-open-router.svg
148
+ [commits]: https://github.com/joostlek/python-open-router/commits/master
149
+ [contributors]: https://github.com/joostlek/python-open-router/graphs/contributors
150
+ [joostlek]: https://github.com/joostlek
151
+ [keepchangelog]: http://keepachangelog.com/en/1.0.0/
152
+ [license-shield]: https://img.shields.io/github/license/joostlek/python-open-router.svg
153
+ [maintenance-shield]: https://img.shields.io/maintenance/yes/2025.svg
154
+ [poetry-install]: https://python-poetry.org/docs/#installation
155
+ [poetry]: https://python-poetry.org
156
+ [pre-commit]: https://pre-commit.com/
157
+ [project-stage-shield]: https://img.shields.io/badge/project%20stage-stable-green.svg
158
+ [python-versions-shield]: https://img.shields.io/pypi/pyversions/python-open-router
159
+ [releases-shield]: https://img.shields.io/github/release/joostlek/python-open-router.svg
160
+ [releases]: https://github.com/joostlek/python-open-router/releases
161
+ [semver]: http://semver.org/spec/v2.0.0.html
162
+ [pypi]: https://pypi.org/project/python-open-router/
163
+
@@ -0,0 +1,9 @@
1
+ python_open_router/__init__.py,sha256=qWLg-1XHDTgXR7AGOzVjxQ2amINWgwTnMrRe77WFRXw,376
2
+ python_open_router/exceptions.py,sha256=68nskqNdXNMIK4iA1XOE1E5P5rbhAf27DDACkk-ZVwU,312
3
+ python_open_router/models.py,sha256=z-SMl13PAGRyQ_83zXlU7US0teNqxfc4ArTm0ain-zs,478
4
+ python_open_router/open_router.py,sha256=mVcNVZcSEcD5csllZes3RlKa7ReWEQXJf625M-so6Mo,3292
5
+ python_open_router/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ python_open_router-0.1.0.dist-info/LICENSE.md,sha256=Xbw7n2Ic30r4j8_MDNND4ss_sdoj9IGeIkEWc2Hsfs8,1077
7
+ python_open_router-0.1.0.dist-info/METADATA,sha256=KFnz6IFqokjCanKGMC6GmT3hzA53fdjc2JdinQU7OH4,6030
8
+ python_open_router-0.1.0.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
9
+ python_open_router-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.1.2
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any