0xinsider 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,48 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes a GitHub release to https://pypi.org/project/0xinsider/ through
4
+ # PyPI trusted publishing: no API token is stored anywhere. The PyPI project
5
+ # lists this repository and this workflow file as its trusted publisher, and
6
+ # the `pypi` environment scopes the OIDC grant to this job.
7
+ on:
8
+ release:
9
+ types: [published]
10
+ workflow_dispatch:
11
+
12
+ permissions: {}
13
+
14
+ jobs:
15
+ build:
16
+ runs-on: ubuntu-latest
17
+ permissions:
18
+ contents: read
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: astral-sh/setup-uv@v6
22
+ - name: Check the tag matches the package version
23
+ if: github.event_name == 'release'
24
+ run: |
25
+ version=$(python3 -c "import re;print(re.search(r'\"(.+)\"', open('src/oxinsider/_version.py').read()).group(1))")
26
+ test "v${version}" = "${GITHUB_REF_NAME}" || { echo "tag ${GITHUB_REF_NAME} does not match version ${version}"; exit 1; }
27
+ - run: uv build
28
+ - uses: actions/upload-artifact@v4
29
+ with:
30
+ name: dist
31
+ path: dist/
32
+
33
+ publish:
34
+ needs: build
35
+ runs-on: ubuntu-latest
36
+ environment: pypi
37
+ permissions:
38
+ id-token: write
39
+ steps:
40
+ - uses: actions/download-artifact@v4
41
+ with:
42
+ name: dist
43
+ path: dist/
44
+ - uses: pypa/gh-action-pypi-publish@release/v1
45
+ with:
46
+ # A version already on PyPI is skipped, not failed: a release event
47
+ # after a manual dispatch of the same version is then a no-op.
48
+ skip-existing: true
@@ -0,0 +1,32 @@
1
+ name: Regenerate from OpenAPI
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "23 6 * * 1"
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+ pull-requests: write
11
+
12
+ jobs:
13
+ regenerate:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.12"
20
+ - run: python scripts/generate.py
21
+ - name: Open a pull request when the contract changed
22
+ env:
23
+ GH_TOKEN: ${{ github.token }}
24
+ run: |
25
+ if git diff --quiet; then echo "no change"; exit 0; fi
26
+ branch="regenerate/$(date -u +%Y%m%d)"
27
+ git config user.name "github-actions[bot]"
28
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
29
+ git checkout -b "$branch"
30
+ git commit -am "chore: regenerate operations from the OpenAPI document"
31
+ git push origin "$branch"
32
+ gh pr create --title "Regenerate operations from the OpenAPI document" --body "The published OpenAPI document changed. Review the generated diff before releasing."
@@ -0,0 +1,4 @@
1
+ dist/
2
+ __pycache__/
3
+ *.pyc
4
+ .venv/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 0xinsider
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,87 @@
1
+ Metadata-Version: 2.5
2
+ Name: 0xinsider
3
+ Version: 0.1.0
4
+ Summary: Official Python client for the 0xinsider Developer API: Polymarket sports and esports analytics, trader grades, large trades and sharp-money flow.
5
+ Project-URL: Homepage, https://0xinsider.com/developers
6
+ Project-URL: Documentation, https://docs.0xinsider.com
7
+ Project-URL: Repository, https://github.com/0xinsider/0xinsider-python
8
+ Project-URL: Issues, https://github.com/0xinsider/0xinsider-python/issues
9
+ Project-URL: OpenAPI, https://0xinsider.com/api/v1/openapi.json
10
+ Author-email: 0xinsider <support@0xinsider.com>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: 0xinsider,api,polymarket,prediction markets,sdk,sports analytics
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.9
20
+ Requires-Dist: httpx<1,>=0.27
21
+ Description-Content-Type: text/markdown
22
+
23
+ # 0xinsider Python SDK
24
+
25
+ Official Python client for the [0xinsider Developer API](https://0xinsider.com/developers): Polymarket sports and esports analytics, wallet grades, large trades, positions, reports and sharp-money flow.
26
+
27
+ ```sh
28
+ pip install 0xinsider
29
+ ```
30
+
31
+ The distribution is `0xinsider`; the import is `oxinsider`, because a Python module name cannot start with a digit.
32
+
33
+ ## Try it without a key
34
+
35
+ The [sandbox](https://0xinsider.com/sandbox/api/v1) answers every documented operation with example data. It needs no credential and never touches production data.
36
+
37
+ ```python
38
+ import oxinsider
39
+
40
+ with oxinsider.Client.sandbox() as client:
41
+ page = client.list_leaderboard(limit=5)
42
+ print(page["data"][0]["username"])
43
+
44
+ # Any error the operation documents, on demand:
45
+ try:
46
+ client.request("GET", "/api/v1/leaderboard", query={"sandbox_status": 429})
47
+ except oxinsider.RateLimitedError as error:
48
+ print(error.code, error.retry_after)
49
+ ```
50
+
51
+ ## Live data
52
+
53
+ Data operations need an API key from [0xinsider.com/developers](https://0xinsider.com/developers) or an OAuth 2.1 access token ([auth.md](https://0xinsider.com/auth.md)), plus an active Pro subscription. Discovery, health and platforms are public.
54
+
55
+ ```python
56
+ import oxinsider
57
+
58
+ client = oxinsider.Client() # reads OXINSIDER_API_KEY
59
+ trader = client.get_trader("swisstony", expand=["strategy", "categories"])
60
+ print(trader["data"]["grade"])
61
+
62
+ for trade in client.paginate("list_whale_trades", min_grade="A", limit=100):
63
+ print(trade["size_usd"], trade["market"]["title"])
64
+ ```
65
+
66
+ - Every documented operation is a method named after its operationId in snake_case (`listLeaderboard` becomes `list_leaderboard`). Each returns the decoded JSON body.
67
+ - `if_none_match="<etag>"` returns `{"object": "not_modified", "data": None, "etag": ...}` when nothing changed.
68
+ - `idempotency_key=` is accepted on the webhook mutations that document it.
69
+ - The SSE stream is read with `client.request("GET", "/api/v1/stream", stream=True)`, which returns the open `httpx.Response`.
70
+
71
+ ## Errors
72
+
73
+ Every non-2xx response raises `oxinsider.OxinsiderApiError` or a subclass: `BadRequestError`, `AuthenticationError`, `SubscriptionRequiredError`, `PermissionDeniedError`, `NotFoundError`, `RateLimitedError` or `ServerError`. Each carries `status`, `code`, `reason`, `param`, `retry_at`, `retry_after` and `request_id`. Branch on `reason` when it is present. For `RateLimitedError`, wait `retry_after` seconds. A request that gets no response raises `OxinsiderConnectionError`.
74
+
75
+ ## How it is built
76
+
77
+ `src/oxinsider/_operations.py` is generated from the published [OpenAPI document](https://0xinsider.com/api/v1/openapi.json) by `scripts/generate.py`, and a weekly workflow opens a pull request when the contract changes. Releases publish to PyPI from GitHub Actions through trusted publishing.
78
+
79
+ ## Other official tools
80
+
81
+ - CLI and MCP server: `npm install --global @0xinsider/mcp` or `brew install 0xinsider/tap/oxinsider`
82
+ - Go SDK: `go get github.com/0xinsider/0xinsider-go`
83
+ - Remote MCP server: `https://api.0xinsider.com/api/v1/mcp`
84
+
85
+ ## License
86
+
87
+ MIT
@@ -0,0 +1,65 @@
1
+ # 0xinsider Python SDK
2
+
3
+ Official Python client for the [0xinsider Developer API](https://0xinsider.com/developers): Polymarket sports and esports analytics, wallet grades, large trades, positions, reports and sharp-money flow.
4
+
5
+ ```sh
6
+ pip install 0xinsider
7
+ ```
8
+
9
+ The distribution is `0xinsider`; the import is `oxinsider`, because a Python module name cannot start with a digit.
10
+
11
+ ## Try it without a key
12
+
13
+ The [sandbox](https://0xinsider.com/sandbox/api/v1) answers every documented operation with example data. It needs no credential and never touches production data.
14
+
15
+ ```python
16
+ import oxinsider
17
+
18
+ with oxinsider.Client.sandbox() as client:
19
+ page = client.list_leaderboard(limit=5)
20
+ print(page["data"][0]["username"])
21
+
22
+ # Any error the operation documents, on demand:
23
+ try:
24
+ client.request("GET", "/api/v1/leaderboard", query={"sandbox_status": 429})
25
+ except oxinsider.RateLimitedError as error:
26
+ print(error.code, error.retry_after)
27
+ ```
28
+
29
+ ## Live data
30
+
31
+ Data operations need an API key from [0xinsider.com/developers](https://0xinsider.com/developers) or an OAuth 2.1 access token ([auth.md](https://0xinsider.com/auth.md)), plus an active Pro subscription. Discovery, health and platforms are public.
32
+
33
+ ```python
34
+ import oxinsider
35
+
36
+ client = oxinsider.Client() # reads OXINSIDER_API_KEY
37
+ trader = client.get_trader("swisstony", expand=["strategy", "categories"])
38
+ print(trader["data"]["grade"])
39
+
40
+ for trade in client.paginate("list_whale_trades", min_grade="A", limit=100):
41
+ print(trade["size_usd"], trade["market"]["title"])
42
+ ```
43
+
44
+ - Every documented operation is a method named after its operationId in snake_case (`listLeaderboard` becomes `list_leaderboard`). Each returns the decoded JSON body.
45
+ - `if_none_match="<etag>"` returns `{"object": "not_modified", "data": None, "etag": ...}` when nothing changed.
46
+ - `idempotency_key=` is accepted on the webhook mutations that document it.
47
+ - The SSE stream is read with `client.request("GET", "/api/v1/stream", stream=True)`, which returns the open `httpx.Response`.
48
+
49
+ ## Errors
50
+
51
+ Every non-2xx response raises `oxinsider.OxinsiderApiError` or a subclass: `BadRequestError`, `AuthenticationError`, `SubscriptionRequiredError`, `PermissionDeniedError`, `NotFoundError`, `RateLimitedError` or `ServerError`. Each carries `status`, `code`, `reason`, `param`, `retry_at`, `retry_after` and `request_id`. Branch on `reason` when it is present. For `RateLimitedError`, wait `retry_after` seconds. A request that gets no response raises `OxinsiderConnectionError`.
52
+
53
+ ## How it is built
54
+
55
+ `src/oxinsider/_operations.py` is generated from the published [OpenAPI document](https://0xinsider.com/api/v1/openapi.json) by `scripts/generate.py`, and a weekly workflow opens a pull request when the contract changes. Releases publish to PyPI from GitHub Actions through trusted publishing.
56
+
57
+ ## Other official tools
58
+
59
+ - CLI and MCP server: `npm install --global @0xinsider/mcp` or `brew install 0xinsider/tap/oxinsider`
60
+ - Go SDK: `go get github.com/0xinsider/0xinsider-go`
61
+ - Remote MCP server: `https://api.0xinsider.com/api/v1/mcp`
62
+
63
+ ## License
64
+
65
+ MIT
@@ -0,0 +1,9 @@
1
+ """Read the public discovery document and health from the live API. No key needed."""
2
+
3
+ import oxinsider
4
+
5
+ with oxinsider.Client(api_key="") as client:
6
+ discovery = client.get_api_discovery()
7
+ print("api base:", discovery["data"]["api_base_url"])
8
+ health = client.get_health()
9
+ print("health:", health.get("data", {}).get("status", health))
@@ -0,0 +1,15 @@
1
+ """Call the 0xinsider sandbox: no key, example data, simulated errors."""
2
+
3
+ import oxinsider
4
+
5
+ with oxinsider.Client.sandbox() as client:
6
+ leaderboard = client.list_leaderboard(limit=3)
7
+ print("leaderboard object:", leaderboard["object"], "rows:", len(leaderboard["data"]))
8
+
9
+ trader = client.get_trader("0x0000000000000000000000000000000000000001")
10
+ print("trader grade:", trader["data"]["grade"])
11
+
12
+ try:
13
+ client.request("GET", "/api/v1/leaderboard", query={"sandbox_status": 429})
14
+ except oxinsider.RateLimitedError as error:
15
+ print("simulated rate limit:", error.code, "retry after", error.retry_after, "s")
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.25"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "0xinsider"
7
+ dynamic = ["version"]
8
+ description = "Official Python client for the 0xinsider Developer API: Polymarket sports and esports analytics, trader grades, large trades and sharp-money flow."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.9"
13
+ authors = [{ name = "0xinsider", email = "support@0xinsider.com" }]
14
+ keywords = ["0xinsider", "polymarket", "prediction markets", "sports analytics", "api", "sdk"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Developers",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3",
20
+ "Typing :: Typed",
21
+ ]
22
+ dependencies = ["httpx>=0.27,<1"]
23
+
24
+ [project.urls]
25
+ Homepage = "https://0xinsider.com/developers"
26
+ Documentation = "https://docs.0xinsider.com"
27
+ Repository = "https://github.com/0xinsider/0xinsider-python"
28
+ Issues = "https://github.com/0xinsider/0xinsider-python/issues"
29
+ "OpenAPI" = "https://0xinsider.com/api/v1/openapi.json"
30
+
31
+ [tool.hatch.version]
32
+ path = "src/oxinsider/_version.py"
33
+
34
+ [tool.hatch.build.targets.wheel]
35
+ packages = ["src/oxinsider"]
36
+
37
+ [tool.ruff]
38
+ target-version = "py39"
39
+ line-length = 120
40
+
41
+ [tool.ruff.lint]
42
+ select = ["E", "F", "W", "B", "UP"]
43
+
44
+ [tool.ruff.lint.per-file-ignores]
45
+ # Generated: docstrings quote the OpenAPI descriptions verbatim.
46
+ "src/oxinsider/_operations.py" = ["E501"]
47
+ "scripts/generate.py" = ["E501"]
@@ -0,0 +1,177 @@
1
+ """Generate src/oxinsider/_operations.py from the published 0xinsider OpenAPI document.
2
+
3
+ Usage: python scripts/generate.py [path-or-url]
4
+ Default source: https://0xinsider.com/api/v1/openapi.json
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import keyword
11
+ import re
12
+ import sys
13
+ import textwrap
14
+ import urllib.request
15
+ from pathlib import Path
16
+
17
+ DEFAULT_SOURCE = "https://0xinsider.com/api/v1/openapi.json"
18
+ OUTPUT = Path(__file__).resolve().parent.parent / "src" / "oxinsider" / "_operations.py"
19
+ METHODS = ("get", "post", "put", "patch", "delete")
20
+ # Operations whose success response is a Server-Sent Events stream. They are
21
+ # reachable through Client.request(..., stream=True), not a generated method.
22
+ STREAMING_CONTENT = "text/event-stream"
23
+
24
+
25
+ def load(source: str) -> dict:
26
+ if source.startswith("http://") or source.startswith("https://"):
27
+ request = urllib.request.Request(source, headers={"User-Agent": "0xinsider-python-generator"})
28
+ with urllib.request.urlopen(request, timeout=60) as response: # noqa: S310 - fixed https source
29
+ return json.load(response)
30
+ return json.loads(Path(source).read_text())
31
+
32
+
33
+ def snake(name: str) -> str:
34
+ name = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name)
35
+ name = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", name)
36
+ return name.lower()
37
+
38
+
39
+ def python_name(name: str) -> str:
40
+ candidate = re.sub(r"[^0-9a-zA-Z_]", "_", name.replace("[]", ""))
41
+ if keyword.iskeyword(candidate) or candidate in {"self", "body", "headers"}:
42
+ candidate += "_"
43
+ return candidate
44
+
45
+
46
+ def first_sentence(text: str, limit: int = 300) -> str:
47
+ text = " ".join((text or "").split())
48
+ if len(text) <= limit:
49
+ return text
50
+ cut = text[:limit]
51
+ return cut[: cut.rfind(" ")] + " ..."
52
+
53
+
54
+ def success_content_types(operation: dict) -> list[str]:
55
+ for code in ("200", "201", "202"):
56
+ response = operation.get("responses", {}).get(code)
57
+ if isinstance(response, dict):
58
+ return list((response.get("content") or {}).keys())
59
+ return []
60
+
61
+
62
+ def generate(doc: dict) -> str:
63
+ entries = []
64
+ methods = []
65
+ for path, item in doc.get("paths", {}).items():
66
+ shared_params = item.get("parameters", [])
67
+ for method in METHODS:
68
+ operation = item.get(method)
69
+ if not isinstance(operation, dict):
70
+ continue
71
+ operation_id = operation.get("operationId")
72
+ if not operation_id:
73
+ continue
74
+ params = [*shared_params, *operation.get("parameters", [])]
75
+ seen = set()
76
+ unique = []
77
+ for param in params:
78
+ if "$ref" in param or param.get("name", "").endswith("[]"):
79
+ continue
80
+ key = (param.get("in"), param.get("name"))
81
+ if key in seen:
82
+ continue
83
+ seen.add(key)
84
+ unique.append(param)
85
+ path_params = [p for p in unique if p.get("in") == "path"]
86
+ query_params = [p for p in unique if p.get("in") == "query"]
87
+ header_params = [p for p in unique if p.get("in") == "header"]
88
+ has_body = "requestBody" in operation
89
+ content_types = success_content_types(operation)
90
+ streaming = content_types == [STREAMING_CONTENT]
91
+ entries.append(
92
+ {
93
+ "operation_id": operation_id,
94
+ "method": method.upper(),
95
+ "path": path,
96
+ "streaming": streaming,
97
+ }
98
+ )
99
+ if streaming:
100
+ continue
101
+ name = snake(operation_id)
102
+ args = ["self"]
103
+ args += [f"{python_name(p['name'])}: str" for p in path_params]
104
+ if has_body:
105
+ required = operation["requestBody"].get("required", False)
106
+ args.append("body: Any" if required else "body: Any = None")
107
+ kw = [f"{python_name(p['name'])}: Any = None" for p in query_params]
108
+ for header in header_params:
109
+ hname = header["name"].lower()
110
+ if hname == "if-none-match":
111
+ kw.append("if_none_match: str | None = None")
112
+ elif hname == "idempotency-key":
113
+ kw.append("idempotency_key: str | None = None")
114
+ if kw:
115
+ args.append("*")
116
+ args += kw
117
+ summary = first_sentence(operation.get("summary") or operation_id, 200)
118
+ description = first_sentence(operation.get("description") or "")
119
+ doc_lines = [f"{summary}.".replace("..", "."), "", f"``{method.upper()} {path}`` (operationId ``{operation_id}``)."]
120
+ if description:
121
+ doc_lines += ["", *textwrap.wrap(description, 88)]
122
+ if query_params:
123
+ doc_lines += ["", "Query parameters:"]
124
+ for p in query_params:
125
+ pdesc = first_sentence(p.get("description") or "", 160)
126
+ doc_lines.append(f" {python_name(p['name'])}: {pdesc}".rstrip())
127
+ docstring = "\n ".join(line.replace('"""', "'''") for line in doc_lines)
128
+ path_map = ", ".join(f'"{p["name"]}": {python_name(p["name"])}' for p in path_params)
129
+ query_map = ", ".join(f'"{p["name"]}": {python_name(p["name"])}' for p in query_params)
130
+ header_args = []
131
+ if any(h["name"].lower() == "if-none-match" for h in header_params):
132
+ header_args.append("if_none_match=if_none_match")
133
+ if any(h["name"].lower() == "idempotency-key" for h in header_params):
134
+ header_args.append("idempotency_key=idempotency_key")
135
+ call = [f'"{operation_id}"', f"path_params={{{path_map}}}", f"query={{{query_map}}}"]
136
+ if has_body:
137
+ call.append("body=body")
138
+ call += header_args
139
+ signature = ",\n ".join(args)
140
+ methods.append(
141
+ f" def {name}(\n {signature},\n ) -> Any:\n"
142
+ f' """{docstring}\n """\n'
143
+ f" return self._call({', '.join(call)})\n"
144
+ )
145
+ table = ",\n".join(
146
+ f' "{e["operation_id"]}": Operation("{e["method"]}", "{e["path"]}", streaming={e["streaming"]})'
147
+ for e in entries
148
+ )
149
+ version = doc.get("info", {}).get("version", "unknown")
150
+ header = (
151
+ '"""Generated from the 0xinsider OpenAPI document by scripts/generate.py. Do not edit."""\n\n'
152
+ "from __future__ import annotations\n\n"
153
+ "from typing import Any, NamedTuple\n\n\n"
154
+ f'OPENAPI_VERSION = "{version}"\n\n\n'
155
+ "class Operation(NamedTuple):\n"
156
+ " method: str\n"
157
+ " path: str\n"
158
+ " streaming: bool = False\n\n\n"
159
+ f"OPERATIONS: dict[str, Operation] = {{\n{table},\n}}\n\n\n"
160
+ "class OperationsMixin:\n"
161
+ ' """One method per documented operation. Each returns the decoded JSON body."""\n\n'
162
+ " def _call(self, operation_id: str, **kwargs: Any) -> Any: # pragma: no cover - provided by Client\n"
163
+ " raise NotImplementedError\n\n"
164
+ )
165
+ source = header + "\n".join(methods)
166
+ # Blank docstring lines must not carry the indentation.
167
+ return re.sub(r"[ \t]+\n", "\n", source)
168
+
169
+
170
+ def main() -> None:
171
+ source = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_SOURCE
172
+ OUTPUT.write_text(generate(load(source)))
173
+ print(f"wrote {OUTPUT}")
174
+
175
+
176
+ if __name__ == "__main__":
177
+ main()
@@ -0,0 +1,41 @@
1
+ """Official Python client for the 0xinsider Developer API.
2
+
3
+ https://0xinsider.com/developers
4
+ """
5
+
6
+ from ._client import API_KEY_ENV, NOT_MODIFIED, PRODUCTION_BASE_URL, SANDBOX_BASE_URL, Client
7
+ from ._errors import (
8
+ AuthenticationError,
9
+ BadRequestError,
10
+ NotFoundError,
11
+ OxinsiderApiError,
12
+ OxinsiderConnectionError,
13
+ OxinsiderError,
14
+ PermissionDeniedError,
15
+ RateLimitedError,
16
+ ServerError,
17
+ SubscriptionRequiredError,
18
+ )
19
+ from ._operations import OPENAPI_VERSION, OPERATIONS
20
+ from ._version import __version__
21
+
22
+ __all__ = [
23
+ "API_KEY_ENV",
24
+ "NOT_MODIFIED",
25
+ "OPENAPI_VERSION",
26
+ "OPERATIONS",
27
+ "PRODUCTION_BASE_URL",
28
+ "SANDBOX_BASE_URL",
29
+ "AuthenticationError",
30
+ "BadRequestError",
31
+ "Client",
32
+ "NotFoundError",
33
+ "OxinsiderApiError",
34
+ "OxinsiderConnectionError",
35
+ "OxinsiderError",
36
+ "PermissionDeniedError",
37
+ "RateLimitedError",
38
+ "ServerError",
39
+ "SubscriptionRequiredError",
40
+ "__version__",
41
+ ]