Skip to content

Commit af2e3bf

Browse files
committed
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)
1 parent 50da502 commit af2e3bf

File tree

5 files changed

+43
-44
lines changed

5 files changed

+43
-44
lines changed

dune_client/api/datasets.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,26 +45,26 @@ def list_datasets(
4545
params["type"] = type
4646

4747
response_json = self._get(
48-
route="/v1/datasets",
48+
route="/datasets",
4949
params=params,
5050
)
5151
try:
5252
return DatasetListResponse.from_dict(response_json)
5353
except KeyError as err:
5454
raise DuneError(response_json, "DatasetListResponse", err) from err
5555

56-
def get_dataset(self, slug: str) -> DatasetResponse:
56+
def get_dataset(self, full_name: str) -> DatasetResponse:
5757
"""
5858
https://docs.dune.com/api-reference/datasets/endpoint/get
5959
Retrieve detailed information about a specific dataset.
6060
6161
Args:
62-
slug: The dataset slug (e.g., 'dex.trades')
62+
full_name: The dataset full name (e.g., 'dune.shozaib_khan.aarna')
6363
6464
Returns:
6565
DatasetResponse with full dataset details including columns and metadata
6666
"""
67-
response_json = self._get(route=f"/v1/datasets/{slug}")
67+
response_json = self._get(route=f"/datasets/{full_name}")
6868
try:
6969
return DatasetResponse.from_dict(response_json)
7070
except KeyError as err:

dune_client/api/uploads.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def list_uploads(
4242
UploadListResponse with list of tables and pagination info
4343
"""
4444
response_json = self._get(
45-
route="/v1/uploads",
45+
route="/uploads",
4646
params={
4747
"limit": limit,
4848
"offset": offset,
@@ -78,7 +78,7 @@ def create_table(
7878
UploadCreateResponse with table details
7979
"""
8080
result_json = self._post(
81-
route="/v1/uploads",
81+
route="/uploads",
8282
params={
8383
"namespace": namespace,
8484
"table_name": table_name,
@@ -117,7 +117,7 @@ def upload_csv(
117117
CSVUploadResponse with the created table name
118118
"""
119119
response_json = self._post(
120-
route="/v1/uploads/csv",
120+
route="/uploads/csv",
121121
params={
122122
"table_name": table_name,
123123
"data": data,
@@ -155,7 +155,7 @@ def insert_data(
155155
InsertDataResponse with rows/bytes written
156156
"""
157157
result_json = self._post(
158-
route=f"/v1/uploads/{namespace}/{table_name}/insert",
158+
route=f"/uploads/{namespace}/{table_name}/insert",
159159
headers={"Content-Type": content_type},
160160
data=data,
161161
)
@@ -180,7 +180,7 @@ def clear_table(
180180
Returns:
181181
ClearTableResponse with confirmation message
182182
"""
183-
result_json = self._post(route=f"/v1/uploads/{namespace}/{table_name}/clear")
183+
result_json = self._post(route=f"/uploads/{namespace}/{table_name}/clear")
184184
try:
185185
return ClearTableResponse.from_dict(result_json)
186186
except KeyError as err:
@@ -202,7 +202,7 @@ def delete_table(
202202
Returns:
203203
DeleteTableResponse with confirmation message
204204
"""
205-
response_json = self._delete(route=f"/v1/uploads/{namespace}/{table_name}")
205+
response_json = self._delete(route=f"/uploads/{namespace}/{table_name}")
206206
try:
207207
return DeleteTableResponse.from_dict(response_json)
208208
except KeyError as err:

dune_client/models.py

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,8 @@ class DatasetType(Enum):
541541
class DatasetOwner(DataClassJsonMixin):
542542
"""Owner information for a dataset"""
543543

544-
id: int
545544
handle: str
545+
type: str
546546

547547

548548
@dataclass
@@ -551,17 +551,18 @@ class DatasetColumn(DataClassJsonMixin):
551551

552552
name: str
553553
type: str
554+
nullable: bool
554555

555556

556557
@dataclass
557558
class Dataset(DataClassJsonMixin):
558559
"""Dataset information returned by list datasets endpoint"""
559560

560-
slug: str
561-
name: str
561+
full_name: str
562562
type: str
563563
owner: DatasetOwner
564-
namespace: str
564+
columns: list[DatasetColumn]
565+
metadata: dict[str, str]
565566
created_at: str
566567
updated_at: str
567568
is_private: bool
@@ -577,15 +578,13 @@ class DatasetListResponse(DataClassJsonMixin):
577578

578579
@dataclass
579580
class DatasetResponse(DataClassJsonMixin):
580-
"""Response from GET /v1/datasets/{slug}"""
581+
"""Response from GET /v1/datasets/{full_name}"""
581582

582-
slug: str
583-
name: str
583+
full_name: str
584584
type: str
585585
owner: DatasetOwner
586-
namespace: str
587586
columns: list[DatasetColumn]
588-
description: str | None
587+
metadata: dict[str, str]
589588
created_at: str
590589
updated_at: str
591590
is_private: bool
@@ -595,8 +594,8 @@ class DatasetResponse(DataClassJsonMixin):
595594
class TableOwner(DataClassJsonMixin):
596595
"""Owner information for an uploaded table"""
597596

598-
id: int
599597
handle: str
598+
type: str
600599

601600

602601
@dataclass
@@ -605,24 +604,20 @@ class TableColumn(DataClassJsonMixin):
605604

606605
name: str
607606
type: str
607+
nullable: bool
608608

609609

610610
@dataclass
611611
class TableElement(DataClassJsonMixin):
612612
"""Individual table metadata in list response"""
613613

614-
namespace: str
615-
table_name: str
616614
full_name: str
617-
example_query: str
618-
description: str | None
619615
is_private: bool
620-
columns: list[TableColumn]
621-
size_bytes: int
622-
row_count: int
623-
owner: TableOwner
616+
table_size_bytes: str
624617
created_at: str
625618
updated_at: str
619+
owner: TableOwner
620+
columns: list[TableColumn]
626621

627622

628623
@dataclass
@@ -677,7 +672,7 @@ class InsertDataResponse(DataClassJsonMixin):
677672

678673
rows_written: int
679674
bytes_written: int
680-
table_name: str
675+
name: str
681676

682677

683678
@dataclass

tests/e2e/test_datasets_integration.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def setUp(self) -> None:
1717
self.dune = DuneClient()
1818

1919
def test_list_datasets(self):
20-
result = self.dune.list_datasets(limit=10, offset=0)
20+
result = self.dune.list_datasets(limit=10, offset=0, type="uploaded_table")
2121

2222
self.assertIsInstance(result, DatasetListResponse)
2323
self.assertIsInstance(result.datasets, list)
@@ -26,11 +26,10 @@ def test_list_datasets(self):
2626

2727
if len(result.datasets) > 0:
2828
dataset = result.datasets[0]
29-
self.assertIsNotNone(dataset.slug)
30-
self.assertIsNotNone(dataset.name)
29+
self.assertIsNotNone(dataset.full_name)
3130
self.assertIsNotNone(dataset.type)
3231
self.assertIsNotNone(dataset.owner)
33-
self.assertIsNotNone(dataset.namespace)
32+
self.assertIsNotNone(dataset.columns)
3433

3534
def test_list_datasets_with_filters(self):
3635
result = self.dune.list_datasets(
@@ -59,21 +58,25 @@ def test_list_datasets_by_owner(self):
5958
self.assertEqual(dataset.owner.handle, "dune")
6059

6160
def test_get_dataset(self):
62-
result = self.dune.get_dataset("dex.trades")
61+
result_list = self.dune.list_datasets(limit=1, type="uploaded_table")
62+
if len(result_list.datasets) == 0:
63+
self.skipTest("No uploaded tables found to test")
64+
65+
full_name = result_list.datasets[0].full_name
66+
result = self.dune.get_dataset(full_name)
6367

6468
self.assertIsInstance(result, DatasetResponse)
65-
self.assertEqual(result.slug, "dex.trades")
66-
self.assertIsNotNone(result.name)
69+
self.assertEqual(result.full_name, full_name)
6770
self.assertIsNotNone(result.type)
6871
self.assertIsNotNone(result.owner)
69-
self.assertIsNotNone(result.namespace)
7072
self.assertIsNotNone(result.columns)
7173
self.assertIsInstance(result.columns, list)
7274
self.assertGreater(len(result.columns), 0)
7375

7476
column = result.columns[0]
7577
self.assertIsNotNone(column.name)
7678
self.assertIsNotNone(column.type)
79+
self.assertIsNotNone(column.nullable)
7780

7881
def test_get_dataset_with_uploaded_table(self):
7982
result_list = self.dune.list_datasets(
@@ -82,11 +85,11 @@ def test_get_dataset_with_uploaded_table(self):
8285
)
8386

8487
if len(result_list.datasets) > 0:
85-
slug = result_list.datasets[0].slug
86-
result = self.dune.get_dataset(slug)
88+
full_name = result_list.datasets[0].full_name
89+
result = self.dune.get_dataset(full_name)
8790

8891
self.assertIsInstance(result, DatasetResponse)
89-
self.assertEqual(result.slug, slug)
92+
self.assertEqual(result.full_name, full_name)
9093
self.assertEqual(result.type, "uploaded_table")
9194

9295

tests/e2e/test_uploads_integration.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import unittest
23
from io import BytesIO
34

@@ -23,12 +24,12 @@ class TestUploadsIntegration(unittest.TestCase):
2324

2425
def setUp(self) -> None:
2526
self.dune = DuneClient()
26-
self.test_namespace = "test"
27+
self.test_namespace = os.getenv("DUNE_NAMESPACE", "test")
2728
self.test_table_name = f"test_uploads_api_{int(__import__('time').time())}"
2829

2930
def test_create_and_delete_table(self):
3031
schema = [
31-
{"name": "id", "type": "int"},
32+
{"name": "id", "type": "integer"},
3233
{"name": "name", "type": "varchar"},
3334
{"name": "value", "type": "double"},
3435
]
@@ -70,7 +71,7 @@ def test_upload_csv_and_delete(self):
7071

7172
delete_result = self.dune.delete_table(
7273
namespace=self.test_namespace,
73-
table_name=self.test_table_name,
74+
table_name=f"dataset_{self.test_table_name}",
7475
)
7576
self.assertIsInstance(delete_result, DeleteTableResponse)
7677

@@ -82,7 +83,7 @@ def test_list_uploads(self):
8283

8384
def test_full_table_lifecycle(self):
8485
schema = [
85-
{"name": "id", "type": "int"},
86+
{"name": "id", "type": "integer"},
8687
{"name": "message", "type": "varchar"},
8788
]
8889

0 commit comments

Comments
 (0)