Skip to content

Commit 3dacf5e

Browse files
authored
Add modern Uploads and Datasets APIs, deprecate legacy Table API (#187)
* Add modern Uploads and Datasets APIs, deprecate legacy Table API This commit introduces the modern /v1/uploads and /v1/datasets API endpoints while maintaining backward compatibility with the legacy /table endpoints. Changes: - Add UploadsAPI with /v1/uploads/* endpoints for table management - Add DatasetsAPI with /v1/datasets/* endpoints for dataset discovery - Deprecate all TableAPI methods with migration guidance - Add comprehensive response models for new APIs - Update ExtendedAPI to include new APIs with proper MRO - Add unit and E2E tests for new functionality - Configure ruff to allow unittest-style assertions in tests All existing TableAPI methods remain functional but emit deprecation warnings pointing users to the new UploadsAPI methods. * Fix API routes and response models for Uploads and Datasets APIs - Remove double /v1 prefix from all routes (api_version already includes it) - Update Dataset models to match actual API responses (full_name instead of slug/namespace) - Update Table models to match actual API responses (full_name format) - Change owner from id to handle+type fields - Add nullable field to column models - Change InsertDataResponse to use 'name' field instead of 'table_name' - Update datasets integration tests to use full_name and required filters - Update uploads integration tests to use DUNE_NAMESPACE env var and handle CSV upload naming - Fix column types in test schemas (int -> integer) * Update unit test mocks to match new API response structure - Change Dataset mocks to use full_name instead of slug/namespace - Update owner structure to use handle+type instead of id+handle - Add nullable field to all column mocks - Change metadata from description field to dict - Update TableElement mocks to use full_name format - Change InsertDataResponse mock to use 'name' instead of 'table_name' - Fix all route expectations to remove /v1 prefix (already in api_version) * Fix formatting in test_datasets_api.py * Make next_offset optional in UploadListResponse
1 parent 9f69ac7 commit 3dacf5e

File tree

11 files changed

+1022
-4
lines changed

11 files changed

+1022
-4
lines changed

.github/workflows/pull-request.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,5 @@ jobs:
4545
- name: Run E2E tests (Python 3.13)
4646
env:
4747
DUNE_API_KEY: ${{ secrets.DUNE_API_KEY }}
48+
DUNE_API_KEY_OWNER_HANDLE: ${{ secrets.DUNE_API_KEY_OWNER_HANDLE }}
4849
run: uv run --python 3.13 --dev python -m pytest tests/e2e -v
49-

dune_client/api/datasets.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""
2+
Datasets API endpoints for dataset discovery via /v1/datasets/*
3+
"""
4+
5+
from __future__ import annotations
6+
7+
from dune_client.api.base import BaseRouter
8+
from dune_client.models import DatasetListResponse, DatasetResponse, DuneError
9+
10+
11+
class DatasetsAPI(BaseRouter):
12+
"""
13+
Implementation of Datasets endpoints
14+
https://docs.dune.com/api-reference/datasets/
15+
"""
16+
17+
def list_datasets(
18+
self,
19+
limit: int = 50,
20+
offset: int = 0,
21+
owner_handle: str | None = None,
22+
type: str | None = None,
23+
) -> DatasetListResponse:
24+
"""
25+
https://docs.dune.com/api-reference/datasets/endpoint/list
26+
Retrieve a paginated list of datasets with optional filtering.
27+
28+
Args:
29+
limit: Maximum number of datasets to return (max 250)
30+
offset: Pagination offset
31+
owner_handle: Optional filter by owner handle
32+
type: Optional filter by dataset type (transformation_view, transformation_table,
33+
uploaded_table, decoded_table, spell, dune_table)
34+
35+
Returns:
36+
DatasetListResponse with list of datasets and total count
37+
"""
38+
params: dict[str, int | str] = {
39+
"limit": limit,
40+
"offset": offset,
41+
}
42+
if owner_handle is not None:
43+
params["owner_handle"] = owner_handle
44+
if type is not None:
45+
params["type"] = type
46+
47+
response_json = self._get(
48+
route="/datasets",
49+
params=params,
50+
)
51+
try:
52+
return DatasetListResponse.from_dict(response_json)
53+
except KeyError as err:
54+
raise DuneError(response_json, "DatasetListResponse", err) from err
55+
56+
def get_dataset(self, full_name: str) -> DatasetResponse:
57+
"""
58+
https://docs.dune.com/api-reference/datasets/endpoint/get
59+
Retrieve detailed information about a specific dataset.
60+
61+
Args:
62+
full_name: The dataset full name (e.g., 'dune.shozaib_khan.aarna')
63+
64+
Returns:
65+
DatasetResponse with full dataset details including columns and metadata
66+
"""
67+
response_json = self._get(route=f"/datasets/{full_name}")
68+
try:
69+
return DatasetResponse.from_dict(response_json)
70+
except KeyError as err:
71+
raise DuneError(response_json, "DatasetResponse", err) from err

dune_client/api/extensions.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
MAX_NUM_ROWS_PER_BATCH,
1717
)
1818
from dune_client.api.custom import CustomEndpointAPI
19+
from dune_client.api.datasets import DatasetsAPI
1920
from dune_client.api.execution import ExecutionAPI
2021
from dune_client.api.pipeline import PipelineAPI
2122
from dune_client.api.query import QueryAPI
2223
from dune_client.api.table import TableAPI
24+
from dune_client.api.uploads import UploadsAPI
2325
from dune_client.api.usage import UsageAPI
2426
from dune_client.models import (
2527
DuneError,
@@ -40,10 +42,26 @@
4042
POLL_FREQUENCY_SECONDS = 1
4143

4244

43-
class ExtendedAPI(ExecutionAPI, QueryAPI, TableAPI, UsageAPI, CustomEndpointAPI, PipelineAPI):
45+
class ExtendedAPI( # type: ignore[misc]
46+
ExecutionAPI,
47+
QueryAPI,
48+
UploadsAPI,
49+
DatasetsAPI,
50+
TableAPI,
51+
UsageAPI,
52+
CustomEndpointAPI,
53+
PipelineAPI,
54+
):
4455
"""
4556
Provides higher level helper methods for faster
4657
and easier development on top of the base ExecutionAPI.
58+
59+
Includes both legacy TableAPI (deprecated) and modern UploadsAPI/DatasetsAPI.
60+
UploadsAPI is listed before TableAPI in the MRO to ensure modern methods
61+
take precedence over deprecated ones with the same name.
62+
63+
Note: TableAPI has incompatible method signatures with UploadsAPI but is
64+
kept for backward compatibility. The UploadsAPI methods take precedence.
4765
"""
4866

4967
def run_query(

dune_client/api/table.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
"""
22
Table API endpoints enables users to
33
create and insert data into Dune.
4+
5+
DEPRECATED: This API uses legacy /table/* routes.
6+
Please use UploadsAPI for the modern /v1/uploads/* endpoints instead.
47
"""
58

69
from __future__ import annotations
710

811
from typing import IO
912

13+
from deprecated import deprecated
14+
1015
from dune_client.api.base import BaseRouter
1116
from dune_client.models import (
1217
ClearTableResult,
@@ -21,8 +26,15 @@ class TableAPI(BaseRouter):
2126
"""
2227
Implementation of Table endpoints - Plus subscription only
2328
https://docs.dune.com/api-reference/tables/
29+
30+
DEPRECATED: This API uses legacy /table/* routes.
31+
Please use UploadsAPI for the modern /v1/uploads/* endpoints instead.
2432
"""
2533

34+
@deprecated(
35+
version="1.9.0",
36+
reason="Use UploadsAPI.upload_csv() instead. This method uses legacy /table/* routes.",
37+
)
2638
def upload_csv(
2739
self,
2840
table_name: str,
@@ -54,6 +66,10 @@ def upload_csv(
5466
except KeyError as err:
5567
raise DuneError(response_json, "UploadCsvResponse", err) from err
5668

69+
@deprecated(
70+
version="1.9.0",
71+
reason="Use UploadsAPI.create_table() instead. This method uses legacy /table/* routes.",
72+
)
5773
def create_table(
5874
self,
5975
namespace: str,
@@ -87,6 +103,10 @@ def create_table(
87103
except KeyError as err:
88104
raise DuneError(result_json, "CreateTableResult", err) from err
89105

106+
@deprecated(
107+
version="1.9.0",
108+
reason="Use UploadsAPI.insert_data() instead. This method uses legacy /table/* routes.",
109+
)
90110
def insert_table(
91111
self,
92112
namespace: str,
@@ -113,6 +133,10 @@ def insert_table(
113133
except KeyError as err:
114134
raise DuneError(result_json, "InsertTableResult", err) from err
115135

136+
@deprecated(
137+
version="1.9.0",
138+
reason="Use UploadsAPI.clear_table() instead. This method uses legacy /table/* routes.",
139+
)
116140
def clear_data(self, namespace: str, table_name: str) -> ClearTableResult:
117141
"""
118142
https://docs.dune.com/api-reference/tables/endpoint/clear
@@ -126,6 +150,10 @@ def clear_data(self, namespace: str, table_name: str) -> ClearTableResult:
126150
except KeyError as err:
127151
raise DuneError(result_json, "ClearTableResult", err) from err
128152

153+
@deprecated(
154+
version="1.9.0",
155+
reason="Use UploadsAPI.delete_table() instead. This method uses legacy /table/* routes.",
156+
)
129157
def delete_table(self, namespace: str, table_name: str) -> DeleteTableResult:
130158
"""
131159
https://docs.dune.com/api-reference/tables/endpoint/delete

0 commit comments

Comments
 (0)