Skip to content

Commit

Permalink
feat: handle list of filenames in absolute_path and file_mtime (#89)
Browse files Browse the repository at this point in the history
Closes #88

### Summary of Changes

`file_mtime` and `absolute_path` can now work with a list of strings as
well as a single string. This is needed for function like
`ImageList.from_files` that accept multiple paths.

For now, order matters. Specifying the same paths in a different order
leads to a different memoization key.
  • Loading branch information
lars-reimann authored Apr 17, 2024
1 parent 9992b21 commit 50d831f
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 12 deletions.
46 changes: 34 additions & 12 deletions src/safeds_runner/server/_pipeline_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,41 +393,63 @@ def memoized_dynamic_call(
)


def file_mtime(filename: str) -> int | None:
@typing.overload
def file_mtime(filenames: str) -> int | None: ...


@typing.overload
def file_mtime(filenames: list[str]) -> list[int | None]: ...


def file_mtime(filenames: str | list[str]) -> int | None | list[int | None]:
"""
Get the last modification timestamp of the provided file.
Parameters
----------
filename: str
Name of the file
filenames:
Names of the files
Returns
-------
int | None
Last modification timestamp if the provided file exists, otherwise None
timestamps:
Last modification timestamp or None for each provided file, depending on whether the file exists or not.
"""
if isinstance(filenames, list):
return [file_mtime(f) for f in filenames]

try:
return Path(filename).stat().st_mtime_ns
return Path(filenames).stat().st_mtime_ns
except FileNotFoundError:
return None


def absolute_path(filename: str) -> str:
@typing.overload
def absolute_path(filenames: str) -> str: ...


@typing.overload
def absolute_path(filenames: list[str]) -> list[str]: ...


def absolute_path(filenames: str | list[str]) -> str | list[str]:
"""
Get the absolute path of the provided file.
Parameters
----------
filename:
Name of the file
filenames:
Names of the files.
Returns
-------
absolute_path:
Absolute path of the provided file
absolute_paths:
Absolute paths of the provided files.
"""
return str(Path(filename).resolve())
if isinstance(filenames, list):
return [absolute_path(f) for f in filenames]

return str(Path(filenames).resolve())


def get_backtrace_info(error: BaseException) -> list[dict[str, Any]]:
Expand Down
12 changes: 12 additions & 0 deletions tests/safeds_runner/server/test_memoization.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,13 @@ def test_file_mtime_exists() -> None:
assert mtime is not None


def test_file_mtime_exists_list() -> None:
with tempfile.NamedTemporaryFile() as file:
mtime = file_mtime([file.name, file.name])
assert isinstance(mtime, list)
assert all(it is not None for it in mtime)


def test_file_mtime_not_exists() -> None:
mtime = file_mtime(f"file_not_exists.{datetime.now(tz=UTC).timestamp()}")
assert mtime is None
Expand All @@ -282,6 +289,11 @@ def test_absolute_path() -> None:
assert Path(result).is_absolute()


def test_absolute_path_list() -> None:
result = absolute_path(["table.csv"])
assert all(Path(it).is_absolute() for it in result)


@pytest.mark.parametrize(
argnames="cache,greater_than_zero",
argvalues=[(MemoizationMap({}, {}), False), (MemoizationMap({}, {"a": MemoizationStats([], [], [], [20])}), True)],
Expand Down

0 comments on commit 50d831f

Please sign in to comment.