nonecap 0.1.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.
@@ -0,0 +1,53 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["v*"]
7
+ pull_request:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ matrix:
17
+ python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python }}
23
+ - run: python -m pip install -e ".[dev]"
24
+ - run: ruff check .
25
+ - run: mypy
26
+ - run: pytest
27
+
28
+ publish:
29
+ # Tag pushes only (v0.1.0, v1.2.3, ...): build and publish to PyPI via
30
+ # trusted publishing (OIDC) — no token stored anywhere. One-time setup on
31
+ # PyPI: add this repo + workflow + the `pypi` environment as a (pending)
32
+ # trusted publisher for the `nonecap` project.
33
+ needs: test
34
+ if: github.ref_type == 'tag' && startsWith(github.ref_name, 'v')
35
+ runs-on: ubuntu-latest
36
+ environment: pypi
37
+ permissions:
38
+ id-token: write
39
+ steps:
40
+ - uses: actions/checkout@v4
41
+ - uses: actions/setup-python@v5
42
+ with:
43
+ python-version: "3.12"
44
+ - name: Verify tag matches package version
45
+ run: |
46
+ want="v$(python -c "import re;print(re.search(r'\"([^\"]+)\"', open('src/nonecap/_version.py').read()).group(1))")"
47
+ if [ "$want" != "$GITHUB_REF_NAME" ]; then
48
+ echo "::error::tag $GITHUB_REF_NAME does not match _version.py ($want). Bump the version or retag."
49
+ exit 1
50
+ fi
51
+ - run: python -m pip install build
52
+ - run: python -m build
53
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ .coverage
11
+ .DS_Store
12
+ .idea/
13
+ .vscode/
nonecap-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lunium
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.
nonecap-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,190 @@
1
+ Metadata-Version: 2.4
2
+ Name: nonecap
3
+ Version: 0.1.0
4
+ Summary: Official Python client for the NoneCap hCaptcha solving API.
5
+ Project-URL: Homepage, https://nonecap.com
6
+ Project-URL: Documentation, https://nonecap.com/api-reference
7
+ Project-URL: Repository, https://github.com/nonecap/nonecap-py
8
+ Project-URL: Issues, https://github.com/nonecap/nonecap-py/issues
9
+ Author: Lunium
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: api-client,captcha,captcha-solver,hcaptcha,hcaptcha-solver,nonecap,sdk
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.9
24
+ Requires-Dist: httpx>=0.24
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy>=1.13; extra == 'dev'
27
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
28
+ Requires-Dist: pytest>=8; extra == 'dev'
29
+ Requires-Dist: ruff>=0.8; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ <h1 align="center">nonecap</h1>
33
+
34
+ <p align="center">
35
+ <a href="https://github.com/nonecap/nonecap-py/actions/workflows/ci.yml"><img src="https://github.com/nonecap/nonecap-py/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
36
+ <a href="https://pypi.org/project/nonecap/"><img src="https://img.shields.io/pypi/v/nonecap.svg" alt="PyPI"></a>
37
+ <a href="https://pypi.org/project/nonecap/"><img src="https://img.shields.io/pypi/pyversions/nonecap.svg" alt="Python versions"></a>
38
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
39
+ </p>
40
+
41
+ <p align="center">Official Python client for the <a href="https://nonecap.com">NoneCap</a> hCaptcha solving API.</p>
42
+
43
+ Submit a captcha, get back a token. The client handles the polling, the timeouts, and the error cases so you don't write the request loop yourself. Sync and async, fully typed.
44
+
45
+ ## Install
46
+
47
+ ```sh
48
+ pip install nonecap
49
+ ```
50
+
51
+ Python 3.9+. The only dependency is [httpx](https://www.python-httpx.org/).
52
+
53
+ ## Quick start
54
+
55
+ Grab an API key from [dashboard.nonecap.com](https://dashboard.nonecap.com), then:
56
+
57
+ ```python
58
+ from nonecap import NoneCap
59
+
60
+ nc = NoneCap(api_key="nc_live_...")
61
+
62
+ solve = nc.solve(
63
+ type="hcaptcha",
64
+ sitekey="10000000-ffff-ffff-ffff-000000000001",
65
+ url="https://example.com/login",
66
+ )
67
+
68
+ print(solve.token) # the hCaptcha token, ready to submit
69
+ ```
70
+
71
+ `solve()` submits the captcha and waits until it's done, using the API's long-poll so you aren't hammering it with requests. It returns the solved solve, or raises if the solve fails or your timeout runs out.
72
+
73
+ ## Async
74
+
75
+ Same surface, `await`ed. Use it as an async context manager so the connection pool gets cleaned up:
76
+
77
+ ```python
78
+ import asyncio
79
+ from nonecap import AsyncNoneCap
80
+
81
+ async def main() -> None:
82
+ async with AsyncNoneCap(api_key="nc_live_...") as nc:
83
+ solve = await nc.solve(type="hcaptcha", sitekey="...", url="https://example.com")
84
+ print(solve.token)
85
+
86
+ asyncio.run(main())
87
+ ```
88
+
89
+ ## Handling failures
90
+
91
+ Every error this library raises extends `NoneCapError`, so you can catch the whole family or pick out the one you care about.
92
+
93
+ ```python
94
+ from nonecap import (
95
+ NoneCap,
96
+ SolveFailedError,
97
+ InsufficientCreditsError,
98
+ RateLimitError,
99
+ )
100
+
101
+ try:
102
+ solve = nc.solve(type="hcaptcha", sitekey=sitekey, url=url)
103
+ except SolveFailedError as err:
104
+ print("Could not solve it:", err.solve.error.code if err.solve.error else "?")
105
+ except InsufficientCreditsError:
106
+ print("Out of credits. Top up at dashboard.nonecap.com")
107
+ except RateLimitError:
108
+ print("Too many solves in flight, back off and retry")
109
+ ```
110
+
111
+ The subclasses are `AuthenticationError` (401), `PermissionDeniedError` (403), `InsufficientCreditsError` (402), `ValidationError` (422/400, with a `param` naming the bad field), `NotFoundError` (404), `ConflictError` (409), `RateLimitError` (429), `APIError` (5xx), `APIConnectionError` and `APITimeoutError` (the request never landed), and `SolveTimeoutError` (your `solve()` budget ran out). `SolveFailedError` carries the full `solve` so you can read the underlying error code and the timings.
112
+
113
+ ## Enterprise captchas
114
+
115
+ For `hcaptcha_enterprise`, `rqdata` is required. The `@overload` signatures enforce that in mypy and pyright, so leaving it out fails your type check, and a runtime check backs it up before any network call:
116
+
117
+ ```python
118
+ solve = nc.solve(
119
+ type="hcaptcha_enterprise",
120
+ sitekey=sitekey,
121
+ url=url,
122
+ rqdata="...", # required for enterprise
123
+ )
124
+ ```
125
+
126
+ ## Proxies
127
+
128
+ Pass a proxy as a dict or a URL string. The solve runs through it, and the bytes are metered back on the solve.
129
+
130
+ ```python
131
+ nc.solve(
132
+ type="hcaptcha",
133
+ sitekey=sitekey,
134
+ url=url,
135
+ proxy={"scheme": "http", "host": "1.2.3.4", "port": 8080, "username": "u", "password": "p"},
136
+ # or: proxy="http://u:p@1.2.3.4:8080"
137
+ )
138
+ ```
139
+
140
+ ## Lower-level API
141
+
142
+ `solve()` is the convenient path. When you want control over submission and polling, the resource methods map one to one to the REST API:
143
+
144
+ ```python
145
+ # Submit without waiting: returns immediately with a pending solve
146
+ pending = nc.solves.create(type="hcaptcha", sitekey=sitekey, url=url)
147
+
148
+ # Submit and hold the connection up to 30s for it to finish
149
+ maybe_done = nc.solves.create(type="hcaptcha", sitekey=sitekey, url=url, wait=30)
150
+
151
+ # Poll one solve, long-polling up to 30s
152
+ solve = nc.solves.retrieve(pending.id, wait=30)
153
+
154
+ # Cancel a pending or in-flight solve
155
+ nc.solves.cancel(pending.id)
156
+
157
+ # List a page of solves
158
+ page = nc.solves.list(limit=50, status="solved")
159
+
160
+ # Or iterate every solve, newest first
161
+ for s in nc.solves.list_all():
162
+ print(s.id, s.status)
163
+
164
+ # Your account and credit balance
165
+ me = nc.me()
166
+ print(me.credits_balance)
167
+ ```
168
+
169
+ On `AsyncNoneCap` the same methods are coroutines, and `list_all()` is an async iterator (`async for s in nc.solves.list_all()`).
170
+
171
+ ## Configuration
172
+
173
+ ```python
174
+ NoneCap(
175
+ api_key="nc_live_...", # required
176
+ base_url="https://api.nonecap.com", # override if you need to
177
+ timeout=100.0, # per HTTP request, seconds
178
+ http_client=my_httpx_client, # inject your own httpx.Client
179
+ )
180
+ ```
181
+
182
+ `solve()` takes its own `timeout` (seconds, default 180) for the overall wait.
183
+
184
+ ## Typing
185
+
186
+ The package ships a `py.typed` marker and full inline annotations. Solves come back as frozen dataclasses with the exact field names the API uses (`solve.token`, `solve.credits_charged`, `solve.queue_ms`), so what you read in the [API reference](https://nonecap.com/api-reference) is what you get in code.
187
+
188
+ ## License
189
+
190
+ MIT, see [LICENSE](LICENSE).
@@ -0,0 +1,159 @@
1
+ <h1 align="center">nonecap</h1>
2
+
3
+ <p align="center">
4
+ <a href="https://github.com/nonecap/nonecap-py/actions/workflows/ci.yml"><img src="https://github.com/nonecap/nonecap-py/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
5
+ <a href="https://pypi.org/project/nonecap/"><img src="https://img.shields.io/pypi/v/nonecap.svg" alt="PyPI"></a>
6
+ <a href="https://pypi.org/project/nonecap/"><img src="https://img.shields.io/pypi/pyversions/nonecap.svg" alt="Python versions"></a>
7
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
8
+ </p>
9
+
10
+ <p align="center">Official Python client for the <a href="https://nonecap.com">NoneCap</a> hCaptcha solving API.</p>
11
+
12
+ Submit a captcha, get back a token. The client handles the polling, the timeouts, and the error cases so you don't write the request loop yourself. Sync and async, fully typed.
13
+
14
+ ## Install
15
+
16
+ ```sh
17
+ pip install nonecap
18
+ ```
19
+
20
+ Python 3.9+. The only dependency is [httpx](https://www.python-httpx.org/).
21
+
22
+ ## Quick start
23
+
24
+ Grab an API key from [dashboard.nonecap.com](https://dashboard.nonecap.com), then:
25
+
26
+ ```python
27
+ from nonecap import NoneCap
28
+
29
+ nc = NoneCap(api_key="nc_live_...")
30
+
31
+ solve = nc.solve(
32
+ type="hcaptcha",
33
+ sitekey="10000000-ffff-ffff-ffff-000000000001",
34
+ url="https://example.com/login",
35
+ )
36
+
37
+ print(solve.token) # the hCaptcha token, ready to submit
38
+ ```
39
+
40
+ `solve()` submits the captcha and waits until it's done, using the API's long-poll so you aren't hammering it with requests. It returns the solved solve, or raises if the solve fails or your timeout runs out.
41
+
42
+ ## Async
43
+
44
+ Same surface, `await`ed. Use it as an async context manager so the connection pool gets cleaned up:
45
+
46
+ ```python
47
+ import asyncio
48
+ from nonecap import AsyncNoneCap
49
+
50
+ async def main() -> None:
51
+ async with AsyncNoneCap(api_key="nc_live_...") as nc:
52
+ solve = await nc.solve(type="hcaptcha", sitekey="...", url="https://example.com")
53
+ print(solve.token)
54
+
55
+ asyncio.run(main())
56
+ ```
57
+
58
+ ## Handling failures
59
+
60
+ Every error this library raises extends `NoneCapError`, so you can catch the whole family or pick out the one you care about.
61
+
62
+ ```python
63
+ from nonecap import (
64
+ NoneCap,
65
+ SolveFailedError,
66
+ InsufficientCreditsError,
67
+ RateLimitError,
68
+ )
69
+
70
+ try:
71
+ solve = nc.solve(type="hcaptcha", sitekey=sitekey, url=url)
72
+ except SolveFailedError as err:
73
+ print("Could not solve it:", err.solve.error.code if err.solve.error else "?")
74
+ except InsufficientCreditsError:
75
+ print("Out of credits. Top up at dashboard.nonecap.com")
76
+ except RateLimitError:
77
+ print("Too many solves in flight, back off and retry")
78
+ ```
79
+
80
+ The subclasses are `AuthenticationError` (401), `PermissionDeniedError` (403), `InsufficientCreditsError` (402), `ValidationError` (422/400, with a `param` naming the bad field), `NotFoundError` (404), `ConflictError` (409), `RateLimitError` (429), `APIError` (5xx), `APIConnectionError` and `APITimeoutError` (the request never landed), and `SolveTimeoutError` (your `solve()` budget ran out). `SolveFailedError` carries the full `solve` so you can read the underlying error code and the timings.
81
+
82
+ ## Enterprise captchas
83
+
84
+ For `hcaptcha_enterprise`, `rqdata` is required. The `@overload` signatures enforce that in mypy and pyright, so leaving it out fails your type check, and a runtime check backs it up before any network call:
85
+
86
+ ```python
87
+ solve = nc.solve(
88
+ type="hcaptcha_enterprise",
89
+ sitekey=sitekey,
90
+ url=url,
91
+ rqdata="...", # required for enterprise
92
+ )
93
+ ```
94
+
95
+ ## Proxies
96
+
97
+ Pass a proxy as a dict or a URL string. The solve runs through it, and the bytes are metered back on the solve.
98
+
99
+ ```python
100
+ nc.solve(
101
+ type="hcaptcha",
102
+ sitekey=sitekey,
103
+ url=url,
104
+ proxy={"scheme": "http", "host": "1.2.3.4", "port": 8080, "username": "u", "password": "p"},
105
+ # or: proxy="http://u:p@1.2.3.4:8080"
106
+ )
107
+ ```
108
+
109
+ ## Lower-level API
110
+
111
+ `solve()` is the convenient path. When you want control over submission and polling, the resource methods map one to one to the REST API:
112
+
113
+ ```python
114
+ # Submit without waiting: returns immediately with a pending solve
115
+ pending = nc.solves.create(type="hcaptcha", sitekey=sitekey, url=url)
116
+
117
+ # Submit and hold the connection up to 30s for it to finish
118
+ maybe_done = nc.solves.create(type="hcaptcha", sitekey=sitekey, url=url, wait=30)
119
+
120
+ # Poll one solve, long-polling up to 30s
121
+ solve = nc.solves.retrieve(pending.id, wait=30)
122
+
123
+ # Cancel a pending or in-flight solve
124
+ nc.solves.cancel(pending.id)
125
+
126
+ # List a page of solves
127
+ page = nc.solves.list(limit=50, status="solved")
128
+
129
+ # Or iterate every solve, newest first
130
+ for s in nc.solves.list_all():
131
+ print(s.id, s.status)
132
+
133
+ # Your account and credit balance
134
+ me = nc.me()
135
+ print(me.credits_balance)
136
+ ```
137
+
138
+ On `AsyncNoneCap` the same methods are coroutines, and `list_all()` is an async iterator (`async for s in nc.solves.list_all()`).
139
+
140
+ ## Configuration
141
+
142
+ ```python
143
+ NoneCap(
144
+ api_key="nc_live_...", # required
145
+ base_url="https://api.nonecap.com", # override if you need to
146
+ timeout=100.0, # per HTTP request, seconds
147
+ http_client=my_httpx_client, # inject your own httpx.Client
148
+ )
149
+ ```
150
+
151
+ `solve()` takes its own `timeout` (seconds, default 180) for the overall wait.
152
+
153
+ ## Typing
154
+
155
+ The package ships a `py.typed` marker and full inline annotations. Solves come back as frozen dataclasses with the exact field names the API uses (`solve.token`, `solve.credits_charged`, `solve.queue_ms`), so what you read in the [API reference](https://nonecap.com/api-reference) is what you get in code.
156
+
157
+ ## License
158
+
159
+ MIT, see [LICENSE](LICENSE).
@@ -0,0 +1,74 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "nonecap"
7
+ dynamic = ["version"]
8
+ description = "Official Python client for the NoneCap hCaptcha solving API."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{ name = "Lunium" }]
13
+ requires-python = ">=3.9"
14
+ dependencies = ["httpx>=0.24"]
15
+ keywords = [
16
+ "nonecap",
17
+ "hcaptcha",
18
+ "captcha",
19
+ "captcha-solver",
20
+ "hcaptcha-solver",
21
+ "api-client",
22
+ "sdk",
23
+ ]
24
+ classifiers = [
25
+ "Development Status :: 4 - Beta",
26
+ "Intended Audience :: Developers",
27
+ "Operating System :: OS Independent",
28
+ "Programming Language :: Python :: 3",
29
+ "Programming Language :: Python :: 3.9",
30
+ "Programming Language :: Python :: 3.10",
31
+ "Programming Language :: Python :: 3.11",
32
+ "Programming Language :: Python :: 3.12",
33
+ "Programming Language :: Python :: 3.13",
34
+ "Typing :: Typed",
35
+ ]
36
+
37
+ [project.urls]
38
+ Homepage = "https://nonecap.com"
39
+ Documentation = "https://nonecap.com/api-reference"
40
+ Repository = "https://github.com/nonecap/nonecap-py"
41
+ Issues = "https://github.com/nonecap/nonecap-py/issues"
42
+
43
+ [project.optional-dependencies]
44
+ dev = [
45
+ "pytest>=8",
46
+ "pytest-asyncio>=0.24",
47
+ "mypy>=1.13",
48
+ "ruff>=0.8",
49
+ ]
50
+
51
+ [tool.hatch.version]
52
+ path = "src/nonecap/_version.py"
53
+
54
+ [tool.hatch.build.targets.wheel]
55
+ packages = ["src/nonecap"]
56
+
57
+ [tool.pytest.ini_options]
58
+ asyncio_mode = "auto"
59
+ testpaths = ["tests"]
60
+
61
+ [tool.mypy]
62
+ strict = true
63
+ warn_unused_ignores = true
64
+ files = ["src/nonecap", "tests/typing_assertions.py"]
65
+
66
+ [tool.ruff]
67
+ line-length = 96
68
+ target-version = "py39"
69
+
70
+ [tool.ruff.lint]
71
+ select = ["E", "F", "W", "I", "UP", "B", "SIM"]
72
+ # UP006/UP007/UP045: keep typing.Optional/Union and dict/list generics as written —
73
+ # the floor is 3.9 and `X | None` in runtime positions needs 3.10.
74
+ ignore = ["UP006", "UP007", "UP045"]
@@ -0,0 +1,66 @@
1
+ """Official Python client for the NoneCap hCaptcha solving API.
2
+
3
+ >>> from nonecap import NoneCap
4
+ >>> nc = NoneCap(api_key="nc_live_...")
5
+ >>> solve = nc.solve(type="hcaptcha", sitekey="...", url="https://example.com")
6
+ >>> solve.token
7
+ 'P1_...'
8
+ """
9
+
10
+ from ._client import AsyncNoneCap, NoneCap
11
+ from ._errors import (
12
+ APIConnectionError,
13
+ APIError,
14
+ APITimeoutError,
15
+ AuthenticationError,
16
+ ConflictError,
17
+ InsufficientCreditsError,
18
+ NoneCapError,
19
+ NotFoundError,
20
+ PermissionDeniedError,
21
+ RateLimitError,
22
+ SolveFailedError,
23
+ SolveTimeoutError,
24
+ ValidationError,
25
+ )
26
+ from ._types import (
27
+ TERMINAL_STATUSES,
28
+ Account,
29
+ Proxy,
30
+ Solve,
31
+ SolveError,
32
+ SolvePage,
33
+ SolveStatus,
34
+ SolveType,
35
+ )
36
+ from ._version import __version__
37
+
38
+ __all__ = [
39
+ "__version__",
40
+ # clients
41
+ "NoneCap",
42
+ "AsyncNoneCap",
43
+ # types
44
+ "Solve",
45
+ "SolveError",
46
+ "SolvePage",
47
+ "Account",
48
+ "Proxy",
49
+ "SolveType",
50
+ "SolveStatus",
51
+ "TERMINAL_STATUSES",
52
+ # errors
53
+ "NoneCapError",
54
+ "AuthenticationError",
55
+ "PermissionDeniedError",
56
+ "InsufficientCreditsError",
57
+ "ValidationError",
58
+ "NotFoundError",
59
+ "ConflictError",
60
+ "RateLimitError",
61
+ "APIError",
62
+ "APIConnectionError",
63
+ "APITimeoutError",
64
+ "SolveFailedError",
65
+ "SolveTimeoutError",
66
+ ]