Skip to content

Commit ba865fd

Browse files
committed
python/ Improve typing.
* pyproject.toml[tools.mypy]: New. * src/moocore/_moocore.py: More type annotations. * src/moocore/_utils.py: Likewise.
1 parent fea577f commit ba865fd

File tree

3 files changed

+53
-15
lines changed

3 files changed

+53
-15
lines changed

python/pyproject.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,21 @@ lint.pydocstyle.convention = "numpy"
189189
faulthandler_timeout = 10
190190
doctest_optionflags = "NUMBER"
191191
addopts = [ "--import-mode=importlib", "--durations=5", "--durations-min=1.0" ]
192+
193+
[tool.mypy]
194+
python_version = "3.11"
195+
# Strictness (recommended for library code)
196+
disallow_untyped_defs = true
197+
disallow_incomplete_defs = true
198+
check_untyped_defs = true
199+
disallow_untyped_calls = true
200+
disallow_untyped_decorators = true
201+
no_implicit_optional = true
202+
# Warnings
203+
warn_unused_ignores = true
204+
warn_return_any = true
205+
warn_redundant_casts = true
206+
warn_unused_configs = true
207+
# Imports
208+
ignore_missing_imports = true
209+
files = [ "src/" ]

python/src/moocore/_moocore.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class ReadDatasetsError(Exception):
4949
"ERROR_COLUMNS",
5050
)
5151

52-
def __init__(self, error_code):
52+
def __init__(self, error_code: int):
5353
self.error = error_code
5454
self.message = self._error_strings[abs(error_code)]
5555
super().__init__(self.message)
@@ -151,7 +151,7 @@ def read_datasets(filename: str | os.PathLike | StringIO) -> np.ndarray:
151151
return np.frombuffer(data_buf).reshape((-1, ncols_p[0]))
152152

153153

154-
def _parse_maximise(maximise, nobj: int):
154+
def _parse_maximise(maximise, nobj: int) -> np.ndarray:
155155
"""Convert maximise array or single bool to ndarray format."""
156156
return atleast_1d_of_length_n(maximise, nobj).astype(bool)
157157

@@ -160,7 +160,12 @@ def _all_positive(x: ArrayLike) -> bool:
160160
return x.min() > 0
161161

162162

163-
def _unary_refset_common(data, ref, maximise, check_all_positive=False):
163+
def _unary_refset_common(
164+
data: ArrayLike,
165+
ref: ArrayLike,
166+
maximise: bool | list[bool],
167+
check_all_positive: bool = False,
168+
):
164169
# Convert to numpy.array in case the user provides a list. We use
165170
# np.asarray(dtype=float) to convert it to floating-point, otherwise if a user inputs
166171
# something like ref = np.array([10, 10]) then numpy would interpret it as
@@ -355,7 +360,9 @@ def epsilon_additive(
355360
)
356361

357362

358-
def epsilon_mult(data, /, ref, *, maximise: bool | list[bool] = False) -> float:
363+
def epsilon_mult(
364+
data: ArrayLike, /, ref: ArrayLike, *, maximise: bool | list[bool] = False
365+
) -> float:
359366
"""Multiplicative epsilon metric.
360367
361368
.. warning::
@@ -374,7 +381,7 @@ def epsilon_mult(data, /, ref, *, maximise: bool | list[bool] = False) -> float:
374381
return lib.epsilon_mult(data_p, nobj, npoints, ref_p, ref_size, maximise_p)
375382

376383

377-
def _hypervolume(data: ArrayLike, ref: ArrayLike):
384+
def _hypervolume(data: ArrayLike, ref: ArrayLike) -> float:
378385
data_p, npoints, nobj = np2d_to_double_array(data)
379386
ref_buf = ffi.from_buffer("double []", ref)
380387
hv = lib.fpli_hv(data_p, nobj, npoints, ref_buf)

python/src/moocore/_utils.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
1+
from numpy.typing import ArrayLike # For type hints
2+
from typing import Any
3+
14
import numpy as np
25
from ._libmoocore import ffi
36

47

5-
def get1_and_is_copied(x, x_):
8+
def get1_and_is_copied(x: Any, x_: Any) -> tuple[Any, bool]:
69
x_copied = id(x) != id(x_)
710
return x, x_copied
811

912

10-
def asarray_maybe_copy(x, dtype=float):
13+
def asarray_maybe_copy(
14+
x: ArrayLike, dtype: type = float
15+
) -> tuple[np.ndarray, bool]:
1116
"""Convert to numpy array of dtype=float and detect copies."""
1217
return get1_and_is_copied(np.asarray(x, dtype=dtype), x)
1318

1419

15-
def unique_nosort(array, **kwargs):
20+
def unique_nosort(array: ArrayLike, **kwargs: Any) -> np.ndarray:
1621
"""Return unique values without sorting them.
1722
1823
See https://github.com/numpy/numpy/issues/7265
@@ -22,7 +27,9 @@ def unique_nosort(array, **kwargs):
2227
return uniq[index.argsort()]
2328

