44from typing import TYPE_CHECKING
55
66import duckdb
7- import duckdb .typing as duckdb_dtypes
87from duckdb import Expression
9- from duckdb .typing import DuckDBPyType
8+
9+ try :
10+ import duckdb .sqltypes as duckdb_dtypes
11+ except ModuleNotFoundError :
12+ # DuckDB pre 1.3
13+ import duckdb .typing as duckdb_dtypes
1014
1115from narwhals ._utils import Version , isinstance_or_issubclass , zip_strict
1216from narwhals .exceptions import ColumnNotFoundError
@@ -131,7 +135,9 @@ def time_zone(self) -> str:
131135
132136
133137def native_to_narwhals_dtype (
134- duckdb_dtype : DuckDBPyType , version : Version , deferred_time_zone : DeferredTimeZone
138+ duckdb_dtype : duckdb_dtypes .DuckDBPyType ,
139+ version : Version ,
140+ deferred_time_zone : DeferredTimeZone ,
135141) -> DType :
136142 duckdb_dtype_id = duckdb_dtype .id
137143 dtypes = version .dtypes
@@ -216,7 +222,7 @@ def _non_nested_native_to_narwhals_dtype(duckdb_dtype_id: str, version: Version)
216222
217223
218224dtypes = Version .MAIN .dtypes
219- NW_TO_DUCKDB_DTYPES : Mapping [type [DType ], DuckDBPyType ] = {
225+ NW_TO_DUCKDB_DTYPES : Mapping [type [DType ], duckdb_dtypes . DuckDBPyType ] = {
220226 dtypes .Float64 : duckdb_dtypes .DOUBLE ,
221227 dtypes .Float32 : duckdb_dtypes .FLOAT ,
222228 dtypes .Binary : duckdb_dtypes .BLOB ,
@@ -228,14 +234,14 @@ def _non_nested_native_to_narwhals_dtype(duckdb_dtype_id: str, version: Version)
228234 dtypes .Int16 : duckdb_dtypes .SMALLINT ,
229235 dtypes .Int32 : duckdb_dtypes .INTEGER ,
230236 dtypes .Int64 : duckdb_dtypes .BIGINT ,
231- dtypes .Int128 : DuckDBPyType ( "INT128" ) ,
237+ dtypes .Int128 : duckdb_dtypes . HUGEINT ,
232238 dtypes .UInt8 : duckdb_dtypes .UTINYINT ,
233239 dtypes .UInt16 : duckdb_dtypes .USMALLINT ,
234240 dtypes .UInt32 : duckdb_dtypes .UINTEGER ,
235241 dtypes .UInt64 : duckdb_dtypes .UBIGINT ,
236- dtypes .UInt128 : DuckDBPyType ( "UINT128" ) ,
242+ dtypes .UInt128 : duckdb_dtypes . UHUGEINT ,
237243}
238- TIME_UNIT_TO_TIMESTAMP : Mapping [TimeUnit , DuckDBPyType ] = {
244+ TIME_UNIT_TO_TIMESTAMP : Mapping [TimeUnit , duckdb_dtypes . DuckDBPyType ] = {
239245 "s" : duckdb_dtypes .TIMESTAMP_S ,
240246 "ms" : duckdb_dtypes .TIMESTAMP_MS ,
241247 "us" : duckdb_dtypes .TIMESTAMP ,
@@ -246,7 +252,7 @@ def _non_nested_native_to_narwhals_dtype(duckdb_dtype_id: str, version: Version)
246252
247253def narwhals_to_native_dtype ( # noqa: PLR0912, C901
248254 dtype : IntoDType , version : Version , deferred_time_zone : DeferredTimeZone
249- ) -> DuckDBPyType :
255+ ) -> duckdb_dtypes . DuckDBPyType :
250256 dtypes = version .dtypes
251257 base_type = dtype .base_type ()
252258 if duckdb_type := NW_TO_DUCKDB_DTYPES .get (base_type ):
@@ -256,7 +262,7 @@ def narwhals_to_native_dtype( # noqa: PLR0912, C901
256262 msg = "Converting to Enum is not supported in narwhals.stable.v1"
257263 raise NotImplementedError (msg )
258264 if isinstance (dtype , dtypes .Enum ):
259- return DuckDBPyType (f"ENUM{ dtype .categories !r} " )
265+ return duckdb_dtypes . DuckDBPyType (f"ENUM{ dtype .categories !r} " )
260266 msg = "Can not cast / initialize Enum without categories present"
261267 raise ValueError (msg )
262268 if isinstance_or_issubclass (dtype , dtypes .Datetime ):
@@ -291,7 +297,7 @@ def narwhals_to_native_dtype( # noqa: PLR0912, C901
291297 nw_inner = nw_inner .inner
292298 duckdb_inner = narwhals_to_native_dtype (nw_inner , version , deferred_time_zone )
293299 duckdb_shape_fmt = "" .join (f"[{ item } ]" for item in dtype .shape )
294- return DuckDBPyType (f"{ duckdb_inner } { duckdb_shape_fmt } " )
300+ return duckdb_dtypes . DuckDBPyType (f"{ duckdb_inner } { duckdb_shape_fmt } " )
295301 if issubclass (base_type , UNSUPPORTED_DTYPES ):
296302 msg = f"Converting to { base_type .__name__ } dtype is not supported for DuckDB."
297303 raise NotImplementedError (msg )
@@ -378,19 +384,39 @@ def function(name: str, *args: Expression) -> Expression:
378384 if name == "isnull" :
379385 return args [0 ].isnull ()
380386 if name == "count_distinct" :
381- try :
382- from duckdb import SQLExpression
383- except ModuleNotFoundError as exc : # pragma: no cover
384- msg = f"DuckDB>=1.3.0 is required for this operation. Found: DuckDB { duckdb .__version__ } "
385- raise NotImplementedError (msg ) from exc
386- return SQLExpression (f"count(distinct { args [0 ]} )" )
387+ return sql_expression (f"count(distinct { args [0 ]} )" )
387388 return F (name , * args )
388389
389390
390391def sql_expression (expr : str ) -> Expression :
391392 try :
392393 from duckdb import SQLExpression
393- except ModuleNotFoundError as exc : # pragma: no cover
394+ except ImportError as exc : # pragma: no cover
394395 msg = f"DuckDB>=1.3.0 is required for this operation. Found: DuckDB { duckdb .__version__ } "
395396 raise NotImplementedError (msg ) from exc
396397 return SQLExpression (expr )
398+
399+
400+ __all__ = [
401+ "UNITS_DICT" ,
402+ "DeferredTimeZone" ,
403+ "F" ,
404+ "catch_duckdb_exception" ,
405+ "col" ,
406+ "concat_str" ,
407+ "duckdb_dtypes" ,
408+ "evaluate_exprs" ,
409+ "fetch_rel_time_zone" ,
410+ "function" ,
411+ "generate_order_by_sql" ,
412+ "generate_partition_by_sql" ,
413+ "join_column_names" ,
414+ "lambda_expr" ,
415+ "lit" ,
416+ "narwhals_to_native_dtype" ,
417+ "native_to_narwhals_dtype" ,
418+ "parse_into_expression" ,
419+ "sql_expression" ,
420+ "when" ,
421+ "window_expression" ,
422+ ]
0 commit comments