11#!/usr/bin/env python
22from __future__ import annotations
33
4+ import abc
45import collections
56import logging
67import os
1920 TYPE_CHECKING ,
2021 Any ,
2122 Callable ,
23+ Generic ,
2224 Iterator ,
2325 Literal ,
2426 NamedTuple ,
8688 from .result_batch import ResultBatch
8789
8890T = TypeVar ("T" , bound = collections .abc .Sequence )
91+ FetchRow = TypeVar ("FetchRow" , bound = tuple [Any , ...] | dict [str , Any ])
8992
9093logger = getLogger (__name__ )
9194
@@ -332,29 +335,7 @@ class ResultState(Enum):
332335 RESET = 3
333336
334337
335- class SnowflakeCursor :
336- """Implementation of Cursor object that is returned from Connection.cursor() method.
337-
338- Attributes:
339- description: A list of namedtuples about metadata for all columns.
340- rowcount: The number of records updated or selected. If not clear, -1 is returned.
341- rownumber: The current 0-based index of the cursor in the result set or None if the index cannot be
342- determined.
343- sfqid: Snowflake query id in UUID form. Include this in the problem report to the customer support.
344- sqlstate: Snowflake SQL State code.
345- timestamp_output_format: Snowflake timestamp_output_format for timestamps.
346- timestamp_ltz_output_format: Snowflake output format for LTZ timestamps.
347- timestamp_tz_output_format: Snowflake output format for TZ timestamps.
348- timestamp_ntz_output_format: Snowflake output format for NTZ timestamps.
349- date_output_format: Snowflake output format for dates.
350- time_output_format: Snowflake output format for times.
351- timezone: Snowflake timezone.
352- binary_output_format: Snowflake output format for binary fields.
353- arraysize: The default number of rows fetched by fetchmany.
354- connection: The connection object by which the cursor was created.
355- errorhandle: The class that handles error handling.
356- is_file_transfer: Whether, or not the current command is a put, or get.
357- """
338+ class SnowflakeCursorBase (abc .ABC , Generic [FetchRow ]):
358339
359340 # TODO:
360341 # Most of these attributes have no reason to be properties, we could just store them in public variables.
@@ -1514,7 +1495,11 @@ def executemany(
15141495
15151496 return self
15161497
1517- def fetchone (self ) -> dict | tuple | None :
1498+ @abc .abstractmethod
1499+ def fetchone (self ) -> FetchRow :
1500+ pass
1501+
1502+ def _fetchone (self ) -> dict [str , Any ] | tuple [Any , ...] | None :
15181503 """Fetches one row."""
15191504 if self ._prefetch_hook is not None :
15201505 self ._prefetch_hook ()
@@ -1539,7 +1524,7 @@ def fetchone(self) -> dict | tuple | None:
15391524 else :
15401525 return None
15411526
1542- def fetchmany (self , size : int | None = None ) -> list [tuple ] | list [ dict ]:
1527+ def fetchmany (self , size : int | None = None ) -> list [FetchRow ]:
15431528 """Fetches the number of specified rows."""
15441529 if size is None :
15451530 size = self .arraysize
@@ -1565,7 +1550,7 @@ def fetchmany(self, size: int | None = None) -> list[tuple] | list[dict]:
15651550
15661551 return ret
15671552
1568- def fetchall (self ) -> list [tuple ] | list [ dict ]:
1553+ def fetchall (self ) -> list [FetchRow ]:
15691554 """Fetches all of the results."""
15701555 ret = []
15711556 while True :
@@ -1925,7 +1910,37 @@ def _create_file_transfer_agent(
19251910 )
19261911
19271912
1928- class DictCursor (SnowflakeCursor ):
1913+ class SnowflakeCursor (SnowflakeCursorBase [tuple [Any , ...]]):
1914+ """Implementation of Cursor object that is returned from Connection.cursor() method.
1915+
1916+ Attributes:
1917+ description: A list of namedtuples about metadata for all columns.
1918+ rowcount: The number of records updated or selected. If not clear, -1 is returned.
1919+ rownumber: The current 0-based index of the cursor in the result set or None if the index cannot be
1920+ determined.
1921+ sfqid: Snowflake query id in UUID form. Include this in the problem report to the customer support.
1922+ sqlstate: Snowflake SQL State code.
1923+ timestamp_output_format: Snowflake timestamp_output_format for timestamps.
1924+ timestamp_ltz_output_format: Snowflake output format for LTZ timestamps.
1925+ timestamp_tz_output_format: Snowflake output format for TZ timestamps.
1926+ timestamp_ntz_output_format: Snowflake output format for NTZ timestamps.
1927+ date_output_format: Snowflake output format for dates.
1928+ time_output_format: Snowflake output format for times.
1929+ timezone: Snowflake timezone.
1930+ binary_output_format: Snowflake output format for binary fields.
1931+ arraysize: The default number of rows fetched by fetchmany.
1932+ connection: The connection object by which the cursor was created.
1933+ errorhandle: The class that handles error handling.
1934+ is_file_transfer: Whether, or not the current command is a put, or get.
1935+ """
1936+
1937+ def fetchone (self ) -> tuple [Any , ...] | None :
1938+ row = self ._fetchone ()
1939+ assert row is None or isinstance (row , tuple )
1940+ return row
1941+
1942+
1943+ class DictCursor (SnowflakeCursorBase [dict [str , Any ]]):
19291944 """Cursor returning results in a dictionary."""
19301945
19311946 def __init__ (self , connection ) -> None :
@@ -1934,6 +1949,11 @@ def __init__(self, connection) -> None:
19341949 use_dict_result = True ,
19351950 )
19361951
1952+ def fetchone (self ) -> dict [str , Any ] | None :
1953+ row = self ._fetchone ()
1954+ assert row is None or isinstance (row , dict )
1955+ return row
1956+
19371957
19381958def __getattr__ (name ):
19391959 if name == "NanoarrowUsage" :
0 commit comments