Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ skops Changelog

v0.17
-----
- Fix ``skops update`` failing when a relative output path contains a
directory, including updates with ``--inplace``.
- Loading a skops file now checks that each part of the file holds the kind
of content its loader expects, for instance that the keyword arguments of a
``functools.partial`` are stored as a dict. A file that does not is refused
Expand Down
4 changes: 3 additions & 1 deletion skops/cli/_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ def _update_file(
return None

with tempfile.TemporaryDirectory() as tmp_dir:
tmp_output_file = Path(tmp_dir) / f"{output_file}.tmp"
# Only the file name is used, so a relative output path with directories
# (e.g. ``models/model.skops``) doesn't point into a missing directory.
tmp_output_file = Path(tmp_dir) / f"{Path(output_file).name}.tmp"
dump(input_model, tmp_output_file)
shutil.move(str(tmp_output_file), str(output_file))
logger.info(f"Updated skops file written to {output_file}")
Expand Down
17 changes: 17 additions & 0 deletions skops/cli/tests/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,23 @@ def test_base_case_works_as_expected(
mock_logger.error.assert_not_called()
mock_logger.debug.assert_not_called()

@pytest.mark.parametrize("inplace", [True, False])
def test_relative_path_with_directory(
self, tmp_path, monkeypatch, inplace: bool, dump_old_file, safe_obj
):
# A relative output path with a directory component used to fail, since
# it was joined to the temporary directory as is.
monkeypatch.chdir(tmp_path.parent)
input_file = pathlib.Path(tmp_path.name) / f"{self.model_name}.skops"
output_file = None if inplace else input_file.with_name("updated.skops")

_update._update_file(
input_file=input_file, output_file=output_file, inplace=inplace
)

updated_obj = load(output_file or input_file)
assert np.array_equal(updated_obj, safe_obj)

@mock.patch("skops.cli._update.dump")
def test_only_diff(
self, mock_dump: mock.MagicMock, skops_path: pathlib.Path, dump_old_file
Expand Down