diff --git a/docs/_authors.rst b/docs/_authors.rst new file mode 100644 index 00000000..28768c7c --- /dev/null +++ b/docs/_authors.rst @@ -0,0 +1,10 @@ + +.. role:: raw-html(raw) + :format: html + + +.. _Adrin Jalali: https://github.com/adrinjalali + +.. _Benjamin Bossan: https://github.com/BenjaminBossan + +.. _Merve Noyan: https://github.com/merveenoyan diff --git a/docs/changes.rst b/docs/changes.rst index 61faf111..7e02e36b 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -1,3 +1,5 @@ +.. include:: _authors.rst + .. _changelog: skops Changelog @@ -10,8 +12,11 @@ skops Changelog v0.2 ---- - Tables, e.g. cross-validation results, can now be added to model cards using - the :meth:`.Card.add_table` method. :pr:`90` by :user:`Benjamin Bossan ` + the :meth:`.Card.add_table` method. :pr:`90` by `Benjamin Bossan`_. - Add method :meth:`.Card.render` which returns the model card as a string. + :pr:`94` by `Benjamin Bossan`_. +- Make :meth:`skops.hub_utils.init` atomic. Now it doesn't leave a trace on the + filesystem if it fails for some reason. :pr:`60` by `Adrin Jalali`_` v0.1 ---- diff --git a/skops/hub_utils/_hf_hub.py b/skops/hub_utils/_hf_hub.py index 608e6e3f..e0e79e14 100644 --- a/skops/hub_utils/_hf_hub.py +++ b/skops/hub_utils/_hf_hub.py @@ -279,16 +279,20 @@ def init( ) dst.mkdir(parents=True, exist_ok=True) - shutil.copy2(src=model, dst=dst) - - model_name = Path(model).name - _create_config( - model_path=model_name, - requirements=requirements, - dst=dst, - task=task, - data=data, - ) + try: + shutil.copy2(src=model, dst=dst) + + model_name = Path(model).name + _create_config( + model_path=model_name, + requirements=requirements, + dst=dst, + task=task, + data=data, + ) + except Exception: + shutil.rmtree(dst) + raise def update_env( diff --git a/skops/hub_utils/tests/test_hf_hub.py b/skops/hub_utils/tests/test_hf_hub.py index 37589bc4..e1169493 100644 --- a/skops/hub_utils/tests/test_hf_hub.py +++ b/skops/hub_utils/tests/test_hf_hub.py @@ -183,6 +183,28 @@ def test_create_config_invalid_text_data(temp_path): ) +def test_atomic_init(classifier_pickle, temp_path): + with pytest.raises(ValueError): + # this fails since we're passing an invalid task. + init( + model=classifier_pickle, + requirements=["scikit-learn"], + dst=temp_path, + task="tabular-classification", + data="invalid", + ) + + # this passes even though the above init has failed once, on the same + # destination path. + init( + model=classifier_pickle, + requirements=["scikit-learn"], + dst=temp_path, + task="tabular-classification", + data=iris.data, + ) + + def test_init_invalid_task(classifier_pickle, temp_path): with pytest.raises( ValueError, match="Task invalid not supported. Supported tasks are"