Coverage for dataexcept/_validation.py: 100%

5 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-09-03 20:46 +0000

1"""Small runtime checks shared by the exception constructors.""" 

2 

3from __future__ import annotations 

4 

5import numbers 

6 

7__all__ = ["is_number"] 

8 

9 

10def is_number(value: object) -> bool: 

11 """Return True for any real number, including NumPy scalars. 

12 

13 ``isinstance(value, (int, float))`` rejects ``numpy.float32`` and 

14 ``numpy.int64``, which is a poor answer from a library aimed at data 

15 science. ``numbers.Real`` accepts them because NumPy registers its scalar 

16 types with the ABC, and it needs no dependency on NumPy to do so. 

17 

18 Booleans are excluded: ``bool`` subclasses ``int``, so ``numbers.Real`` 

19 would accept ``True`` as a metric. 

20 

21 This is a function rather than an inline ``isinstance`` because narrowing a 

22 value to ``numbers.Real`` defeats mypy's inference for the rest of the 

23 enclosing class. 

24 """ 

25 # bool subclasses int, so numbers.Real accepts True and False. A boolean 

26 # is never a meaningful metric, threshold or ratio, and accepting one hides 

27 # a caller passing the wrong variable. 

28 return not isinstance(value, bool) and isinstance(value, numbers.Real)