From b8d71acb0e18145133b33087a063712470aa459f Mon Sep 17 00:00:00 2001 From: Hagen Wierstorf Date: Thu, 14 Nov 2024 15:28:35 +0100 Subject: [PATCH] Remove deprecated functions (#246) * Remove audbackend.delete() * Remove audbackend.access() * Remove audbackend.create() * Remove audbackend.register() * Fix typo in docstrings * Fix coverage --- audbackend/__init__.py | 4 - audbackend/core/api.py | 242 ------------------------- audbackend/core/backend/artifactory.py | 2 +- audbackend/core/backend/filesystem.py | 2 +- docs/api-src/audbackend.rst | 4 - tests/conftest.py | 12 -- tests/test_api.py | 108 ----------- tests/test_backend_artifactory.py | 15 ++ tests/test_backend_filesystem.py | 22 +++ tests/test_backend_minio.py | 15 ++ 10 files changed, 54 insertions(+), 372 deletions(-) delete mode 100644 audbackend/core/api.py delete mode 100644 tests/test_api.py diff --git a/audbackend/__init__.py b/audbackend/__init__.py index b3abcf72..c94d8468 100644 --- a/audbackend/__init__.py +++ b/audbackend/__init__.py @@ -1,9 +1,5 @@ from audbackend import backend from audbackend import interface -from audbackend.core.api import access -from audbackend.core.api import create -from audbackend.core.api import delete -from audbackend.core.api import register from audbackend.core.backend.base import Base as Backend # legacy from audbackend.core.backend.filesystem import FileSystem # legacy from audbackend.core.errors import BackendError diff --git a/audbackend/core/api.py b/audbackend/core/api.py deleted file mode 100644 index 6ec12365..00000000 --- a/audbackend/core/api.py +++ /dev/null @@ -1,242 +0,0 @@ -import warnings - -import audeer - -from audbackend.core import utils -from audbackend.core.backend.base import Base -from audbackend.core.backend.filesystem import FileSystem -from audbackend.core.interface.base import Base as Interface -from audbackend.core.interface.versioned import Versioned - - -backends = {} -r"""Backend cache.""" - -backend_registry = {} -r"""Backend registry.""" - - -def _backend( - name: str, - host: str, - repository: str, -) -> Base: - r"""Get backend instance.""" - if name not in backend_registry: - raise ValueError( - f"A backend class with name " - f"'{name}' " - f"does not exist. " - f"Use 'audbackend.register()' to register one." - ) - - if name not in backends: - backends[name] = {} - if host not in backends[name]: - backends[name][host] = {} - if repository not in backends[name][host]: - backend_cls = backend_registry[name] - backend = backend_cls(host, repository) - backends[name][host][repository] = backend - - backend = backends[name][host][repository] - return backend - - -@audeer.deprecated( - removal_version="2.2.0", - alternative="Backend.__init__() of corresponding backend", -) -def access( - name: str, - host: str, - repository: str, - *, - interface: type[Interface] = Versioned, - interface_kwargs: dict = None, -) -> Interface: - r"""Access repository. - - Returns an ``interface`` instance - to access the ``repository`` - located at ``host`` - on the backend with alias ``name`` - (see :func:`audbackend.register`). - - .. Warning:: - - ``audbackend.access()`` is deprecated - and will be removed in version 2.2.0. - Repositories on backends are instead accessed - by instantiating the corresponding backend class, - and connecting to it using the ``open()`` method, - e.g. - - .. code-block:: python - - backend = audbackend.backend.FileSystem(host, repo) - backend.open() - - Args: - name: backend alias - host: host address - repository: repository name - interface: interface class - interface_kwargs: keyword arguments for interface class - - Returns: - interface object - - Raises: - BackendError: if an error is raised on the backend, - e.g. repository does not exist - ValueError: if no backend class with alias ``name`` - has been registered - - """ # noqa: E501 - backend = _backend(name, host, repository) - utils.call_function_on_backend(backend._open) - interface_kwargs = interface_kwargs or {} - return interface(backend, **interface_kwargs) - - -@audeer.deprecated( - removal_version="2.2.0", - alternative="class method Backend.create() of corresponding backend", -) -def create( - name: str, - host: str, - repository: str, -): - r"""Create repository. - - Creates ``repository`` - located at ``host`` - on the backend with alias ``name`` - (see :func:`audbackend.register`). - - .. note:: For legacy reasons the method - returns an (undocumented) instance of - :class:`audbackend.interface.Versioned`. - Since the return value might be removed in - a future version it is not recommended to use it. - - .. Warning:: - - ``audbackend.create()`` is deprecated - and will be removed in version 2.2.0. - Repositories on backends are instead created - by the class method ``create()`` - for the desired backend, - e.g. :meth:`audbackend.backend.FileSystem.create`. - - Args: - name: backend alias - host: host address - repository: repository name - - Raises: - BackendError: if an error is raised on the backend, - e.g. repository exists already - or cannot be created - ValueError: if no backend class with alias ``name`` - has been registered - - """ # noqa: E501 - backend = _backend(name, host, repository) - utils.call_function_on_backend(backend._create) - # for legacy reasons we return a versioned interface - return Versioned(backend) - - -@audeer.deprecated( - removal_version="2.2.0", - alternative="class method Backend.delete() of corresponding backend", -) -def delete( - name: str, - host: str, - repository: str, -): - r"""Delete repository. - - Deletes the repository - with name ``repository`` - located at ``host`` - on the backend with alias ``name``. - - .. Warning:: - - ``audbackend.delete()`` is deprecated - and will be removed in version 2.2.0. - Repositories on backends are instead deleted - by the class method ``delete()`` - for the desired backend, - e.g. :meth:`audbackend.backend.FileSystem.delete`. - - Args: - name: backend alias - host: host address - repository: repository name - - Raises: - BackendError: if an error is raised on the backend, - e.g. repository does not exist - ValueError: if no backend class with alias ``name`` - has been registered - - """ # noqa: E501 - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - interface = access(name, host, repository) - utils.call_function_on_backend(interface._backend._delete) - backends[name][host].pop(repository) - - -@audeer.deprecated(removal_version="2.2.0", alternative="backend classes directly") -def register( - name: str, - cls: type[Base], -): - r"""Register backend class. - - If there is already a backend class - registered under the alias ``name`` - it will be overwritten. - - .. Warning:: - - ``audbackend.register()`` is deprecated - and will be removed in version 2.2.0. - Instead of backend names - we now use backend classes, - such as :class:`audbackend.backend.FileSystem`. - - Args: - name: backend alias - cls: backend class - - """ - backend_registry[name] = cls - - -with warnings.catch_warnings(): - warnings.simplefilter("ignore") - register("file-system", FileSystem) - - # Register optional backends - try: - from audbackend.core.backend.artifactory import Artifactory - - register("artifactory", Artifactory) - except ImportError: # pragma: no cover - pass - - # Register optional backends - try: - from audbackend.core.backend.minio import Minio - - register("minio", Minio) - except ImportError: # pragma: no cover - pass diff --git a/audbackend/core/backend/artifactory.py b/audbackend/core/backend/artifactory.py index f02d7d25..3b928144 100644 --- a/audbackend/core/backend/artifactory.py +++ b/audbackend/core/backend/artifactory.py @@ -219,7 +219,7 @@ def _copy_file( def _create( self, ): - r"""Access existing repository.""" + r"""Create repository.""" with requests.Session() as session: session.auth = self.authentication path = artifactory.ArtifactoryPath(self.host, session=session) diff --git a/audbackend/core/backend/filesystem.py b/audbackend/core/backend/filesystem.py index eff8d04c..c6b09e17 100644 --- a/audbackend/core/backend/filesystem.py +++ b/audbackend/core/backend/filesystem.py @@ -64,7 +64,7 @@ def _copy_file( def _create( self, ): - r"""Access existing repository.""" + r"""Create repository.""" if os.path.exists(self._root): utils.raise_file_exists_error(self._root) diff --git a/docs/api-src/audbackend.rst b/docs/api-src/audbackend.rst index bea27688..2fd8359c 100644 --- a/docs/api-src/audbackend.rst +++ b/docs/api-src/audbackend.rst @@ -31,8 +31,4 @@ and functions are available. BackendError Repository - access checksum - create - delete - register diff --git a/tests/conftest.py b/tests/conftest.py index e0e3d2eb..8dd54aac 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,8 +7,6 @@ import audbackend -from singlefolder import SingleFolder - # UID for test session # Repositories on the host will be named @@ -47,16 +45,6 @@ def authentication(): del os.environ[key] -@pytest.fixture(scope="package", autouse=True) -def register_single_folder(): - warning = ( - "register is deprecated and will be removed with version 2.2.0. " - "Use backend classes directly instead." - ) - with pytest.warns(UserWarning, match=warning): - audbackend.register("single-folder", SingleFolder) - - @pytest.fixture(scope="package", autouse=False) def hosts(tmpdir_factory): return { diff --git a/tests/test_api.py b/tests/test_api.py deleted file mode 100644 index 417d4dcb..00000000 --- a/tests/test_api.py +++ /dev/null @@ -1,108 +0,0 @@ -import sys - -import pytest - -import audeer - -import audbackend - - -@pytest.mark.parametrize( - "name, host, repository, expected_class", - [ - ( - "file-system", - "file-system", - f"unittest-{audeer.uid()[:8]}", - "audbackend.backend.FileSystem", - ), - pytest.param( - "artifactory", - "artifactory", - f"unittest-{audeer.uid()[:8]}", - "audbackend.backend.Artifactory", - marks=pytest.mark.skipif( - sys.version_info >= (3, 12), - reason="Requires Python<3.12", - ), - ), - ( - "minio", - "minio", - f"unittest-{audeer.uid()[:8]}", - "audbackend.backend.Minio", - ), - pytest.param( # backend does not exist - "bad-backend", - None, - None, - None, - marks=pytest.mark.xfail(raises=ValueError), - ), - pytest.param( # host does not exist - "minio", - "bad-host", - "repo", - None, - marks=pytest.mark.xfail(raises=audbackend.BackendError), - ), - pytest.param( # invalid repository name - "minio", - "minio", - "bad/repo", - None, - marks=pytest.mark.xfail(raises=audbackend.BackendError), - ), - ], -) -def test_api(hosts, name, host, repository, expected_class): - if host is not None and host in hosts: - host = hosts[name] - - access_warning = ( - "access is deprecated and will be removed with version 2.2.0. " - r"Use Backend.__init__\(\) of corresponding backend instead." - ) - create_warning = ( - "create is deprecated and will be removed with version 2.2.0. " - r"Use class method Backend.create\(\) of corresponding backend instead." - ) - delete_warning = ( - "delete is deprecated and will be removed with version 2.2.0. " - r"Use class method Backend.delete\(\) of corresponding backend instead." - ) - - error_msg = "A backend class with name 'bad' does not exist." - with pytest.raises(ValueError, match=error_msg): - with pytest.warns(UserWarning, match=access_warning): - audbackend.access("bad", host, repository) - - error_msg = ( - "An exception was raised by the backend, " - "please see stack trace for further information." - ) - - with pytest.raises(audbackend.BackendError, match=error_msg): - with pytest.warns(UserWarning, match=access_warning): - audbackend.access(name, host, repository) - - # returns versioned interface for legacy reasons - with pytest.warns(UserWarning, match=create_warning): - interface = audbackend.create(name, host, repository) - assert isinstance(interface, audbackend.interface.Versioned) - assert str(interface.backend).startswith(expected_class) - - with pytest.raises(audbackend.BackendError, match=error_msg): - with pytest.warns(UserWarning, match=create_warning): - audbackend.create(name, host, repository) - - with pytest.warns(UserWarning, match=access_warning): - interface = audbackend.access(name, host, repository) - assert str(interface.backend).startswith(expected_class) - - with pytest.warns(UserWarning, match=delete_warning): - audbackend.delete(name, host, repository) - - with pytest.raises(audbackend.BackendError, match=error_msg): - with pytest.warns(UserWarning, match=access_warning): - audbackend.access(name, host, repository) diff --git a/tests/test_backend_artifactory.py b/tests/test_backend_artifactory.py index 48d77ffc..9926ff40 100644 --- a/tests/test_backend_artifactory.py +++ b/tests/test_backend_artifactory.py @@ -74,6 +74,9 @@ def test_authentication(tmpdir, hosts, hide_credentials): @pytest.mark.parametrize("repository", [f"unittest-{pytest.UID}-{audeer.uid()[:8]}"]) def test_create_delete_repositories(host, repository): audbackend.backend.Artifactory.create(host, repository) + with pytest.raises(audbackend.BackendError): + # Repository exists already + audbackend.backend.Artifactory.create(host, repository) audbackend.backend.Artifactory.delete(host, repository) @@ -213,3 +216,15 @@ def test_maven_file_structure( assert url_expected == url assert interface.ls(file) == [(file, version)] assert interface.ls() == [(file, version)] + + +@pytest.mark.parametrize("host", [pytest.HOSTS["artifactory"]]) +@pytest.mark.parametrize("repository", [f"unittest-{pytest.UID}-{audeer.uid()[:8]}"]) +def test_open_close(host, repository): + backend = audbackend.backend.Artifactory(host, repository) + with pytest.raises(audbackend.BackendError): + # Repository does not exist yet + backend.open() + audbackend.backend.Artifactory.create(host, repository) + backend.open() + backend.close() diff --git a/tests/test_backend_filesystem.py b/tests/test_backend_filesystem.py index 1ed2a9ac..000b4cec 100644 --- a/tests/test_backend_filesystem.py +++ b/tests/test_backend_filesystem.py @@ -9,6 +9,16 @@ from bad_file_system import BadFileSystem +@pytest.mark.parametrize("repository", [f"unittest-{pytest.UID}-{audeer.uid()[:8]}"]) +def test_create_delete_repositories(tmpdir, repository): + host = audeer.mkdir(tmpdir, "host") + audbackend.backend.FileSystem.create(host, repository) + with pytest.raises(audbackend.BackendError): + # Repository exists already + audbackend.backend.FileSystem.create(host, repository) + audbackend.backend.FileSystem.delete(host, repository) + + @pytest.mark.parametrize( "interface", [(BadFileSystem, audbackend.interface.Versioned)], @@ -167,3 +177,15 @@ def test_maven_file_structure( assert path_expected == path assert interface.ls(file) == [(file, version)] assert interface.ls() == [(file, version)] + + +@pytest.mark.parametrize("repository", [f"unittest-{pytest.UID}-{audeer.uid()[:8]}"]) +def test_open_close(tmpdir, repository): + host = audeer.mkdir(tmpdir, "host") + backend = audbackend.backend.FileSystem(host, repository) + with pytest.raises(audbackend.BackendError): + # Repository does not exist yet + backend.open() + audbackend.backend.FileSystem.create(host, repository) + backend.open() + backend.close() diff --git a/tests/test_backend_minio.py b/tests/test_backend_minio.py index 6fc71e61..1778161c 100644 --- a/tests/test_backend_minio.py +++ b/tests/test_backend_minio.py @@ -138,6 +138,9 @@ def test_copy_large_file(tmpdir, interface, src_path, dst_path): @pytest.mark.parametrize("repository", [f"unittest-{pytest.UID}-{audeer.uid()[:8]}"]) def test_create_delete_repositories(host, repository): audbackend.backend.Minio.create(host, repository) + with pytest.raises(audbackend.BackendError): + # Repository exists already + audbackend.backend.Minio.create(host, repository) audbackend.backend.Minio.delete(host, repository) @@ -342,3 +345,15 @@ def test_maven_file_structure( assert url_expected == url assert interface.ls(file) == [(file, version)] assert interface.ls() == [(file, version)] + + +@pytest.mark.parametrize("host", [pytest.HOSTS["minio"]]) +@pytest.mark.parametrize("repository", [f"unittest-{pytest.UID}-{audeer.uid()[:8]}"]) +def test_open_close(host, repository): + backend = audbackend.backend.Minio(host, repository) + with pytest.raises(audbackend.BackendError): + # Repository does not exist yet + backend.open() + audbackend.backend.Minio.create(host, repository) + backend.open() + backend.close()