Skip to content

Commit 2f77665

Browse files
authored
Remove list_tables, consume status error field APP-6033 (#185)
* Consume error message from the status endpoint when available * remove list tables endpoint * fix test * format
1 parent 95a33a7 commit 2f77665

File tree

7 files changed

+10
-163
lines changed

7 files changed

+10
-163
lines changed

dune_client/api/extensions.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,9 @@ def run_sql(
359359

360360
if status.state == ExecutionState.FAILED:
361361
self.logger.error(status)
362-
raise QueryFailedError(f"Error data: {status.error}")
362+
if status.error:
363+
raise QueryFailedError(status.error.message)
364+
raise QueryFailedError("Query execution failed")
363365

364366
# Fetch and return results
365367
return self._fetch_entire_result(self.get_execution_results(job_id))
@@ -434,7 +436,9 @@ def _refresh(
434436
self.logger.warning("Partial result set retrieved.")
435437
if status.state == ExecutionState.FAILED:
436438
self.logger.error(status)
437-
raise QueryFailedError(f"Error data: {status.error}")
439+
if status.error:
440+
raise QueryFailedError(status.error.message)
441+
raise QueryFailedError("Query execution failed")
438442
return job_id
439443

440444
def _fetch_entire_result(

dune_client/api/table.py

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
DeleteTableResult,
1515
DuneError,
1616
InsertTableResult,
17-
ListTablesResponse,
1817
)
1918

2019

@@ -138,34 +137,3 @@ def delete_table(self, namespace: str, table_name: str) -> DeleteTableResult:
138137
return DeleteTableResult.from_dict(response_json)
139138
except KeyError as err:
140139
raise DuneError(response_json, "DeleteTableResult", err) from err
141-
142-
def list_tables(
143-
self,
144-
limit: int | None = None,
145-
offset: int | None = None,
146-
) -> ListTablesResponse:
147-
"""
148-
https://docs.dune.com/api-reference/tables/endpoint/list
149-
Get a paginated list of tables uploaded to Dune.
150-
151-
Args:
152-
limit: Maximum number of tables to return (optional)
153-
offset: Offset for pagination (optional)
154-
155-
Returns:
156-
ListTablesResponse containing list of tables and pagination info
157-
"""
158-
params = {}
159-
if limit is not None:
160-
params["limit"] = limit
161-
if offset is not None:
162-
params["offset"] = offset
163-
164-
response_json = self._get(
165-
route="/tables",
166-
params=params if params else None,
167-
)
168-
try:
169-
return ListTablesResponse.from_dict(response_json)
170-
except KeyError as err:
171-
raise DuneError(response_json, "ListTablesResponse", err) from err

dune_client/client_async.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,9 @@ async def _refresh(
681681
if status.state in terminal_states:
682682
if status.state == ExecutionState.FAILED:
683683
self.logger.error(status)
684-
raise QueryFailedError(f"Error data: {status.error}")
684+
if status.error:
685+
raise QueryFailedError(status.error.message)
686+
raise QueryFailedError("Query execution failed")
685687
return job_id
686688

687689
self.logger.info(f"waiting for query execution {job_id} to complete: {status}")

dune_client/models.py

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -454,58 +454,3 @@ def from_dict(cls, data: dict[str, Any]) -> UsageResponse:
454454
private_dashboards=int(data.get("private_dashboards", 0)),
455455
private_queries=int(data.get("private_queries", 0)),
456456
)
457-
458-
459-
@dataclass
460-
class TableInfo:
461-
"""Information about a single table"""
462-
463-
full_name: str
464-
is_private: bool
465-
created_at: str
466-
# Optional fields that may be present
467-
table_size_bytes: str | None = None
468-
updated_at: str | None = None
469-
470-
@property
471-
def namespace(self) -> str:
472-
"""Extract namespace from full_name (e.g., 'dune.namespace.table' -> 'namespace')"""
473-
parts = self.full_name.split(".")
474-
return parts[1] if len(parts) >= 3 else ""
475-
476-
@property
477-
def table_name(self) -> str:
478-
"""Extract table name from full_name (e.g., 'dune.namespace.table' -> 'table')"""
479-
parts = self.full_name.split(".")
480-
return parts[2] if len(parts) >= 3 else ""
481-
482-
@classmethod
483-
def from_dict(cls, data: dict[str, Any]) -> TableInfo:
484-
"""Constructor from dictionary."""
485-
return cls(
486-
full_name=data["full_name"],
487-
is_private=data["is_private"],
488-
created_at=data["created_at"],
489-
table_size_bytes=data.get("table_size_bytes"),
490-
updated_at=data.get("updated_at"),
491-
)
492-
493-
494-
@dataclass
495-
class ListTablesResponse:
496-
"""
497-
Representation of Response from Dune's [GET] Tables List endpoint
498-
https://docs.dune.com/api-reference/tables/endpoint/list
499-
"""
500-
501-
tables: list[TableInfo]
502-
next_offset: int | None
503-
504-
@classmethod
505-
def from_dict(cls, data: dict[str, Any]) -> ListTablesResponse:
506-
"""Constructor from dictionary."""
507-
tables_data = data.get("tables", [])
508-
return cls(
509-
tables=[TableInfo.from_dict(table) for table in tables_data],
510-
next_offset=data.get("next_offset"),
511-
)

tests/e2e/test_client.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -467,24 +467,6 @@ def test_get_usage_with_dates(self):
467467
# Should have at least one billing period for this date range
468468
assert len(usage.billing_periods) > 0
469469

470-
@unittest.skip("Requires Plus subscription and uploaded tables")
471-
def test_list_tables(self):
472-
"""Test the list_tables endpoint"""
473-
dune = DuneClient()
474-
tables_response = dune.list_tables(limit=10)
475-
# Verify response structure
476-
assert hasattr(tables_response, "tables")
477-
assert hasattr(tables_response, "next_offset")
478-
assert isinstance(tables_response.tables, list)
479-
# If there are tables, verify their structure
480-
if len(tables_response.tables) > 0:
481-
table = tables_response.tables[0]
482-
assert hasattr(table, "namespace")
483-
assert hasattr(table, "table_name")
484-
assert hasattr(table, "full_name")
485-
assert hasattr(table, "created_at")
486-
assert hasattr(table, "is_private")
487-
488470

489471
@unittest.skip("This is an enterprise only endpoint that can no longer be tested.")
490472
class TestCRUDOps(unittest.TestCase):

tests/unit/test_async_client_logic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ async def test_failed_state_raises_query_failed_error(self):
213213
with pytest.raises(QueryFailedError) as exc_info:
214214
await client._refresh(query)
215215

216-
assert "Error data:" in str(exc_info.value)
216+
assert "Query syntax error" in str(exc_info.value)
217217

218218
async def test_completed_state_returns_job_id(self):
219219
"""Test that COMPLETED state returns job_id successfully"""

tests/unit/test_models.py

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@
1616
ExecutionResultCSV,
1717
ExecutionState,
1818
ExecutionStatusResponse,
19-
ListTablesResponse,
2019
ResultMetadata,
2120
ResultsResponse,
22-
TableInfo,
2321
TimeData,
2422
UsageResponse,
2523
)
@@ -351,58 +349,6 @@ def test_usage_response_parsing_with_missing_fields(self):
351349
assert result.private_dashboards == 0
352350
assert result.private_queries == 0
353351

354-
def test_table_info_parsing(self):
355-
"""Test TableInfo parsing from API response"""
356-
response_data = {
357-
"full_name": "dune.my_namespace.my_table",
358-
"created_at": "2024-01-15T10:30:00Z",
359-
"is_private": True,
360-
"table_size_bytes": "1024",
361-
"updated_at": "2024-01-16T10:30:00Z",
362-
}
363-
result = TableInfo.from_dict(response_data)
364-
assert result.full_name == "dune.my_namespace.my_table"
365-
assert result.namespace == "my_namespace"
366-
assert result.table_name == "my_table"
367-
assert result.created_at == "2024-01-15T10:30:00Z"
368-
assert result.is_private is True
369-
assert result.table_size_bytes == "1024"
370-
assert result.updated_at == "2024-01-16T10:30:00Z"
371-
372-
def test_list_tables_response_parsing(self):
373-
"""Test ListTablesResponse parsing from API response"""
374-
response_data = {
375-
"tables": [
376-
{
377-
"full_name": "dune.namespace1.table1",
378-
"created_at": "2024-01-15T10:30:00Z",
379-
"is_private": False,
380-
},
381-
{
382-
"full_name": "dune.namespace2.table2",
383-
"created_at": "2024-01-16T11:30:00Z",
384-
"is_private": True,
385-
},
386-
],
387-
"next_offset": 100,
388-
}
389-
result = ListTablesResponse.from_dict(response_data)
390-
assert len(result.tables) == 2
391-
assert result.tables[0].full_name == "dune.namespace1.table1"
392-
assert result.tables[0].namespace == "namespace1"
393-
assert result.tables[0].table_name == "table1"
394-
assert result.tables[1].full_name == "dune.namespace2.table2"
395-
assert result.tables[1].namespace == "namespace2"
396-
assert result.tables[1].table_name == "table2"
397-
assert result.next_offset == 100
398-
399-
def test_list_tables_response_parsing_empty(self):
400-
"""Test ListTablesResponse parsing with no tables"""
401-
response_data = {"tables": [], "next_offset": None}
402-
result = ListTablesResponse.from_dict(response_data)
403-
assert len(result.tables) == 0
404-
assert result.next_offset is None
405-
406352

407353
if __name__ == "__main__":
408354
unittest.main()

0 commit comments

Comments
 (0)