Skip to content

Commit 7c5017c

Browse files
authored
ENH: Add nullable keyword to read_sql (#50048)
* Start sql implementation * BUG: Fix bug in maybe_convert_objects with None and nullable * Add gh ref * Continue sql implementation * ENH: maybe_convert_objects add boolean support with NA * Fix merge error * Add gh ref * Add to api * Add tests * Fix test * Fix test * Simplify * Implement string support * Add support for table * Add docstring * Add whatsnew * Fix tests * Fix pylint * Fix docstring
1 parent e37040a commit 7c5017c

File tree

4 files changed

+213
-16
lines changed

4 files changed

+213
-16
lines changed

doc/source/whatsnew/v2.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ The ``use_nullable_dtypes`` keyword argument has been expanded to the following
3737

3838
* :func:`read_csv`
3939
* :func:`read_excel`
40+
* :func:`read_sql`
4041

4142
Additionally a new global configuration, ``io.nullable_backend`` can now be used in conjunction with the parameter ``use_nullable_dtypes=True`` in the following functions
4243
to select the nullable dtypes implementation.

pandas/core/internals/construction.py

+33-5
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131
)
3232
from pandas.core.dtypes.common import (
3333
is_1d_only_ea_dtype,
34+
is_bool_dtype,
3435
is_datetime_or_timedelta_dtype,
3536
is_dtype_equal,
3637
is_extension_array_dtype,
38+
is_float_dtype,
3739
is_integer_dtype,
3840
is_list_like,
3941
is_named_tuple,
@@ -49,7 +51,13 @@
4951
algorithms,
5052
common as com,
5153
)
52-
from pandas.core.arrays import ExtensionArray
54+
from pandas.core.arrays import (
55+
BooleanArray,
56+
ExtensionArray,
57+
FloatingArray,
58+
IntegerArray,
59+
)
60+
from pandas.core.arrays.string_ import StringDtype
5361
from pandas.core.construction import (
5462
ensure_wrapped_if_datetimelike,
5563
extract_array,
@@ -900,7 +908,7 @@ def _finalize_columns_and_data(
900908
raise ValueError(err) from err
901909

902910
if len(contents) and contents[0].dtype == np.object_:
903-
contents = _convert_object_array(contents, dtype=dtype)
911+
contents = convert_object_array(contents, dtype=dtype)
904912

905913
return contents, columns
906914

@@ -963,8 +971,11 @@ def _validate_or_indexify_columns(
963971
return columns
964972

965973

966-
def _convert_object_array(
967-
content: list[npt.NDArray[np.object_]], dtype: DtypeObj | None
974+
def convert_object_array(
975+
content: list[npt.NDArray[np.object_]],
976+
dtype: DtypeObj | None,
977+
use_nullable_dtypes: bool = False,
978+
coerce_float: bool = False,
968979
) -> list[ArrayLike]:
969980
"""
970981
Internal function to convert object array.
@@ -973,20 +984,37 @@ def _convert_object_array(
973984
----------
974985
content: List[np.ndarray]
975986
dtype: np.dtype or ExtensionDtype
987+
use_nullable_dtypes: Controls if nullable dtypes are returned.
988+
coerce_float: Cast floats that are integers to int.
976989
977990
Returns
978991
-------
979992
List[ArrayLike]
980993
"""
981994
# provide soft conversion of object dtypes
995+
982996
def convert(arr):
983997
if dtype != np.dtype("O"):
984-
arr = lib.maybe_convert_objects(arr)
998+
arr = lib.maybe_convert_objects(
999+
arr,
1000+
try_float=coerce_float,
1001+
convert_to_nullable_dtype=use_nullable_dtypes,
1002+
)
9851003

9861004
if dtype is None:
9871005
if arr.dtype == np.dtype("O"):
9881006
# i.e. maybe_convert_objects didn't convert
9891007
arr = maybe_infer_to_datetimelike(arr)
1008+
if use_nullable_dtypes and arr.dtype == np.dtype("O"):
1009+
arr = StringDtype().construct_array_type()._from_sequence(arr)
1010+
elif use_nullable_dtypes and isinstance(arr, np.ndarray):
1011+
if is_integer_dtype(arr.dtype):
1012+
arr = IntegerArray(arr, np.zeros(arr.shape, dtype=np.bool_))
1013+
elif is_bool_dtype(arr.dtype):
1014+
arr = BooleanArray(arr, np.zeros(arr.shape, dtype=np.bool_))
1015+
elif is_float_dtype(arr.dtype):
1016+
arr = FloatingArray(arr, np.isnan(arr))
1017+
9901018
elif isinstance(dtype, ExtensionDtype):
9911019
# TODO: test(s) that get here
9921020
# TODO: try to de-duplicate this convert function with

0 commit comments

Comments
 (0)