diff --git a/.github/linters/.ruff.toml b/.github/linters/.ruff.toml index 9dc8ef0..ec96f28 100644 --- a/.github/linters/.ruff.toml +++ b/.github/linters/.ruff.toml @@ -1,7 +1,9 @@ -ignore-init-module-imports = true line-length = 120 target-version = "py311" +[lint] +ignore-init-module-imports = true + select = [ "F", "E", @@ -44,6 +46,7 @@ select = [ "NPY", "RUF" ] + ignore = [ # line-too-long (handled by black) "E501", @@ -91,7 +94,7 @@ ignore = [ "TRY003", ] -[per-file-ignores] +[lint.per-file-ignores] "*test*.py" = [ # Undocumented declarations "D100", @@ -104,5 +107,5 @@ ignore = [ "D107", ] -[pydocstyle] +[lint.pydocstyle] convention = "numpy" diff --git a/src/safeds_runner/server/_memoization_utils.py b/src/safeds_runner/server/_memoization_utils.py index 69963e5..eb48f59 100644 --- a/src/safeds_runner/server/_memoization_utils.py +++ b/src/safeds_runner/server/_memoization_utils.py @@ -10,6 +10,8 @@ from multiprocessing.shared_memory import SharedMemory from typing import Any, TypeAlias +import numpy as np + MemoizationKey: TypeAlias = tuple[str, tuple, tuple] @@ -201,7 +203,7 @@ def _is_not_primitive(value: Any) -> bool: result: True, if the object is not primitive. """ - return not isinstance(value, str | int | float | type(None) | bool) + return not isinstance(value, str | int | float | type(None) | bool | np.generic) def _is_deterministically_hashable(value: Any) -> bool: @@ -428,12 +430,18 @@ def _wrap_value_to_shared_memory( return {_wrap_value_to_shared_memory(entry) for entry in result} if isinstance(result, frozenset): return frozenset({_wrap_value_to_shared_memory(entry) for entry in result}) - elif _is_deterministically_hashable(result): - _set_new_explicit_identity_deterministic_hash(result) - return ExplicitIdentityWrapperLazy.shared(result) - elif _is_not_primitive(result): - _set_new_explicit_identity(result) - return ExplicitIdentityWrapper.shared(result) + + try: + if _is_deterministically_hashable(result): + _set_new_explicit_identity_deterministic_hash(result) + return ExplicitIdentityWrapperLazy.shared(result) + elif _is_not_primitive(result): + _set_new_explicit_identity(result) + return ExplicitIdentityWrapper.shared(result) + except AttributeError: + # We cannot add fields to many built-in types. + pass + return result diff --git a/tests/safeds_runner/server/test_memoization_utils.py b/tests/safeds_runner/server/test_memoization_utils.py index 99bf9e0..fdf1d3c 100644 --- a/tests/safeds_runner/server/test_memoization_utils.py +++ b/tests/safeds_runner/server/test_memoization_utils.py @@ -1,8 +1,10 @@ import base64 +import datetime import pickle import sys from typing import Any +import numpy as np import pytest from safeds.data.image.containers import Image from safeds.data.tabular.containers import Table @@ -308,8 +310,21 @@ def test_wrap_value_to_shared_memory_non_deterministic(value: Any) -> None: {"a": Table()}, {"a", "b", Table()}, frozenset({"a", "b", Table()}), + np.int64(1), + datetime.date(2021, 1, 1), + ], + ids=[ + "int", + "list", + "tuple", + "table", + "tuple_table", + "dict", + "set", + "frozenset", + "numpy_int64", + "datetime_date", ], - ids=["int", "list", "tuple", "table", "tuple_table", "dict", "set", "frozenset"], ) def test_serialize_value_to_shared_memory(value: Any) -> None: _wrapped = _wrap_value_to_shared_memory(value)