-
Couldn't load subscription status.
- Fork 44
Description
We want to move to Python's function @overloading (https://typing.python.org/en/latest/spec/overload.html) to increase readability of the code. However, it was found that Mypy raises errors in certain scenarios for our current type structure.
At the moment, we use type aliases:
SingleColumn: TypeAlias = np.ndarray
DenseBatchArray: TypeAlias = np.ndarray
The problem is that because both SingleColumn and DenseBatchArray are aliases for np.ndarray, Mypy concludes that they are the same type. We do not want to merge or remove these aliases, as the distinct names convey important contextual meaning.
Therefore, a potential solution is defining classes that inherit from the underlying data structure rather than relying solely on type aliases:
class SingleArray(np.ndarray):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if len(self.shape) != 1:
# of course with its own sub-error-type
raise PowerGridError("Single arrays must be 1-dimensional")
class DenseBatchArray(np.ndarray):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if len(self.shape) != 1:
# of course with its own sub-error-type
raise PowerGridError("Dense batch arrays must be 1-dimensional")
Furthermore, for migration purposes it is a good idea to further extend these and all the other classes that will be created by adding another method:
class SingleArray(np.ndarray):
# init
@staticmethod
def from(data: np.ndarray) -> "SingleArray":
if isinstance(data, SingleArray):
return data
return SingleArray(data)
SingleArrayLike: TypeAlias = SingleArray | np.ndarray
The implementation should contain the Class implementations for:
- SingleArray,
- SingleColumn,
- DenseBatchArray,
- SingleColumnarData,
- BatchColumn,
- DenseBatchColumnarData,
- IndexPointer
A desired end result is:
- Mypy should be able to distinguish between the types
- Existing code should be backwards compatible
Example code of overloading where mypy complains:
@overload
def _check_sparse_dense(component_data: SingleArray, err_msg_suffixed: str) -> SingleArray: ...
@overload
def _check_sparse_dense(component_data: DenseBatchArray, err_msg_suffixed: str) -> DenseBatchArray: ... # type: ignore[overload-cannot-match]
@overload
def _check_sparse_dense(component_data: DenseBatchColumnarData, err_msg_suffixed: str) -> DenseBatchColumnarData: ... # type: ignore[overload-overlap]
@overload
def _check_sparse_dense(component_data: SparseBatchArray, err_msg_suffixed: str) -> SingleArray: ... # type: ignore[overload-cannot-match, overload-overlap]
@overload
def _check_sparse_dense(component_data: SingleColumnarData, err_msg_suffixed: str) -> SingleColumnarData: ... # type: ignore[overload-cannot-match]
@overload
def _check_sparse_dense(component_data: SparseBatchColumnarData, err_msg_suffixed: str) -> SingleColumnarData: ...
def _check_sparse_dense(component_data, err_msg_suffixed):
The block of code above was setup locally and was not merged, therefore it will not be found in the repository. To set up your own version, you will need to copy and paste it into: src\power_grid_model\_core\utils.py. One of the proofs that Mypy does not complain about the types that you have created would be that there is no need for the Mypy ignore comments in the code block above.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status