pyth-pandas 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.
Files changed (32) hide show
  1. pyth_pandas-0.1.0/PKG-INFO +213 -0
  2. pyth_pandas-0.1.0/README.md +169 -0
  3. pyth_pandas-0.1.0/explorer/__init__.py +0 -0
  4. pyth_pandas-0.1.0/explorer/app.py +14 -0
  5. pyth_pandas-0.1.0/explorer/home.py +30 -0
  6. pyth_pandas-0.1.0/explorer/pages/1_latest_prices.py +46 -0
  7. pyth_pandas-0.1.0/explorer/pages/2_guardian_set_upgrade.py +18 -0
  8. pyth_pandas-0.1.0/pyproject.toml +89 -0
  9. pyth_pandas-0.1.0/pyth_pandas/__init__.py +37 -0
  10. pyth_pandas-0.1.0/pyth_pandas/async_client.py +96 -0
  11. pyth_pandas-0.1.0/pyth_pandas/async_ws.py +137 -0
  12. pyth_pandas-0.1.0/pyth_pandas/client.py +217 -0
  13. pyth_pandas-0.1.0/pyth_pandas/exceptions.py +33 -0
  14. pyth_pandas-0.1.0/pyth_pandas/mcp_server.py +72 -0
  15. pyth_pandas-0.1.0/pyth_pandas/mixins/__init__.py +6 -0
  16. pyth_pandas-0.1.0/pyth_pandas/mixins/_governance.py +26 -0
  17. pyth_pandas-0.1.0/pyth_pandas/mixins/_prices.py +258 -0
  18. pyth_pandas-0.1.0/pyth_pandas/py.typed +0 -0
  19. pyth_pandas-0.1.0/pyth_pandas/schemas.py +53 -0
  20. pyth_pandas-0.1.0/pyth_pandas/types.py +77 -0
  21. pyth_pandas-0.1.0/pyth_pandas/utils.py +385 -0
  22. pyth_pandas-0.1.0/pyth_pandas/ws.py +191 -0
  23. pyth_pandas-0.1.0/pyth_pandas.egg-info/PKG-INFO +213 -0
  24. pyth_pandas-0.1.0/pyth_pandas.egg-info/SOURCES.txt +30 -0
  25. pyth_pandas-0.1.0/pyth_pandas.egg-info/dependency_links.txt +1 -0
  26. pyth_pandas-0.1.0/pyth_pandas.egg-info/entry_points.txt +3 -0
  27. pyth_pandas-0.1.0/pyth_pandas.egg-info/requires.txt +28 -0
  28. pyth_pandas-0.1.0/pyth_pandas.egg-info/top_level.txt +2 -0
  29. pyth_pandas-0.1.0/setup.cfg +4 -0
  30. pyth_pandas-0.1.0/tests/test_async_unit.py +65 -0
  31. pyth_pandas-0.1.0/tests/test_integration.py +59 -0
  32. pyth_pandas-0.1.0/tests/test_unit.py +201 -0
