Skip to content

Commit 856731e

Browse files
feat: enable mypy session for db-dtypes (#16689)
This PR enables the mypy session in noxfile.py for db-dtypes and aligns it with the GAPIC generator template. It passes with some type ignores added for missing stubs and internal pandas usage. --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 4009eda commit 856731e

File tree

5 files changed

+42
-17
lines changed

5 files changed

+42
-17
lines changed

packages/db-dtypes/db_dtypes/__init__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ class TimeDtype(core.BaseDatetimeDtype):
5555
name = time_dtype_name
5656
type = datetime.time
5757

58-
def construct_array_type(self):
58+
@classmethod
59+
def construct_array_type(cls):
5960
return TimeArray
6061

6162
@staticmethod
@@ -213,7 +214,8 @@ class DateDtype(core.BaseDatetimeDtype):
213214
name = date_dtype_name
214215
type = datetime.date
215216

216-
def construct_array_type(self):
217+
@classmethod
218+
def construct_array_type(cls):
217219
return DateArray
218220

219221
@staticmethod
@@ -322,7 +324,7 @@ def __add__(self, other):
322324
if isinstance(other, TimeArray):
323325
return (other._ndarray - _NPEPOCH) + self._ndarray
324326

325-
return super().__add__(other)
327+
return super().__add__(other) # type: ignore[misc]
326328

327329
def __radd__(self, other):
328330
return self.__add__(other)
@@ -334,7 +336,7 @@ def __sub__(self, other):
334336
if isinstance(other, self.__class__):
335337
return self._ndarray - other._ndarray
336338

337-
return super().__sub__(other)
339+
return super().__sub__(other) # type: ignore[misc]
338340

339341

340342
def _check_python_version():

packages/db-dtypes/db_dtypes/core.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from typing import Optional
15+
from typing import Optional, Callable, Any
1616

1717
import numpy
1818
import pandas
@@ -50,6 +50,13 @@ class BaseDatetimeArray(pandas_backports.OpsMixin, _mixins.NDArrayBackedExtensio
5050
# https://github.com/pandas-dev/pandas/blob/main/pandas/core/arrays/_mixins.py
5151
_internal_fill_value = numpy.datetime64("NaT")
5252

53+
_box_func: Callable[[Any], Any]
54+
_from_backing_data: Callable[[Any], Any]
55+
56+
@classmethod
57+
def _datetime(cls, value: Any) -> Any:
58+
raise NotImplementedError
59+
5360
def __init__(self, values, dtype=None, copy: bool = False):
5461
if not (
5562
isinstance(values, numpy.ndarray) and values.dtype == numpy.dtype("<M8[ns]")
@@ -58,7 +65,11 @@ def __init__(self, values, dtype=None, copy: bool = False):
5865
elif copy:
5966
values = values.copy()
6067

61-
super().__init__(values=values, dtype=values.dtype)
68+
# We must pass values and dtype to the base constructor.
69+
# Manual assignment (self._ndarray = values) will fail at runtime with
70+
# AttributeError because the base is a Cython-backed 'NDArrayBacked'
71+
# object with non-writable attributes.
72+
super().__init__(values=values, dtype=values.dtype) # type: ignore[call-arg]
6273

6374
@classmethod
6475
def __ndarray(cls, scalars):

packages/db-dtypes/db_dtypes/json.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ class JSONDtype(pd.api.extensions.ExtensionDtype):
3232
name = "dbjson"
3333

3434
@property
35-
def na_value(self) -> pd.NA:
35+
def na_value(self) -> pd.NAType: # type: ignore[name-defined]
3636
"""Default NA value to use for this type."""
3737
return pd.NA
3838

3939
@property
40-
def type(self) -> type[str]:
40+
def type(self) -> type[str]: # type: ignore[override]
4141
"""
4242
Return the scalar type for the array elements.
4343
The standard JSON data types can be one of `dict`, `list`, `str`, `int`, `float`,
@@ -203,7 +203,7 @@ def __getitem__(self, item):
203203
assert item.dtype.kind == "b"
204204
return type(self)(self.pa_data.filter(item))
205205
elif isinstance(item, tuple):
206-
item = indexers.unpack_tuple_and_ellipses(item)
206+
item = indexers.unpack_tuple_and_ellipses(item) # type: ignore[attr-defined]
207207

208208
if common.is_scalar(item) and not common.is_integer(item):
209209
# e.g. "foo" or 2.5

packages/db-dtypes/db_dtypes/pandas_backports.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@
2626
pandas_release = packaging.version.parse(pandas.__version__).release
2727

2828
# # Create aliases for private methods in case they move in a future version.
29-
nanall = pandas.core.nanops.nanall
30-
nanany = pandas.core.nanops.nanany
31-
nanmax = pandas.core.nanops.nanmax
32-
nanmin = pandas.core.nanops.nanmin
29+
nanall = pandas.core.nanops.nanall # type: ignore[attr-defined]
30+
nanany = pandas.core.nanops.nanany # type: ignore[attr-defined]
31+
nanmax = pandas.core.nanops.nanmax # type: ignore[attr-defined]
32+
nanmin = pandas.core.nanops.nanmin # type: ignore[attr-defined]
3333
numpy_validate_all = pandas.compat.numpy.function.validate_all
3434
numpy_validate_any = pandas.compat.numpy.function.validate_any
3535
numpy_validate_max = pandas.compat.numpy.function.validate_max
3636
numpy_validate_min = pandas.compat.numpy.function.validate_min
3737

38-
nanmedian = pandas.core.nanops.nanmedian
38+
nanmedian = pandas.core.nanops.nanmedian # type: ignore[attr-defined]
3939
numpy_validate_median = pandas.compat.numpy.function.validate_median
4040

4141

packages/db-dtypes/noxfile.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,18 @@ def core_deps_from_source(session):
487487
@nox.session(python=DEFAULT_PYTHON_VERSION)
488488
def mypy(session):
489489
"""Run the type checker."""
490-
# TODO(https://github.com/googleapis/google-cloud-python/issues/16014):
491-
# Add mypy tests
492-
session.skip("mypy tests are not yet supported")
490+
session.install(
491+
"mypy<1.16.0",
492+
"types-requests",
493+
"types-protobuf",
494+
"pandas-stubs",
495+
)
496+
session.install("-e", ".")
497+
session.run(
498+
"mypy",
499+
"-p",
500+
"db_dtypes",
501+
"--check-untyped-defs",
502+
"--ignore-missing-imports",
503+
*session.posargs,
504+
)

0 commit comments

Comments
 (0)