Skip to content

Commit f903c2c

Browse files
authored
fix!: use pandas.NaT for missing values in dbdate and dbtime dtypes (#67)
* fix!: use `pandas.NaT` for missing values in dbdate and dbtime dtypes This makes them consistent with other date/time dtypes, as well as internally consistent with the advertised `dtype.na_value`. * adjust pandas version support for median BREAKING-CHANGE: dbdate and dbtime dtypes return NaT instead of None for missing values Release-As: 0.4.0
1 parent e9d41d1 commit f903c2c

File tree

7 files changed

+127
-60
lines changed

7 files changed

+127
-60
lines changed

db_dtypes/__init__.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ def _datetime(
145145
raise TypeError("Invalid value type", scalar)
146146

147147
def _box_func(self, x):
148-
if pandas.isnull(x):
149-
return None
148+
if pandas.isna(x):
149+
return pandas.NaT
150150

151151
try:
152152
return x.astype("<M8[us]").astype(datetime.datetime).time()
@@ -250,8 +250,8 @@ def _datetime(
250250
raise TypeError("Invalid value type", scalar)
251251

252252
def _box_func(self, x):
253-
if pandas.isnull(x):
254-
return None
253+
if pandas.isna(x):
254+
return pandas.NaT
255255
try:
256256
return x.astype("<M8[us]").astype(datetime.datetime).date()
257257
except AttributeError:

db_dtypes/core.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
import numpy
1818
import pandas
19-
from pandas import NaT
2019
import pandas.api.extensions
2120
from pandas.api.types import is_dtype_equal, is_list_like, pandas_dtype
2221

@@ -27,8 +26,8 @@
2726

2827

2928
class BaseDatetimeDtype(pandas.api.extensions.ExtensionDtype):
30-
na_value = NaT
31-
kind = "o"
29+
na_value = pandas.NaT
30+
kind = "O"
3231
names = None
3332

3433
@classmethod

db_dtypes/pandas_backports.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
numpy_validate_max = pandas.compat.numpy.function.validate_max
4343
numpy_validate_min = pandas.compat.numpy.function.validate_min
4444

45-
if pandas_release >= (1, 2):
45+
if pandas_release >= (1, 3):
4646
nanmedian = pandas.core.nanops.nanmedian
4747
numpy_validate_median = pandas.compat.numpy.function.validate_median
4848

testing/constraints-3.9.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
sqlalchemy>=1.4.13
1+
# Make sure we test with pandas 1.3.0. The Python version isn't that relevant.
2+
pandas==1.3.0

tests/unit/test_date.py

+27
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
# To register the types.
2121
import db_dtypes # noqa
22+
from db_dtypes import pandas_backports
2223

2324

2425
@pytest.mark.parametrize(
@@ -65,3 +66,29 @@ def test_date_parsing(value, expected):
6566
def test_date_parsing_errors(value, error):
6667
with pytest.raises(ValueError, match=error):
6768
pandas.Series([value], dtype="dbdate")
69+
70+
71+
@pytest.mark.skipif(
72+
not hasattr(pandas_backports, "numpy_validate_median"),
73+
reason="median not available with this version of pandas",
74+
)
75+
@pytest.mark.parametrize(
76+
"values, expected",
77+
[
78+
(["1970-01-01", "1900-01-01", "2000-01-01"], datetime.date(1970, 1, 1)),
79+
(
80+
[
81+
None,
82+
"1900-01-01",
83+
pandas.NA if hasattr(pandas, "NA") else None,
84+
pandas.NaT,
85+
float("nan"),
86+
],
87+
datetime.date(1900, 1, 1),
88+
),
89+
(["2222-02-01", "2222-02-03"], datetime.date(2222, 2, 2)),
90+
],
91+
)
92+
def test_date_median(values, expected):
93+
series = pandas.Series(values, dtype="dbdate")
94+
assert series.median() == expected

0 commit comments

Comments
 (0)