@@ -0,0 +1,213 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyth-pandas
3
+ Version: 0.1.0
4
+ Summary: pandas-style client for the Pyth Pro Router (Pyth Lazer) REST + WebSocket API
5
+ License-Expression: Apache-2.0
6
+ Project-URL: Homepage, https://github.com/sigma-quantiphi/pyth-pandas
7
+ Project-URL: Documentation, https://sigma-quantiphi.github.io/pyth-pandas/
8
+ Project-URL: Issues, https://github.com/sigma-quantiphi/pyth-pandas/issues
9
+ Keywords: api-client,pandas,pyth,lazer,oracle,price-feeds
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: <3.14,>=3.11
19
+ Description-Content-Type: text/markdown
20
+ Requires-Dist: cachetools>=5.3
21
+ Requires-Dist: httpx>=0.28
22
+ Requires-Dist: orjson>=3.10
23
+ Requires-Dist: pandas>=2.2
24
+ Requires-Dist: pandera>=0.22
25
+ Requires-Dist: tqdm>=4.66
26
+ Provides-Extra: ws
27
+ Requires-Dist: websocket-client>=1.8; extra == "ws"
28
+ Requires-Dist: websockets>=13.0; extra == "ws"
29
+ Provides-Extra: explorer
30
+ Requires-Dist: streamlit>=1.30; extra == "explorer"
31
+ Requires-Dist: plotly>=5.0; extra == "explorer"
32
+ Provides-Extra: mcp
33
+ Requires-Dist: fastmcp>=2.0; extra == "mcp"
34
+ Requires-Dist: tabulate>=0.9; extra == "mcp"
35
+ Provides-Extra: dev
36
+ Requires-Dist: pytest>=8.0; extra == "dev"
37
+ Requires-Dist: pytest-httpx>=0.35; extra == "dev"
38
+ Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
39
+ Requires-Dist: ruff>=0.9; extra == "dev"
40
+ Requires-Dist: mypy>=1.11; extra == "dev"
41
+ Requires-Dist: pandas-stubs>=2.2; extra == "dev"
42
+ Requires-Dist: types-cachetools>=5.3; extra == "dev"
43
+ Requires-Dist: python-dotenv>=1.0; extra == "dev"
44
+
45
+ # pyth-pandas
46
+
47
+ > pandas-style client for the Pyth Pro Router (Pyth Lazer) REST + WebSocket API
48
+
49
+ [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/sigma-quantiphi/pyth-pandas/HEAD?labpath=examples)
50
+
51
+ Every list endpoint returns a `pandas.DataFrame`, every dict endpoint returns
52
+ a `TypedDict`, and every shape is enforced by a `pandera` schema. Sync + async,
53
+ plus optional WebSocket, Streamlit explorer, and FastMCP server extras.
54
+
55
+ This client targets **Pyth Pro Router API v1.0.0** (per the published OpenAPI
56
+ spec). The package version (`0.1.0`) is independent of the upstream API
57
+ version — see the `API_VERSION` / `SUPPORTED_API_VERSIONS` class attributes
58
+ on `PythPandas`.
59
+
60
+ ## Install
61
+
62
+ ```bash
63
+ uv pip install pyth-pandas # core
64
+ uv pip install "pyth-pandas[ws]" # + WebSocket
65
+ uv pip install "pyth-pandas[explorer]" # + Streamlit dashboard
66
+ uv pip install "pyth-pandas[mcp]" # + FastMCP server
67
+ uv pip install "pyth-pandas[dev]" # + test/lint toolchain
68
+ ```
69
+
70
+ ## Quickstart
71
+
72
+ ```python
73
+ from pyth_pandas import PythPandas
74
+
75
+ with PythPandas() as client:
76
+ df = client.fetch_latest_prices(
77
+ symbols=["Crypto.BTC/USD", "Crypto.ETH/USD"],
78
+ properties=["price", "confidence", "exponent", "publisherCount"],
79
+ formats=[],
80
+ )
81
+ df["humanPrice"] = df["price"] * 10 ** df["exponent"]
82
+ print(df[["priceFeedId", "humanPrice", "publisherCount"]])
83
+ ```
84
+
85
+ The DataFrame has one row per feed. The on-chain payloads (when
86
+ requested via `formats=["evm", ...]`) and the update timestamp are
87
+ attached on `df.attrs`. For the raw `JsonUpdate` dict, use
88
+ `fetch_latest_prices_raw(...)`.
89
+
90
+ ### Async
91
+
92
+ ```python
93
+ import asyncio
94
+ from pyth_pandas import AsyncPythPandas
95
+
96
+ async def main():
97
+ async with AsyncPythPandas() as client:
98
+ df = await client.fetch_latest_prices(
99
+ symbols=["Crypto.BTC/USD"],
100
+ properties=["price", "exponent"],
101
+ formats=[],
102
+ )
103
+ print(df)
104
+
105
+ asyncio.run(main())
106
+ ```
107
+
108
+ ## Authentication
109
+
110
+ Pyth Pro requires a bearer access token. Set it via env var (recommended) or
111
+ constructor arg. Copy the shipped `.env.example` to `.env` and fill in your
112
+ key — examples and tests load it via `python-dotenv`:
113
+
114
+ ```bash
115
+ cp .env.example .env
116
+ $EDITOR .env # set PYTH_API_KEY=...
117
+ ```
118
+
119
+ Or set it in your shell:
120
+
121
+ ```bash
122
+ export PYTH_API_KEY=...
123
+ ```
124
+
125
+ Or pass it directly:
126
+
127
+ ```python
128
+ PythPandas(api_key="...")
129
+ ```
130
+
131
+ ## Endpoints
132
+
133
+ | Method | HTTP | Returns |
134
+ |---|---|---|
135
+ | `fetch_latest_prices(...)` | `POST /v1/latest_price` | `DataFrame[ParsedFeedSchema]` |
136
+ | `fetch_latest_prices_raw(...)` | `POST /v1/latest_price` | `JsonUpdate` (TypedDict) |
137
+ | `fetch_prices(timestamp=..., ...)` | `POST /v1/price` | `DataFrame[ParsedFeedSchema]` |
138
+ | `fetch_prices_raw(...)` | `POST /v1/price` | `JsonUpdate` |
139
+ | `reduce_price(payload=..., price_feed_ids=...)` | `POST /v1/reduce_price` | `DataFrame[ParsedFeedSchema]` |
140
+ | `reduce_price_raw(...)` | `POST /v1/reduce_price` | `JsonUpdate` |
141
+ | `get_guardian_set_upgrade()` | `GET /v1/guardian_set_upgrade` | `SignedGuardianSetUpgrade \| None` |
142
+
143
+ WebSocket: `PythWebSocket` / `AsyncPythWebSocket` (extra: `ws`) → connects
144
+ to `wss://pyth-lazer.dourolabs.app/v1/stream`.
145
+
146
+ ## Compatibility
147
+
148
+ | pyth-pandas | Pyth Pro Router API |
149
+ |---|---|
150
+ | 0.1.x | 1.0.0 |
151
+
152
+ ## Error handling
153
+
154
+ ```python
155
+ from pyth_pandas import PythAuthError, PythRateLimitError, PythAPIError
156
+
157
+ try:
158
+ df = client.fetch_latest_prices(symbols=["Crypto.BTC/USD"], properties=["price"])
159
+ except PythAuthError:
160
+ ... # 401/403 or missing PYTH_API_KEY
161
+ except PythRateLimitError:
162
+ ... # 429
163
+ except PythAPIError as e:
164
+ print(e.status_code, e.url, e.detail)
165
+ ```
166
+
167
+ ## Development
168
+
169
+ ```bash
170
+ uv pip install -e ".[dev,ws,explorer,mcp]"
171
+ uv run pytest tests/test_unit.py tests/test_async_unit.py -v
172
+ uv run ruff check pyth_pandas tests
173
+ uv run mypy pyth_pandas
174
+ ```
175
+
176
+ CI runs the same checks on every push and PR via `.github/workflows/ci.yml`
177
+ across Python 3.11, 3.12, 3.13.
178
+
179
+ ## Releasing
180
+
181
+ Releases are cut by pushing a `v*` tag. `.github/workflows/release.yml`:
182
+
183
+ 1. Runs ruff + mypy + mocked pytest, then **live integration tests** against
184
+ the real upstream API. If the test job fails, build / publish / release
185
+ are all skipped.
186
+ 2. Builds sdist + wheel via `uv build`.
187
+ 3. Publishes to PyPI via [trusted publishing](https://docs.pypi.org/trusted-publishers/).
188
+ 4. Creates a GitHub release.
189
+
190
+ **One-time setup:**
191
+
192
+ 1. Reserve `pyth-pandas` on PyPI.
193
+ 2. At <https://pypi.org/manage/account/publishing/>, add a pending publisher:
194
+ - Project: `pyth-pandas`
195
+ - Owner: your GitHub user/org
196
+ - Repo: `pyth-pandas`
197
+ - Workflow: `release.yml`
198
+ - Environment: `pypi`
199
+ 3. Create the `pypi` environment in GitHub repo settings.
200
+ 4. Add `PYTH_API_KEY` as an environment secret on the `pypi` environment so
201
+ live integration tests can run before publishing.
202
+ 5. Enable GitHub Pages with source = "GitHub Actions" so `docs.yml` can
203
+ deploy the Sphinx site.
204
+
205
+ **To force a release if the test infra is broken:**
206
+
207
+ ```bash
208
+ gh workflow run release.yml -f tag=v0.1.1 -f skip_tests=true
209
+ ```
210
+
211
+ ## License
212
+
213
+ Apache-2.0
@@ -0,0 +1,169 @@
1
+ # pyth-pandas
2
+
3
+ > pandas-style client for the Pyth Pro Router (Pyth Lazer) REST + WebSocket API
4
+
5
+ [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/sigma-quantiphi/pyth-pandas/HEAD?labpath=examples)
6
+
7
+ Every list endpoint returns a `pandas.DataFrame`, every dict endpoint returns
8
+ a `TypedDict`, and every shape is enforced by a `pandera` schema. Sync + async,
9
+ plus optional WebSocket, Streamlit explorer, and FastMCP server extras.
10
+
11
+ This client targets **Pyth Pro Router API v1.0.0** (per the published OpenAPI
12
+ spec). The package version (`0.1.0`) is independent of the upstream API
13
+ version — see the `API_VERSION` / `SUPPORTED_API_VERSIONS` class attributes
14
+ on `PythPandas`.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ uv pip install pyth-pandas # core
20
+ uv pip install "pyth-pandas[ws]" # + WebSocket
21
+ uv pip install "pyth-pandas[explorer]" # + Streamlit dashboard
22
+ uv pip install "pyth-pandas[mcp]" # + FastMCP server
23
+ uv pip install "pyth-pandas[dev]" # + test/lint toolchain
24
+ ```
25
+
26
+ ## Quickstart
27
+
28
+ ```python
29
+ from pyth_pandas import PythPandas
30
+
31
+ with PythPandas() as client:
32
+ df = client.fetch_latest_prices(
33
+ symbols=["Crypto.BTC/USD", "Crypto.ETH/USD"],
34
+ properties=["price", "confidence", "exponent", "publisherCount"],
35
+ formats=[],
36
+ )
37
+ df["humanPrice"] = df["price"] * 10 ** df["exponent"]
38
+ print(df[["priceFeedId", "humanPrice", "publisherCount"]])
39
+ ```
40
+
41
+ The DataFrame has one row per feed. The on-chain payloads (when
42
+ requested via `formats=["evm", ...]`) and the update timestamp are
43
+ attached on `df.attrs`. For the raw `JsonUpdate` dict, use
44
+ `fetch_latest_prices_raw(...)`.
45
+
46
+ ### Async
47
+
48
+ ```python
49
+ import asyncio
50
+ from pyth_pandas import AsyncPythPandas
51
+
52
+ async def main():
53
+ async with AsyncPythPandas() as client:
54
+ df = await client.fetch_latest_prices(
55
+ symbols=["Crypto.BTC/USD"],
56
+ properties=["price", "exponent"],
57
+ formats=[],
58
+ )
59
+ print(df)
60
+
61
+ asyncio.run(main())
62
+ ```
63
+
64
+ ## Authentication
65
+
66
+ Pyth Pro requires a bearer access token. Set it via env var (recommended) or
67
+ constructor arg. Copy the shipped `.env.example` to `.env` and fill in your
68
+ key — examples and tests load it via `python-dotenv`:
69
+
70
+ ```bash
71
+ cp .env.example .env
72
+ $EDITOR .env # set PYTH_API_KEY=...
73
+ ```
74
+
75
+ Or set it in your shell:
76
+
77
+ ```bash
78
+ export PYTH_API_KEY=...
79
+ ```
80
+
81
+ Or pass it directly:
82
+
83
+ ```python
84
+ PythPandas(api_key="...")
85
+ ```
86
+
87
+ ## Endpoints
88
+
89
+ | Method | HTTP | Returns |
90
+ |---|---|---|
91
+ | `fetch_latest_prices(...)` | `POST /v1/latest_price` | `DataFrame[ParsedFeedSchema]` |
92
+ | `fetch_latest_prices_raw(...)` | `POST /v1/latest_price` | `JsonUpdate` (TypedDict) |
93
+ | `fetch_prices(timestamp=..., ...)` | `POST /v1/price` | `DataFrame[ParsedFeedSchema]` |
94
+ | `fetch_prices_raw(...)` | `POST /v1/price` | `JsonUpdate` |
95
+ | `reduce_price(payload=..., price_feed_ids=...)` | `POST /v1/reduce_price` | `DataFrame[ParsedFeedSchema]` |
96
+ | `reduce_price_raw(...)` | `POST /v1/reduce_price` | `JsonUpdate` |
97
+ | `get_guardian_set_upgrade()` | `GET /v1/guardian_set_upgrade` | `SignedGuardianSetUpgrade \| None` |
98
+
99
+ WebSocket: `PythWebSocket` / `AsyncPythWebSocket` (extra: `ws`) → connects
100
+ to `wss://pyth-lazer.dourolabs.app/v1/stream`.
101
+
102
+ ## Compatibility
103
+
104
+ | pyth-pandas | Pyth Pro Router API |
105
+ |---|---|
106
+ | 0.1.x | 1.0.0 |
107
+
108
+ ## Error handling
109
+
110
+ ```python
111
+ from pyth_pandas import PythAuthError, PythRateLimitError, PythAPIError
112
+
113
+ try:
114
+ df = client.fetch_latest_prices(symbols=["Crypto.BTC/USD"], properties=["price"])
115
+ except PythAuthError:
116
+ ... # 401/403 or missing PYTH_API_KEY
117
+ except PythRateLimitError:
118
+ ... # 429
119
+ except PythAPIError as e:
120
+ print(e.status_code, e.url, e.detail)
121
+ ```
122
+
123
+ ## Development
124
+
125
+ ```bash
126
+ uv pip install -e ".[dev,ws,explorer,mcp]"
127
+ uv run pytest tests/test_unit.py tests/test_async_unit.py -v
128
+ uv run ruff check pyth_pandas tests
129
+ uv run mypy pyth_pandas
130
+ ```
131
+
132
+ CI runs the same checks on every push and PR via `.github/workflows/ci.yml`
133
+ across Python 3.11, 3.12, 3.13.
134
+
135
+ ## Releasing
136
+
137
+ Releases are cut by pushing a `v*` tag. `.github/workflows/release.yml`:
138
+
139
+ 1. Runs ruff + mypy + mocked pytest, then **live integration tests** against
140
+ the real upstream API. If the test job fails, build / publish / release
141
+ are all skipped.
142
+ 2. Builds sdist + wheel via `uv build`.
143
+ 3. Publishes to PyPI via [trusted publishing](https://docs.pypi.org/trusted-publishers/).
144
+ 4. Creates a GitHub release.
145
+
146
+ **One-time setup:**
147
+
148
+ 1. Reserve `pyth-pandas` on PyPI.
149
+ 2. At <https://pypi.org/manage/account/publishing/>, add a pending publisher:
150
+ - Project: `pyth-pandas`
151
+ - Owner: your GitHub user/org
152
+ - Repo: `pyth-pandas`
153
+ - Workflow: `release.yml`
154
+ - Environment: `pypi`
155
+ 3. Create the `pypi` environment in GitHub repo settings.
156
+ 4. Add `PYTH_API_KEY` as an environment secret on the `pypi` environment so
157
+ live integration tests can run before publishing.
158
+ 5. Enable GitHub Pages with source = "GitHub Actions" so `docs.yml` can
159
+ deploy the Sphinx site.
160
+
161
+ **To force a release if the test infra is broken:**
162
+
163
+ ```bash
164
+ gh workflow run release.yml -f tag=v0.1.1 -f skip_tests=true
165
+ ```
166
+
167
+ ## License
168
+
169
+ Apache-2.0
File without changes
@@ -0,0 +1,14 @@
1
+ """CLI entry point for the pyth-pandas Streamlit explorer."""
2
+
3
+ import os
4
+ import sys
5
+ from pathlib import Path
6
+
7
+
8
+ def main() -> None:
9
+ home = Path(__file__).parent / "home.py"
10
+ os.execvp("streamlit", ["streamlit", "run", str(home), *sys.argv[1:]])
11
+
12
+
13
+ if __name__ == "__main__":
14
+ main()
@@ -0,0 +1,30 @@
1
+ """pyth-pandas explorer — home page."""
2
+
3
+ import streamlit as st
4
+
5
+ from pyth_pandas import PythPandas
6
+
7
+ st.set_page_config(page_title="pyth-pandas explorer", layout="wide")
8
+
9
+ st.title("pyth-pandas explorer")
10
+ st.caption("Interactive playground for the Pyth Pro Router (Pyth Lazer) API")
11
+
12
+ with st.sidebar:
13
+ st.header("Client config")
14
+ base_url = st.text_input("Base URL", value="https://pyth-lazer.dourolabs.app/v1/")
15
+ api_key = st.text_input("PYTH_API_KEY", value="", type="password")
16
+
17
+ if "client" not in st.session_state or st.sidebar.button("Reload client"):
18
+ st.session_state.client = PythPandas(
19
+ base_url=base_url, api_key=api_key or None, use_tqdm=False
20
+ )
21
+
22
+ st.markdown(
23
+ """
24
+ Pick an endpoint from the sidebar pages on the left.
25
+
26
+ - **Latest prices** — point-in-time snapshot per feed
27
+ - **Historical price** — feed values at a specific timestamp
28
+ - **Guardian set upgrade** — Wormhole governance status
29
+ """
30
+ )
@@ -0,0 +1,46 @@
1
+ """Latest prices explorer page."""
2
+
3
+ import streamlit as st
4
+
5
+ st.title("Latest prices")
6
+
7
+ client = st.session_state.get("client")
8
+ if client is None:
9
+ st.warning("Configure the client on the home page first.")
10
+ st.stop()
11
+
12
+ symbols_text = st.text_input(
13
+ "Symbols (comma-separated)", value="Crypto.BTC/USD, Crypto.ETH/USD"
14
+ )
15
+ symbols = [s.strip() for s in symbols_text.split(",") if s.strip()] or None
16
+
17
+ properties = st.multiselect(
18
+ "Properties",
19
+ [
20
+ "price",
21
+ "confidence",
22
+ "exponent",
23
+ "publisherCount",
24
+ "bestBidPrice",
25
+ "bestAskPrice",
26
+ "emaPrice",
27
+ "emaConfidence",
28
+ "fundingRate",
29
+ "feedUpdateTimestamp",
30
+ ],
31
+ default=["price", "confidence", "exponent", "publisherCount"],
32
+ )
33
+ channel = st.selectbox(
34
+ "Channel",
35
+ ["real_time", "fixed_rate@50ms", "fixed_rate@200ms", "fixed_rate@1000ms"],
36
+ )
37
+
38
+ if st.button("Fetch"):
39
+ with st.spinner("Fetching..."):
40
+ df = client.fetch_latest_prices(
41
+ symbols=symbols,
42
+ properties=properties,
43
+ channel=channel,
44
+ )
45
+ st.dataframe(df, use_container_width=True)
46
+ st.write("attrs:", df.attrs)
@@ -0,0 +1,18 @@
1
+ """Guardian set upgrade status page."""
2
+
3
+ import streamlit as st
4
+
5
+ st.title("Guardian set upgrade")
6
+
7
+ client = st.session_state.get("client")
8
+ if client is None:
9
+ st.warning("Configure the client on the home page first.")
10
+ st.stop()
11
+
12
+ if st.button("Check"):
13
+ with st.spinner("Fetching..."):
14
+ result = client.get_guardian_set_upgrade()
15
+ if result is None:
16
+ st.success("No guardian set upgrade is currently in progress.")
17
+ else:
18
+ st.json(result)
@@ -0,0 +1,89 @@
1
+ [project]
2
+ name = "pyth-pandas"
3
+ version = "0.1.0"
4
+ description = "pandas-style client for the Pyth Pro Router (Pyth Lazer) REST + WebSocket API"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11,<3.14"
7
+ license = "Apache-2.0"
8
+ keywords = ["api-client", "pandas", "pyth", "lazer", "oracle", "price-feeds"]
9
+ classifiers = [
10
+ "Development Status :: 3 - Alpha",
11
+ "Intended Audience :: Developers",
12
+ "Topic :: Software Development :: Libraries :: Python Modules",
13
+ "Programming Language :: Python :: 3",
14
+ "Programming Language :: Python :: 3.11",
15
+ "Programming Language :: Python :: 3.12",
16
+ "Programming Language :: Python :: 3.13",
17
+ "Typing :: Typed",
18
+ ]
19
+
20
+ dependencies = [
21
+ "cachetools>=5.3",
22
+ "httpx>=0.28",
23
+ "orjson>=3.10",
24
+ "pandas>=2.2",
25
+ "pandera>=0.22",
26
+ "tqdm>=4.66",
27
+ ]
28
+
29
+ [project.optional-dependencies]
30
+ ws = [
31
+ "websocket-client>=1.8",
32
+ "websockets>=13.0",
33
+ ]
34
+ explorer = [
35
+ "streamlit>=1.30",
36
+ "plotly>=5.0",
37
+ ]
38
+ mcp = [
39
+ "fastmcp>=2.0",
40
+ "tabulate>=0.9",
41
+ ]
42
+ dev = [
43
+ "pytest>=8.0",
44
+ "pytest-httpx>=0.35",
45
+ "pytest-asyncio>=0.24",
46
+ "ruff>=0.9",
47
+ "mypy>=1.11",
48
+ "pandas-stubs>=2.2",
49
+ "types-cachetools>=5.3",
50
+ "python-dotenv>=1.0",
51
+ ]
52
+
53
+ [project.scripts]
54
+ pyth-pandas-explore = "explorer.app:main"
55
+ pyth-pandas-mcp = "pyth_pandas.mcp_server:main"
56
+
57
+ [project.urls]
58
+ Homepage = "https://github.com/sigma-quantiphi/pyth-pandas"
59
+ Documentation = "https://sigma-quantiphi.github.io/pyth-pandas/"
60
+ Issues = "https://github.com/sigma-quantiphi/pyth-pandas/issues"
61
+
62
+ [build-system]
63
+ requires = ["setuptools>=70"]
64
+ build-backend = "setuptools.build_meta"
65
+
66
+ [tool.setuptools.packages.find]
67
+ include = ["pyth_pandas*", "explorer*"]
68
+
69
+ [tool.setuptools.package-data]
70
+ pyth_pandas = ["py.typed"]
71
+
72
+ [tool.pytest.ini_options]
73
+ testpaths = ["tests"]
74
+ addopts = "-v"
75
+ asyncio_mode = "auto"
76
+
77
+ [tool.ruff]
78
+ target-version = "py311"
79
+ line-length = 100
80
+
81
+ [tool.ruff.lint]
82
+ select = ["E", "F", "I", "UP", "B"]
83
+ ignore = ["B008"]
84
+
85
+ [tool.mypy]
86
+ python_version = "3.11"
87
+ ignore_missing_imports = true
88
+ warn_return_any = false
89
+ warn_unused_ignores = true
@@ -0,0 +1,37 @@
1
+ """pyth-pandas — pandas-style client for the Pyth Pro Router (Pyth Lazer) API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pyth_pandas.async_client import AsyncPythPandas
6
+ from pyth_pandas.client import PythPandas
7
+ from pyth_pandas.exceptions import (
8
+ PythAPIError,
9
+ PythAuthError,
10
+ PythError,
11
+ PythRateLimitError,
12
+ )
13
+ from pyth_pandas.schemas import ParsedFeedSchema
14
+ from pyth_pandas.types import (
15
+ JsonBinaryData,
16
+ JsonUpdate,
17
+ ParsedFeedPayload,
18
+ ParsedPayload,
19
+ SignedGuardianSetUpgrade,
20
+ SignedMerkleRoot,
21
+ )
22
+
23
+ __all__ = [
24
+ "AsyncPythPandas",
25
+ "JsonBinaryData",
26
+ "JsonUpdate",
27
+ "ParsedFeedPayload",
28
+ "ParsedFeedSchema",
29
+ "ParsedPayload",
30
+ "PythAPIError",
31
+ "PythAuthError",
32
+ "PythError",
33
+ "PythPandas",
34
+ "PythRateLimitError",
35
+ "SignedGuardianSetUpgrade",
36
+ "SignedMerkleRoot",
37
+ ]