runapi-core 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.
- runapi_core-0.1.0/PKG-INFO +46 -0
- runapi_core-0.1.0/README.md +33 -0
- runapi_core-0.1.0/pyproject.toml +30 -0
- runapi_core-0.1.0/src/runapi/core/__init__.py +71 -0
- runapi_core-0.1.0/src/runapi/core/auth.py +36 -0
- runapi_core-0.1.0/src/runapi/core/config.py +23 -0
- runapi_core-0.1.0/src/runapi/core/constants.py +17 -0
- runapi_core-0.1.0/src/runapi/core/contract_gen.py +1462 -0
- runapi_core-0.1.0/src/runapi/core/errors.py +254 -0
- runapi_core-0.1.0/src/runapi/core/files.py +101 -0
- runapi_core-0.1.0/src/runapi/core/http_client.py +130 -0
- runapi_core-0.1.0/src/runapi/core/models.py +248 -0
- runapi_core-0.1.0/src/runapi/core/multipart.py +23 -0
- runapi_core-0.1.0/src/runapi/core/options.py +54 -0
- runapi_core-0.1.0/src/runapi/core/polling.py +55 -0
- runapi_core-0.1.0/src/runapi/core/py.typed +0 -0
- runapi_core-0.1.0/src/runapi/core/resource.py +65 -0
- runapi_core-0.1.0/src/runapi/core/version.py +1 -0
- runapi_core-0.1.0/tests/test_auth.py +62 -0
- runapi_core-0.1.0/tests/test_config.py +45 -0
- runapi_core-0.1.0/tests/test_errors.py +122 -0
- runapi_core-0.1.0/tests/test_files.py +113 -0
- runapi_core-0.1.0/tests/test_http_client.py +202 -0
- runapi_core-0.1.0/tests/test_models.py +112 -0
- runapi_core-0.1.0/tests/test_polling.py +85 -0
- runapi_core-0.1.0/tests/test_resource.py +55 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: runapi-core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Core module for the RunAPI Python SDK
|
|
5
|
+
Project-URL: Homepage, https://runapi.ai
|
|
6
|
+
Project-URL: Documentation, https://runapi.ai/docs#sdk
|
|
7
|
+
Author-email: RunAPI <contact@runapi.ai>
|
|
8
|
+
License-Expression: Apache-2.0
|
|
9
|
+
Keywords: ai,api,runapi,sdk
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Requires-Dist: httpx>=0.27
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# RunAPI Core Python SDK
|
|
15
|
+
|
|
16
|
+
The RunAPI Core Python SDK provides shared authentication, HTTP, retry, error, and polling primitives for RunAPI model packages. Install `runapi-core` only when you are building SDK infrastructure or shared Python tooling; application code should normally install a concrete model package such as `runapi-flux-2`.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install runapi-core
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Notes
|
|
25
|
+
|
|
26
|
+
Use the core package for common client options, error classes, request helpers, file uploads, and task polling behavior that model SDKs share. Configure it globally or per client:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import runapi.core as runapi
|
|
30
|
+
|
|
31
|
+
runapi.configure(api_key="sk-...") # or set RUNAPI_API_KEY in the environment
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from runapi.core import FilesClient
|
|
36
|
+
|
|
37
|
+
files = FilesClient() # reads RUNAPI_API_KEY, or pass api_key="sk-..."
|
|
38
|
+
uploaded = files.create(file="./input.png")
|
|
39
|
+
print(uploaded.url)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Public SDK docs live at https://runapi.ai/docs#runapi-sdks and the model catalog lives at https://runapi.ai/models.
|
|
43
|
+
|
|
44
|
+
## License
|
|
45
|
+
|
|
46
|
+
Licensed under the Apache License, Version 2.0.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# RunAPI Core Python SDK
|
|
2
|
+
|
|
3
|
+
The RunAPI Core Python SDK provides shared authentication, HTTP, retry, error, and polling primitives for RunAPI model packages. Install `runapi-core` only when you are building SDK infrastructure or shared Python tooling; application code should normally install a concrete model package such as `runapi-flux-2`.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install runapi-core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Notes
|
|
12
|
+
|
|
13
|
+
Use the core package for common client options, error classes, request helpers, file uploads, and task polling behavior that model SDKs share. Configure it globally or per client:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
import runapi.core as runapi
|
|
17
|
+
|
|
18
|
+
runapi.configure(api_key="sk-...") # or set RUNAPI_API_KEY in the environment
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from runapi.core import FilesClient
|
|
23
|
+
|
|
24
|
+
files = FilesClient() # reads RUNAPI_API_KEY, or pass api_key="sk-..."
|
|
25
|
+
uploaded = files.create(file="./input.png")
|
|
26
|
+
print(uploaded.url)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Public SDK docs live at https://runapi.ai/docs#runapi-sdks and the model catalog lives at https://runapi.ai/models.
|
|
30
|
+
|
|
31
|
+
## License
|
|
32
|
+
|
|
33
|
+
Licensed under the Apache License, Version 2.0.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "runapi-core"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Core module for the RunAPI Python SDK"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "Apache-2.0"
|
|
12
|
+
authors = [{ name = "RunAPI", email = "contact@runapi.ai" }]
|
|
13
|
+
keywords = ["runapi", "ai", "sdk", "api"]
|
|
14
|
+
dependencies = ["httpx>=0.27"]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://runapi.ai"
|
|
18
|
+
Documentation = "https://runapi.ai/docs#sdk"
|
|
19
|
+
|
|
20
|
+
[tool.hatch.version]
|
|
21
|
+
path = "src/runapi/core/version.py"
|
|
22
|
+
|
|
23
|
+
[tool.hatch.build.targets.wheel]
|
|
24
|
+
packages = ["src/runapi"]
|
|
25
|
+
|
|
26
|
+
[tool.uv]
|
|
27
|
+
package = true
|
|
28
|
+
|
|
29
|
+
[dependency-groups]
|
|
30
|
+
dev = ["pytest>=8", "httpx>=0.27"]
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""RunAPI Python SDK — shared core.
|
|
2
|
+
|
|
3
|
+
Configuration, errors, models, HTTP transport, polling, and the file upload
|
|
4
|
+
client shared by every per-model-line package.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from . import config, errors, polling
|
|
8
|
+
from .auth import resolve_api_key
|
|
9
|
+
from .config import configure
|
|
10
|
+
from .contract_gen import CONTRACT
|
|
11
|
+
from .errors import (
|
|
12
|
+
AuthenticationError,
|
|
13
|
+
ConflictError,
|
|
14
|
+
Error,
|
|
15
|
+
InsufficientCreditsError,
|
|
16
|
+
NetworkError,
|
|
17
|
+
NotFoundError,
|
|
18
|
+
RateLimitError,
|
|
19
|
+
ServerError,
|
|
20
|
+
ServiceUnavailableError,
|
|
21
|
+
TaskFailedError,
|
|
22
|
+
TaskTimeoutError,
|
|
23
|
+
TimeoutError,
|
|
24
|
+
ValidationError,
|
|
25
|
+
error_from_response,
|
|
26
|
+
)
|
|
27
|
+
from .files import FilesClient, UploadResponse
|
|
28
|
+
from .http_client import HttpClient
|
|
29
|
+
from .models import BaseModel, DynamicModel, TaskResponse, optional, required
|
|
30
|
+
from .multipart import MultipartBody, MultipartFile
|
|
31
|
+
from .options import ClientOptions, PollingOptions, RequestOptions
|
|
32
|
+
from .resource import Resource
|
|
33
|
+
from .version import __version__
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"__version__",
|
|
37
|
+
"config",
|
|
38
|
+
"configure",
|
|
39
|
+
"errors",
|
|
40
|
+
"polling",
|
|
41
|
+
"CONTRACT",
|
|
42
|
+
"resolve_api_key",
|
|
43
|
+
"Error",
|
|
44
|
+
"AuthenticationError",
|
|
45
|
+
"InsufficientCreditsError",
|
|
46
|
+
"NotFoundError",
|
|
47
|
+
"ConflictError",
|
|
48
|
+
"ValidationError",
|
|
49
|
+
"RateLimitError",
|
|
50
|
+
"ServiceUnavailableError",
|
|
51
|
+
"ServerError",
|
|
52
|
+
"NetworkError",
|
|
53
|
+
"TimeoutError",
|
|
54
|
+
"TaskTimeoutError",
|
|
55
|
+
"TaskFailedError",
|
|
56
|
+
"error_from_response",
|
|
57
|
+
"ClientOptions",
|
|
58
|
+
"RequestOptions",
|
|
59
|
+
"PollingOptions",
|
|
60
|
+
"BaseModel",
|
|
61
|
+
"DynamicModel",
|
|
62
|
+
"TaskResponse",
|
|
63
|
+
"required",
|
|
64
|
+
"optional",
|
|
65
|
+
"MultipartBody",
|
|
66
|
+
"MultipartFile",
|
|
67
|
+
"HttpClient",
|
|
68
|
+
"Resource",
|
|
69
|
+
"FilesClient",
|
|
70
|
+
"UploadResponse",
|
|
71
|
+
]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""API key resolution."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from . import config
|
|
7
|
+
from .errors import AuthenticationError
|
|
8
|
+
|
|
9
|
+
ENV_VAR_NAME = "RUNAPI_API_KEY"
|
|
10
|
+
|
|
11
|
+
MISSING_KEY_MESSAGE = (
|
|
12
|
+
"API key is required. Pass api_key or set the RUNAPI_API_KEY environment variable."
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def resolve_api_key(explicit: Optional[str] = None) -> str:
|
|
17
|
+
"""Resolve the API key, in priority order:
|
|
18
|
+
|
|
19
|
+
1. the explicit argument
|
|
20
|
+
2. the global ``runapi.core`` configuration (``config.api_key``)
|
|
21
|
+
3. the ``RUNAPI_API_KEY`` environment variable
|
|
22
|
+
|
|
23
|
+
All sources are trimmed; blank values are treated as missing. Raises
|
|
24
|
+
:class:`AuthenticationError` when no source yields a value.
|
|
25
|
+
"""
|
|
26
|
+
resolved = _normalize(explicit) or _normalize(config.api_key) or _normalize(os.environ.get(ENV_VAR_NAME))
|
|
27
|
+
if not resolved:
|
|
28
|
+
raise AuthenticationError(MISSING_KEY_MESSAGE)
|
|
29
|
+
return resolved
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _normalize(value: Optional[str]) -> Optional[str]:
|
|
33
|
+
if not isinstance(value, str):
|
|
34
|
+
return None
|
|
35
|
+
trimmed = value.strip()
|
|
36
|
+
return trimmed or None
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Module-level configuration shared across RunAPI clients.
|
|
2
|
+
|
|
3
|
+
Mirrors Ruby's global ``RunApi.api_key`` / ``RunApi.base_url``. Values are read
|
|
4
|
+
at request time, so ``configure()`` (or assigning these attributes directly)
|
|
5
|
+
affects clients constructed afterwards.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from .constants import DEFAULT_BASE_URL
|
|
12
|
+
|
|
13
|
+
api_key: Optional[str] = None
|
|
14
|
+
base_url: str = DEFAULT_BASE_URL
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def configure(api_key: Optional[str] = None, base_url: Optional[str] = None) -> None:
|
|
18
|
+
"""Set global configuration. Only non-None arguments are applied."""
|
|
19
|
+
module = sys.modules[__name__]
|
|
20
|
+
if api_key is not None:
|
|
21
|
+
module.api_key = api_key
|
|
22
|
+
if base_url is not None:
|
|
23
|
+
module.base_url = base_url
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from .version import __version__
|
|
2
|
+
|
|
3
|
+
HTTP_REQUEST_TIMEOUT = 900
|
|
4
|
+
POLLING_INTERVAL = 2
|
|
5
|
+
POLLING_MAX_WAIT = 900
|
|
6
|
+
|
|
7
|
+
MAX_RETRIES = 2
|
|
8
|
+
RETRY_BASE_DELAY = 0.5
|
|
9
|
+
RETRY_MAX_DELAY = 5.0
|
|
10
|
+
|
|
11
|
+
DEFAULT_BASE_URL = "https://runapi.ai"
|
|
12
|
+
|
|
13
|
+
SDK_USER_AGENT = f"runapi-sdk-python/{__version__}"
|
|
14
|
+
|
|
15
|
+
IDEMPOTENT_METHODS = frozenset({"GET", "HEAD", "PUT", "DELETE", "OPTIONS"})
|
|
16
|
+
|
|
17
|
+
RETRYABLE_STATUS_CODES = frozenset({429, 500, 502, 503, 504})
|