diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 1b3cf9e4..44a627b1 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -28,7 +28,8 @@ jobs: - name: Install ReSDK and its testing dependencies run: | - python${{ env.PYTHON_VERSION }} -m pip install .[test] + uv venv --python=${{ env.PYTHON_VERSION }} + uv sync --extra=test - name: Reset Docker credentials store run: | @@ -141,6 +142,5 @@ jobs: - name: Run tests run: | # Make sure `python` refers to the tox environment's Python - export PATH=`pwd`/.tox/py310-e2e-resdk/bin:$PATH - python${{ env.PYTHON_VERSION }} -m pytest --cov=resdk --cov-report=xml:.reports/resdk_e2e_cov.xml \ + uv run pytest --cov=resdk --cov-report=xml:.reports/resdk_e2e_cov.xml \ --junit-xml=.reports/resdk_e2e_report.xml tests/functional/**/e2e_*.py diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index 5399ead8..792ffe70 100644 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -12,6 +12,11 @@ Added ----- - Add support for ``Python 3.14`` +Fixed +----- +- Fix a bug that prevented the downloading and renaming of + a directory from a data object + =================== 22.2.1 - 2025-11-19 diff --git a/pyproject.toml b/pyproject.toml index 61460821..80ed27b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ dependencies = [ "wrapt", "pytz", "tzlocal", - "pandas", + "pandas<3.0.0", "tqdm", "openpyxl", "xlrd", diff --git a/src/resdk/resources/data.py b/src/resdk/resources/data.py index a34c0f38..477d0f63 100644 --- a/src/resdk/resources/data.py +++ b/src/resdk/resources/data.py @@ -257,6 +257,7 @@ def download( field_name: Optional[str] = None, download_dir: Optional[str] = None, show_progress: bool = True, + return_dir_names: bool = False, ) -> list[str]: """Download Data object's files and directories. @@ -270,6 +271,12 @@ def download( * re.data.get(42).download(file_name='alignment7.bam') * re.data.get(42).download(field_name='bam') + The function returns a list of downloaded file names. In case the + Data object contains directories, the user can specify to return directory names + instead of file names contained in those directories via the return_dir_names argument. + WARNING: If neither file_name nor field_name is specified and return_dir_names is set + to True, the method will download both directories and files when the Data object + contains both. However, the returned list will include only the directory names. """ if file_name and field_name: raise ValueError("Only one of file_name or field_name may be given.") @@ -281,41 +288,52 @@ def download( files=files, download_dir=download_dir, show_progress=show_progress ) - return file_names + dir_names = self._files_dirs("dir", file_name, field_name) + if dir_names and return_dir_names: + asset_names = dir_names + else: + asset_names = file_names + + return asset_names def download_and_rename( self, - custom_file_name: str, + custom_asset_name: str, overwrite_existing: bool = False, field_name: Optional[str] = None, file_name: Optional[str] = None, download_dir: Optional[str] = None, ): - """Download and rename a single file from the Data object.""" + """Download and rename an asset from the Data object.""" if not field_name and not file_name: raise ValueError("Either 'file_name' or 'field_name' must be given.") if download_dir is None: download_dir = os.getcwd() - destination_file_path = os.path.join(download_dir, custom_file_name) - if os.path.exists(destination_file_path) and not overwrite_existing: - raise FileExistsError( - f"File with path '{destination_file_path}' already exists. Skipping download." + destination_asset_path = os.path.join(download_dir, custom_asset_name) + if os.path.exists(destination_asset_path) and not overwrite_existing: + logging.warning( + f"File or directory with path '{destination_asset_path}' already exists. " + "Skipping download." ) + return - source_file_name = self.download( + source_asset_name = self.download( file_name=file_name, field_name=field_name, download_dir=download_dir, + return_dir_names=True, )[0] - source_file_path = os.path.join(download_dir, source_file_name) + source_asset_path = os.path.join(download_dir, source_asset_name) - logging.info(f"Renaming file '{source_file_name}' to '{custom_file_name}'.") + logging.info( + f"Renaming the downloaded asset from '{source_asset_name}' to '{custom_asset_name}'." + ) os.rename( - source_file_path, - destination_file_path, + source_asset_path, + destination_asset_path, ) def stdout(self) -> str: diff --git a/tests/unit/test_data.py b/tests/unit/test_data.py index 3a9ed94f..02f1e590 100644 --- a/tests/unit/test_data.py +++ b/tests/unit/test_data.py @@ -209,13 +209,16 @@ def test_download_ok(self, data_mock): with patch("os.rename") as mock_rename: Data.download_and_rename( data_mock, - custom_file_name="text_file1.txt", + custom_asset_name="text_file1.txt", field_name="txt", download_dir="/some/path/", ) data_mock.download.assert_called_once_with( - file_name=None, field_name="txt", download_dir="/some/path/" + file_name=None, + field_name="txt", + download_dir="/some/path/", + return_dir_names=True, ) mock_rename.assert_called_once()