2429

25-
def np2d_to_double_array(x, ctype_shape=("int", "int")):
30+
def np2d_to_double_array(
31+
x: ArrayLike, ctype_shape: tuple[str, str] = ("int", "int")
32+
) -> tuple[ffi.CData, ffi.CData, ffi.CData]:
2633
nrows = ffi.cast(ctype_shape[0], x.shape[0])
2734
ncols = ffi.cast(ctype_shape[1], x.shape[1])
2835
# FIXME: This may cause an unexpected copy. Make this an assert and force
@@ -32,23 +39,29 @@ def np2d_to_double_array(x, ctype_shape=("int", "int")):
3239
return x, nrows, ncols
3340

3441

35-
def np1d_to_c_array(x, ctype_data, ctype_size):
42+
def np1d_to_c_array(
43+
x: ArrayLike, ctype_data: str, ctype_size: str
44+
) -> tuple[ffi.CData, ffi.CData]:
3645
size = ffi.cast(ctype_size, x.shape[0])
3746
ctype_dtype = np.intc() if ctype_data == "int" else None
3847
x = np.ascontiguousarray(x, dtype=ctype_dtype)
3948
x = ffi.from_buffer(ctype_data + "[]", x)
4049
return x, size
4150

4251

43-
def np1d_to_double_array(x, ctype_size="int"):
52+
def np1d_to_double_array(
53+
x: ArrayLike, ctype_size: str = "int"
54+
) -> tuple[ffi.CData, ffi.CData]:
4455
return np1d_to_c_array(x, ctype_data="double", ctype_size=ctype_size)
4556

4657

47-
def np1d_to_int_array(x, ctype_size="int"):
58+
def np1d_to_int_array(
59+
x: ArrayLike, ctype_size: str = "int"
60+
) -> tuple[ffi.CData, ffi.CData]:
4861
return np1d_to_c_array(x, ctype_data="int", ctype_size=ctype_size)
4962

5063

51-
def atleast_1d_of_length_n(x, n):
64+
def atleast_1d_of_length_n(x: ArrayLike, n: int) -> np.ndarray:
5265
x = np.atleast_1d(x)
5366
if len(x) == 1:
5467
return np.full((n), x[0])
@@ -59,7 +72,7 @@ def atleast_1d_of_length_n(x, n):
5972
)
6073

6174

62-
def is_integer_value(n):
75+
def is_integer_value(n: Any) -> bool:
6376
if isinstance(n, int):
6477
return True
6578
if n is None:
@@ -73,7 +86,7 @@ def is_integer_value(n):
7386
return False
7487

7588

76-
def _get_seed_for_c(seed):
89+
def _get_seed_for_c(seed: Any) -> ffi.CData:
7790
if not is_integer_value(seed):
7891
seed = np.random.default_rng(seed).integers(2**32 - 2, dtype=np.uint32)
7992
return ffi.cast("uint32_t", seed)

0 commit comments

Comments
 (0)