From e1bc42a372956038a79d08bc45c19c4c0443fbe2 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Thu, 24 Dec 2020 12:24:25 +0100 Subject: [PATCH 1/5] Add typing for io/sql.py --- pandas/io/sql.py | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 0ad9140f2a757..2124133780c08 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -383,6 +383,8 @@ def read_sql_query( Data type for data or columns. E.g. np.float64 or {‘a’: np.float64, ‘b’: np.int32, ‘c’: ‘Int64’} + .. versionadded:: 1.3.0 + Returns ------- DataFrame or Iterator[DataFrame] @@ -609,7 +611,7 @@ def to_sql( index: bool = True, index_label=None, chunksize: Optional[int] = None, - dtype=None, + dtype: Optional[DtypeArg] = None, method: Optional[str] = None, ) -> None: """ @@ -768,7 +770,7 @@ def __init__( index_label=None, schema=None, keys=None, - dtype=None, + dtype: Optional[DtypeArg] = None, ): self.name = name self.pd_sql = pandas_sql_engine @@ -1108,9 +1110,9 @@ def _harmonize_columns(self, parse_dates=None): def _sqlalchemy_type(self, col): - dtype = self.dtype or {} - if col.name in dtype: - return self.dtype[col.name] + dtype: DtypeArg = self.dtype or {} + if isinstance(dtype, dict) and col.name in dtype: + return dtype[col.name] # Infer type of column, while ignoring missing values. # Needed for inserting typed data containing NULLs, GH 8778. @@ -1203,7 +1205,18 @@ def read_sql(self, *args, **kwargs): "connectable or sqlite connection" ) - def to_sql(self, *args, **kwargs): + def to_sql( + self, + frame, + name, + if_exists="fail", + index=True, + index_label=None, + schema=None, + chunksize=None, + dtype: Optional[DtypeArg] = None, + method=None, + ): raise ValueError( "PandasSQL must be created with an SQLAlchemy " "connectable or sqlite connection" @@ -1430,7 +1443,7 @@ def to_sql( index_label=None, schema=None, chunksize=None, - dtype=None, + dtype: Optional[DtypeArg] = None, method=None, ): """ @@ -1477,7 +1490,7 @@ def to_sql( if dtype and not is_dict_like(dtype): dtype = {col_name: dtype for col_name in frame} - if dtype is not None: + if dtype is not None and isinstance(dtype, dict): from sqlalchemy.types import TypeEngine, to_instance for col, my_type in dtype.items(): @@ -1563,7 +1576,7 @@ def _create_sql_schema( frame: DataFrame, table_name: str, keys: Optional[List[str]] = None, - dtype: Optional[dict] = None, + dtype: Optional[DtypeArg] = None, schema: Optional[str] = None, ): table = SQLTable( @@ -1734,8 +1747,8 @@ def _create_table_setup(self): return create_stmts def _sql_type_name(self, col): - dtype = self.dtype or {} - if col.name in dtype: + dtype: DtypeArg = self.dtype or {} + if isinstance(dtype, dict) and col.name in dtype: return dtype[col.name] # Infer type of column, while ignoring missing values. @@ -1895,7 +1908,7 @@ def to_sql( index_label=None, schema=None, chunksize=None, - dtype=None, + dtype: Optional[DtypeArg] = None, method=None, ): """ @@ -1941,7 +1954,7 @@ def to_sql( if dtype and not is_dict_like(dtype): dtype = {col_name: dtype for col_name in frame} - if dtype is not None: + if dtype is not None and isinstance(dtype, dict): for col, my_type in dtype.items(): if not isinstance(my_type, str): raise ValueError(f"{col} ({my_type}) not a string") @@ -1980,7 +1993,7 @@ def _create_sql_schema( frame, table_name: str, keys=None, - dtype=None, + dtype: Optional[DtypeArg] = None, schema: Optional[str] = None, ): table = SQLiteTable( @@ -1996,7 +2009,12 @@ def _create_sql_schema( def get_schema( - frame, name: str, keys=None, con=None, dtype=None, schema: Optional[str] = None + frame, + name: str, + keys=None, + con=None, + dtype: Optional[DtypeArg] = None, + schema: Optional[str] = None, ): """ Get the SQL db table schema for the given frame. From 2c70647dd470fa7b68ef21ce6559c5aa16c4b4d2 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Mon, 28 Dec 2020 21:58:31 +0100 Subject: [PATCH 2/5] Cast dtype to dict --- pandas/io/sql.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 573d2cdff826d..a5501cb880a6e 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -7,7 +7,7 @@ from datetime import date, datetime, time from functools import partial import re -from typing import Any, Dict, Iterator, List, Optional, Sequence, Union, overload +from typing import Any, Dict, Iterator, List, Optional, Sequence, Union, cast, overload import warnings import numpy as np @@ -1493,10 +1493,13 @@ def to_sql( .. versionadded:: 0.24.0 """ - if dtype and not is_dict_like(dtype): - dtype = {col_name: dtype for col_name in frame} + if dtype is not None: + if not is_dict_like(dtype): + dtype = {col_name: dtype for col_name in frame} + else: + dtype = cast(dict, dtype) - if dtype is not None and isinstance(dtype, dict): + if dtype: from sqlalchemy.types import TypeEngine, to_instance for col, my_type in dtype.items(): From a82a6c1b68ad301df2f1a0f925c8d3275f25e228 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Tue, 29 Dec 2020 01:45:12 +0100 Subject: [PATCH 3/5] Replace isinstance checks with is_dict_like --- pandas/io/sql.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index a5501cb880a6e..21f6bc80bfa14 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -1111,8 +1111,10 @@ def _harmonize_columns(self, parse_dates=None): def _sqlalchemy_type(self, col): dtype: DtypeArg = self.dtype or {} - if isinstance(dtype, dict) and col.name in dtype: - return dtype[col.name] + if is_dict_like(dtype): + dtype = cast(dict, dtype) + if col.name in dtype: + return dtype[col.name] # Infer type of column, while ignoring missing values. # Needed for inserting typed data containing NULLs, GH 8778. @@ -1757,8 +1759,10 @@ def _create_table_setup(self): def _sql_type_name(self, col): dtype: DtypeArg = self.dtype or {} - if isinstance(dtype, dict) and col.name in dtype: - return dtype[col.name] + if is_dict_like(dtype): + dtype = cast(dict, dtype) + if col.name in dtype: + return dtype[col.name] # Infer type of column, while ignoring missing values. # Needed for inserting typed data containing NULLs, GH 8778. @@ -1960,10 +1964,13 @@ def to_sql( .. versionadded:: 0.24.0 """ - if dtype and not is_dict_like(dtype): - dtype = {col_name: dtype for col_name in frame} + if dtype is not None: + if not is_dict_like(dtype): + dtype = {col_name: dtype for col_name in frame} + else: + dtype = cast(dict, dtype) - if dtype is not None and isinstance(dtype, dict): + if dtype: for col, my_type in dtype.items(): if not isinstance(my_type, str): raise ValueError(f"{col} ({my_type}) not a string") From 8dc13bd9cd04e04c8f643a9f102b431958e541e2 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Tue, 29 Dec 2020 01:52:52 +0100 Subject: [PATCH 4/5] Revert check to original form --- pandas/io/sql.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 21f6bc80bfa14..f2bad546b69e1 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -1495,13 +1495,13 @@ def to_sql( .. versionadded:: 0.24.0 """ - if dtype is not None: + if dtype: if not is_dict_like(dtype): dtype = {col_name: dtype for col_name in frame} else: dtype = cast(dict, dtype) - if dtype: + if dtype is not None: from sqlalchemy.types import TypeEngine, to_instance for col, my_type in dtype.items(): @@ -1964,13 +1964,13 @@ def to_sql( .. versionadded:: 0.24.0 """ - if dtype is not None: + if dtype: if not is_dict_like(dtype): dtype = {col_name: dtype for col_name in frame} else: dtype = cast(dict, dtype) - if dtype: + if dtype is not None: for col, my_type in dtype.items(): if not isinstance(my_type, str): raise ValueError(f"{col} ({my_type}) not a string") From ae41d91010c5ab04bc6ca3df48e41da9e17965c5 Mon Sep 17 00:00:00 2001 From: Avinash Pancham Date: Tue, 29 Dec 2020 13:34:49 +0100 Subject: [PATCH 5/5] Remove superfluous if statement --- pandas/io/sql.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index f2bad546b69e1..aa4bcd8b1565a 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -1501,7 +1501,6 @@ def to_sql( else: dtype = cast(dict, dtype) - if dtype is not None: from sqlalchemy.types import TypeEngine, to_instance for col, my_type in dtype.items(): @@ -1970,7 +1969,6 @@ def to_sql( else: dtype = cast(dict, dtype) - if dtype is not None: for col, my_type in dtype.items(): if not isinstance(my_type, str): raise ValueError(f"{col} ({my_type}) not a string")