openhandle 1.0.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.
- openhandle-1.0.0/.gitignore +10 -0
- openhandle-1.0.0/LICENSE +21 -0
- openhandle-1.0.0/PKG-INFO +189 -0
- openhandle-1.0.0/README.md +163 -0
- openhandle-1.0.0/evals/README.md +29 -0
- openhandle-1.0.0/openapi/README.md +7 -0
- openhandle-1.0.0/pyproject.toml +79 -0
- openhandle-1.0.0/src/openhandle/__init__.py +21 -0
- openhandle-1.0.0/src/openhandle/_async_resources.py +3681 -0
- openhandle-1.0.0/src/openhandle/_client.py +83 -0
- openhandle-1.0.0/src/openhandle/_errors.py +59 -0
- openhandle-1.0.0/src/openhandle/_operations.py +1016 -0
- openhandle-1.0.0/src/openhandle/_references.py +174 -0
- openhandle-1.0.0/src/openhandle/_response.py +148 -0
- openhandle-1.0.0/src/openhandle/_sync_resources.py +3591 -0
- openhandle-1.0.0/src/openhandle/_transport.py +342 -0
- openhandle-1.0.0/src/openhandle/_types.py +5 -0
- openhandle-1.0.0/src/openhandle/models.py +846 -0
- openhandle-1.0.0/src/openhandle/py.typed +0 -0
openhandle-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OpenHandle
|
|
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,189 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: openhandle
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for OpenHandle
|
|
5
|
+
Project-URL: Homepage, https://openhandle.dev
|
|
6
|
+
Project-URL: Documentation, https://openhandle.dev/docs/sdks
|
|
7
|
+
Project-URL: Repository, https://github.com/openhandlehq/openhandle-python
|
|
8
|
+
Project-URL: Issues, https://github.com/openhandlehq/openhandle-python/issues
|
|
9
|
+
Author-email: OpenHandle <support@openhandle.dev>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: api,openhandle,sdk,social-media
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: httpx>=0.27
|
|
24
|
+
Requires-Dist: typing-extensions>=4.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# OpenHandle Python SDK
|
|
28
|
+
|
|
29
|
+
The official Python client for the OpenHandle API.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install openhandle
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The package supports Python 3.10 and newer and ships full type annotations.
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
Create a Test key in the [Openhandle dashboard](https://app.openhandle.dev),
|
|
42
|
+
store it as `OPENHANDLE_TEST_KEY`, and create one reusable client:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import os
|
|
46
|
+
|
|
47
|
+
from openhandle import OpenHandle
|
|
48
|
+
|
|
49
|
+
openhandle = OpenHandle(api_key=os.environ["OPENHANDLE_TEST_KEY"])
|
|
50
|
+
profile = openhandle.instagram.profile("northstar_forge_test")
|
|
51
|
+
|
|
52
|
+
response = profile.get()
|
|
53
|
+
posts = profile.posts.list(freshness="24h")
|
|
54
|
+
|
|
55
|
+
print(response.data["handle"], len(posts.data))
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The key selects the environment. `oh_test_` keys return deterministic synthetic
|
|
59
|
+
data with a `$0.000` actual charge; `oh_live_` keys use real public identifiers
|
|
60
|
+
and normal billing. Never expose an API key in client-side code.
|
|
61
|
+
|
|
62
|
+
See the [API reference](https://openhandle.dev/docs/api-reference) for a typed
|
|
63
|
+
SDK example for every operation.
|
|
64
|
+
|
|
65
|
+
## Resource selection
|
|
66
|
+
|
|
67
|
+
The SDK follows one predictable grammar:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
openhandle.<platform>.<resource>(reference).<subresource>.<operation>(options)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Only terminal operations such as `get`, `list`, `search`, and `fetch` perform
|
|
74
|
+
network requests. Selecting a resource is synchronous and reusable:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
post = openhandle.instagram.post("Db04otPRpRH")
|
|
78
|
+
|
|
79
|
+
response = post.get()
|
|
80
|
+
comments = post.comments.list()
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
A profile selector accepts a username shorthand or an explicit reference:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
openhandle.instagram.profile("openai")
|
|
87
|
+
openhandle.instagram.profile("https://www.instagram.com/openai/")
|
|
88
|
+
openhandle.instagram.profile(username="12356")
|
|
89
|
+
openhandle.instagram.profile(id="25025320")
|
|
90
|
+
openhandle.instagram.profile(url="https://www.instagram.com/openai/")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
A raw string is never treated as a platform ID. `profile("12356")` selects the
|
|
94
|
+
username `12356`; `profile(id="12356")` selects platform ID `12356`. Numeric
|
|
95
|
+
reference values are rejected because platform IDs are opaque strings.
|
|
96
|
+
|
|
97
|
+
Call `openhandle.fetch(url)` when you do not know which resource a supported
|
|
98
|
+
social URL represents.
|
|
99
|
+
|
|
100
|
+
## Pagination
|
|
101
|
+
|
|
102
|
+
A list or search operation returns one typed page:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
page = openhandle.instagram.profile("northstar_forge_test").posts.list()
|
|
106
|
+
|
|
107
|
+
print(page.data, page.has_next_page, page.next_cursor)
|
|
108
|
+
next_page = page.next()
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`items()` iterates lazily across pages, one request per page:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
for post in openhandle.instagram.profile("northstar_forge_test").posts.items():
|
|
115
|
+
print(post["id"])
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Async client
|
|
119
|
+
|
|
120
|
+
`AsyncOpenHandle` exposes the same resource graph with `async` terminal
|
|
121
|
+
operations:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
import asyncio
|
|
125
|
+
import os
|
|
126
|
+
|
|
127
|
+
from openhandle import AsyncOpenHandle
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
async def main() -> None:
|
|
131
|
+
async with AsyncOpenHandle(api_key=os.environ["OPENHANDLE_TEST_KEY"]) as openhandle:
|
|
132
|
+
response = await openhandle.instagram.profile("northstar_forge_test").get()
|
|
133
|
+
print(response.data["handle"])
|
|
134
|
+
|
|
135
|
+
async for post in openhandle.instagram.profile("northstar_forge_test").posts.items():
|
|
136
|
+
print(post["id"])
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
asyncio.run(main())
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Responses
|
|
143
|
+
|
|
144
|
+
Every response preserves the public envelope. `data` stays typed through the
|
|
145
|
+
generated models in `openhandle.models`, and metadata is available on the
|
|
146
|
+
response object:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
response = openhandle.instagram.profile("northstar_forge_test").get()
|
|
150
|
+
|
|
151
|
+
response.platform # "instagram"
|
|
152
|
+
response.resource # "profile"
|
|
153
|
+
response.captured_at # datetime
|
|
154
|
+
response.source # "live" or "cache"
|
|
155
|
+
response.request_id # stable request identifier for logs and support
|
|
156
|
+
response.billing.cost # authoritative charge as a decimal string
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
A missing metric is `None`. It is never `0`.
|
|
160
|
+
|
|
161
|
+
## Errors and retries
|
|
162
|
+
|
|
163
|
+
The SDK raises `OpenHandleError` with the documented fields. Branch on `code`,
|
|
164
|
+
never on `message`:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from openhandle import OpenHandle, OpenHandleError
|
|
168
|
+
|
|
169
|
+
try:
|
|
170
|
+
response = openhandle.instagram.profile("private_account").get()
|
|
171
|
+
except OpenHandleError as error:
|
|
172
|
+
print(error.code, error.request_id, error.retryable)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Retryable failures are retried automatically with capped exponential backoff
|
|
176
|
+
and `Retry-After` support. Configure the client, or override per request:
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
openhandle = OpenHandle(api_key="...", timeout=10.0, max_retries=1)
|
|
180
|
+
openhandle.twitter.profile("openai").get(timeout=5.0, max_retries=0)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Locally invalid references raise `OpenHandleReferenceError` before any request
|
|
184
|
+
is made. `ReferenceMismatchError` reports a social URL that belongs to a
|
|
185
|
+
different platform or resource than the selector.
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# OpenHandle Python SDK
|
|
2
|
+
|
|
3
|
+
The official Python client for the OpenHandle API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install openhandle
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The package supports Python 3.10 and newer and ships full type annotations.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Create a Test key in the [Openhandle dashboard](https://app.openhandle.dev),
|
|
16
|
+
store it as `OPENHANDLE_TEST_KEY`, and create one reusable client:
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
import os
|
|
20
|
+
|
|
21
|
+
from openhandle import OpenHandle
|
|
22
|
+
|
|
23
|
+
openhandle = OpenHandle(api_key=os.environ["OPENHANDLE_TEST_KEY"])
|
|
24
|
+
profile = openhandle.instagram.profile("northstar_forge_test")
|
|
25
|
+
|
|
26
|
+
response = profile.get()
|
|
27
|
+
posts = profile.posts.list(freshness="24h")
|
|
28
|
+
|
|
29
|
+
print(response.data["handle"], len(posts.data))
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The key selects the environment. `oh_test_` keys return deterministic synthetic
|
|
33
|
+
data with a `$0.000` actual charge; `oh_live_` keys use real public identifiers
|
|
34
|
+
and normal billing. Never expose an API key in client-side code.
|
|
35
|
+
|
|
36
|
+
See the [API reference](https://openhandle.dev/docs/api-reference) for a typed
|
|
37
|
+
SDK example for every operation.
|
|
38
|
+
|
|
39
|
+
## Resource selection
|
|
40
|
+
|
|
41
|
+
The SDK follows one predictable grammar:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
openhandle.<platform>.<resource>(reference).<subresource>.<operation>(options)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Only terminal operations such as `get`, `list`, `search`, and `fetch` perform
|
|
48
|
+
network requests. Selecting a resource is synchronous and reusable:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
post = openhandle.instagram.post("Db04otPRpRH")
|
|
52
|
+
|
|
53
|
+
response = post.get()
|
|
54
|
+
comments = post.comments.list()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
A profile selector accepts a username shorthand or an explicit reference:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
openhandle.instagram.profile("openai")
|
|
61
|
+
openhandle.instagram.profile("https://www.instagram.com/openai/")
|
|
62
|
+
openhandle.instagram.profile(username="12356")
|
|
63
|
+
openhandle.instagram.profile(id="25025320")
|
|
64
|
+
openhandle.instagram.profile(url="https://www.instagram.com/openai/")
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
A raw string is never treated as a platform ID. `profile("12356")` selects the
|
|
68
|
+
username `12356`; `profile(id="12356")` selects platform ID `12356`. Numeric
|
|
69
|
+
reference values are rejected because platform IDs are opaque strings.
|
|
70
|
+
|
|
71
|
+
Call `openhandle.fetch(url)` when you do not know which resource a supported
|
|
72
|
+
social URL represents.
|
|
73
|
+
|
|
74
|
+
## Pagination
|
|
75
|
+
|
|
76
|
+
A list or search operation returns one typed page:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
page = openhandle.instagram.profile("northstar_forge_test").posts.list()
|
|
80
|
+
|
|
81
|
+
print(page.data, page.has_next_page, page.next_cursor)
|
|
82
|
+
next_page = page.next()
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`items()` iterates lazily across pages, one request per page:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
for post in openhandle.instagram.profile("northstar_forge_test").posts.items():
|
|
89
|
+
print(post["id"])
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Async client
|
|
93
|
+
|
|
94
|
+
`AsyncOpenHandle` exposes the same resource graph with `async` terminal
|
|
95
|
+
operations:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
import asyncio
|
|
99
|
+
import os
|
|
100
|
+
|
|
101
|
+
from openhandle import AsyncOpenHandle
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
async def main() -> None:
|
|
105
|
+
async with AsyncOpenHandle(api_key=os.environ["OPENHANDLE_TEST_KEY"]) as openhandle:
|
|
106
|
+
response = await openhandle.instagram.profile("northstar_forge_test").get()
|
|
107
|
+
print(response.data["handle"])
|
|
108
|
+
|
|
109
|
+
async for post in openhandle.instagram.profile("northstar_forge_test").posts.items():
|
|
110
|
+
print(post["id"])
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
asyncio.run(main())
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Responses
|
|
117
|
+
|
|
118
|
+
Every response preserves the public envelope. `data` stays typed through the
|
|
119
|
+
generated models in `openhandle.models`, and metadata is available on the
|
|
120
|
+
response object:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
response = openhandle.instagram.profile("northstar_forge_test").get()
|
|
124
|
+
|
|
125
|
+
response.platform # "instagram"
|
|
126
|
+
response.resource # "profile"
|
|
127
|
+
response.captured_at # datetime
|
|
128
|
+
response.source # "live" or "cache"
|
|
129
|
+
response.request_id # stable request identifier for logs and support
|
|
130
|
+
response.billing.cost # authoritative charge as a decimal string
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
A missing metric is `None`. It is never `0`.
|
|
134
|
+
|
|
135
|
+
## Errors and retries
|
|
136
|
+
|
|
137
|
+
The SDK raises `OpenHandleError` with the documented fields. Branch on `code`,
|
|
138
|
+
never on `message`:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from openhandle import OpenHandle, OpenHandleError
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
response = openhandle.instagram.profile("private_account").get()
|
|
145
|
+
except OpenHandleError as error:
|
|
146
|
+
print(error.code, error.request_id, error.retryable)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Retryable failures are retried automatically with capped exponential backoff
|
|
150
|
+
and `Retry-After` support. Configure the client, or override per request:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
openhandle = OpenHandle(api_key="...", timeout=10.0, max_retries=1)
|
|
154
|
+
openhandle.twitter.profile("openai").get(timeout=5.0, max_retries=0)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Locally invalid references raise `OpenHandleReferenceError` before any request
|
|
158
|
+
is made. `ReferenceMismatchError` reports a social URL that belongs to a
|
|
159
|
+
different platform or resource than the selector.
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Agent usability eval
|
|
2
|
+
|
|
3
|
+
This eval measures whether a coding agent can discover the public SDK from the
|
|
4
|
+
installed package without reading SDK source files.
|
|
5
|
+
|
|
6
|
+
Give the agent the ten prompts in `tasks.json` and ask it to write one Python
|
|
7
|
+
file per task, named `<task-id>.py`. The agent may inspect the installed
|
|
8
|
+
package's type annotations and the package README, but not `src`, `openapi`,
|
|
9
|
+
tests, generator code, or the reference answers.
|
|
10
|
+
|
|
11
|
+
Score an answer directory with:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
python scripts/generate.py
|
|
15
|
+
python scripts/score_agent_eval.py path/to/answers
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The scorer reports two independent results per task:
|
|
19
|
+
|
|
20
|
+
- `compile`: the answer passes `mypy --strict` against the installed package.
|
|
21
|
+
- `semantic`: lightweight required/forbidden markers indicate that it used the
|
|
22
|
+
intended resource, terminal operation, and behavior.
|
|
23
|
+
|
|
24
|
+
The semantic checks are intentionally conservative heuristics, not a substitute
|
|
25
|
+
for human review. Review incorrect answers for invented methods, raw HTTP paths,
|
|
26
|
+
misunderstood references, eager pagination, and branching on error messages.
|
|
27
|
+
|
|
28
|
+
`evals/reference` is a checked-in 10/10 baseline that proves the tasks and
|
|
29
|
+
scorer remain compatible with the current package. It is not an agent score.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# OpenAPI input
|
|
2
|
+
|
|
3
|
+
`openhandle.json` is the exact public API contract used to generate this SDK.
|
|
4
|
+
It is committed so generation and releases remain reproducible.
|
|
5
|
+
|
|
6
|
+
Updates arrive through automated pull requests from the OpenHandle API
|
|
7
|
+
repository. Do not edit the snapshot or generated Python files by hand.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "openhandle"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Official Python SDK for OpenHandle"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [{ name = "OpenHandle", email = "support@openhandle.dev" }]
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
dependencies = ["httpx>=0.27", "typing-extensions>=4.10"]
|
|
15
|
+
keywords = ["openhandle", "social-media", "api", "sdk"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Typing :: Typed",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://openhandle.dev"
|
|
30
|
+
Documentation = "https://openhandle.dev/docs/sdks"
|
|
31
|
+
Repository = "https://github.com/openhandlehq/openhandle-python"
|
|
32
|
+
Issues = "https://github.com/openhandlehq/openhandle-python/issues"
|
|
33
|
+
|
|
34
|
+
[dependency-groups]
|
|
35
|
+
dev = [
|
|
36
|
+
"mypy>=1.14",
|
|
37
|
+
"pytest>=8.3",
|
|
38
|
+
"pytest-asyncio>=0.25",
|
|
39
|
+
"ruff>=0.9",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[tool.hatch.build.targets.sdist]
|
|
43
|
+
include = ["src/openhandle", "README.md", "LICENSE"]
|
|
44
|
+
|
|
45
|
+
[tool.hatch.build.targets.wheel]
|
|
46
|
+
packages = ["src/openhandle"]
|
|
47
|
+
|
|
48
|
+
[tool.ruff]
|
|
49
|
+
line-length = 120
|
|
50
|
+
target-version = "py310"
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint]
|
|
53
|
+
select = ["E", "F", "W", "I", "UP", "B", "SIM", "RUF"]
|
|
54
|
+
ignore = ["SIM108"]
|
|
55
|
+
|
|
56
|
+
[tool.ruff.lint.per-file-ignores]
|
|
57
|
+
"scripts/generate.py" = ["E501"]
|
|
58
|
+
"src/openhandle/models.py" = ["E501"]
|
|
59
|
+
"src/openhandle/_operations.py" = ["E501"]
|
|
60
|
+
"src/openhandle/_sync_resources.py" = ["E501"]
|
|
61
|
+
"src/openhandle/_async_resources.py" = ["E501"]
|
|
62
|
+
|
|
63
|
+
[tool.ruff.format]
|
|
64
|
+
exclude = [
|
|
65
|
+
"src/openhandle/models.py",
|
|
66
|
+
"src/openhandle/_operations.py",
|
|
67
|
+
"src/openhandle/_sync_resources.py",
|
|
68
|
+
"src/openhandle/_async_resources.py",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[tool.mypy]
|
|
72
|
+
strict = true
|
|
73
|
+
python_version = "3.10"
|
|
74
|
+
mypy_path = "src"
|
|
75
|
+
files = ["src/openhandle", "scripts", "tests"]
|
|
76
|
+
|
|
77
|
+
[tool.pytest.ini_options]
|
|
78
|
+
testpaths = ["tests"]
|
|
79
|
+
asyncio_mode = "auto"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from openhandle._client import AsyncOpenHandle, OpenHandle
|
|
2
|
+
from openhandle._errors import OpenHandleError, OpenHandleReferenceError, ReferenceMismatchError
|
|
3
|
+
from openhandle._response import AsyncPage, Billing, Page, Response
|
|
4
|
+
from openhandle._transport import sdk_version
|
|
5
|
+
from openhandle._types import Freshness
|
|
6
|
+
|
|
7
|
+
__version__ = sdk_version()
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"AsyncOpenHandle",
|
|
11
|
+
"AsyncPage",
|
|
12
|
+
"Billing",
|
|
13
|
+
"Freshness",
|
|
14
|
+
"OpenHandle",
|
|
15
|
+
"OpenHandleError",
|
|
16
|
+
"OpenHandleReferenceError",
|
|
17
|
+
"Page",
|
|
18
|
+
"ReferenceMismatchError",
|
|
19
|
+
"Response",
|
|
20
|
+
"__version__",
|
|
21
|
+
]
|