From 3ff23c9134aa2777e045c58f57ae55826f5cfdd0 Mon Sep 17 00:00:00 2001 From: Adrien Perrin Date: Mon, 19 Feb 2024 10:11:11 +0000 Subject: [PATCH] create symlink to IDF conversion auxiliary files --- .gitignore | 2 +- .../converters/idf/converter.py | 19 +++++- tests/converters/test_idf_converters.py | 63 ++++++++++++++++--- 3 files changed, 74 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index faf15773..d81d3834 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,5 @@ dist build **egg* .coverage -**/auxiliary/** +**/auxiliary **.pyc \ No newline at end of file diff --git a/geospaas_processing/converters/idf/converter.py b/geospaas_processing/converters/idf/converter.py index 3dcca6e6..2eb81ce2 100644 --- a/geospaas_processing/converters/idf/converter.py +++ b/geospaas_processing/converters/idf/converter.py @@ -6,7 +6,6 @@ import re import shutil import subprocess -import sys import tarfile import tempfile from contextlib import closing @@ -22,6 +21,19 @@ class IDFConversionManager(ConversionManager): downloaded_aux = False + @staticmethod + def make_symlink(source, destination): + """Create a symbolic link at `destination` pointing to `source` + If the destination already exists, it is deleted and replaced + with the symlink + """ + if not os.path.islink(destination): + if os.path.isdir(destination): + shutil.rmtree(destination) + elif os.path.isfile(destination): + os.remove(destination) + os.symlink(source, destination) + @classmethod def download_auxiliary_files(cls, auxiliary_path): """Download the auxiliary files necessary for IDF conversion. @@ -50,9 +62,12 @@ def download_auxiliary_files(cls, auxiliary_path): raise cls.downloaded_aux = True + cls.make_symlink(auxiliary_path, os.path.join(os.path.dirname(__file__), 'auxiliary')) + def __init__(self, *args, **kwargs): + download_auxiliary = kwargs.pop('download_auxiliary', True) super().__init__(*args, **kwargs) - if 'unittest' not in sys.modules: # pragma: no cover + if download_auxiliary: # pragma: no cover self.download_auxiliary_files(AUXILIARY_PATH) diff --git a/tests/converters/test_idf_converters.py b/tests/converters/test_idf_converters.py index e7e90a87..086d1f46 100644 --- a/tests/converters/test_idf_converters.py +++ b/tests/converters/test_idf_converters.py @@ -4,6 +4,7 @@ import subprocess import sys import tarfile +import tempfile import unittest import unittest.mock as mock from pathlib import Path @@ -23,9 +24,12 @@ def test_do_not_download_auxiliary_files_if_folder_present(self): is present """ with mock.patch('os.path.isdir', return_value=True), \ - mock.patch('ftplib.FTP') as mock_ftp: + mock.patch('ftplib.FTP') as mock_ftp, \ + mock.patch('geospaas_processing.converters.idf.converter.IDFConversionManager' + '.make_symlink') as mock_make_symlink: idf_converter.IDFConversionManager.download_auxiliary_files('/foo') mock_ftp.assert_not_called() + mock_make_symlink.assert_called() def test_download_auxiliary_files_if_folder_not_present(self): """Test that auxiliary files are downloaded if the folder is @@ -34,10 +38,15 @@ def test_download_auxiliary_files_if_folder_not_present(self): with mock.patch('os.path.isdir', return_value=False), \ mock.patch('os.makedirs'), \ mock.patch('ftplib.FTP') as mock_ftp, \ - mock.patch('tempfile.TemporaryFile'): + mock.patch('tempfile.TemporaryFile'), \ + mock.patch('geospaas_processing.converters.idf.converter.IDFConversionManager' + '.make_symlink') as mock_make_symlink: idf_converter.IDFConversionManager.download_auxiliary_files('/foo') mock_ftp.assert_called() mock_ftp.return_value.retrbinary.assert_called() + mock_make_symlink.assert_called_with( + '/foo', + os.path.join(os.path.dirname(idf_converter.__file__), 'auxiliary')) def test_download_auxiliary_error(self): """Test that partly extracted auxiliary files are removed in @@ -53,21 +62,61 @@ def test_download_auxiliary_error(self): idf_converter.IDFConversionManager.download_auxiliary_files('/foo') mock_rmtree.assert_called_with('/foo') - def test_download_if_no_unittest(self): - """Test that the download happens only if not in the process of - running unit tests + def test_make_symlink(self): + """Test making a symbolic link if none exists""" + with tempfile.TemporaryDirectory() as tmp_dir: + tmp_path = Path(tmp_dir) + source = tmp_path / 'foo' + dest = tmp_path / 'bar' + source.mkdir() + idf_converter.IDFConversionManager.make_symlink(source, dest) + self.assertTrue(dest.is_symlink()) + self.assertEqual(dest.resolve(), source) + + def test_make_symlink_replace_dir(self): + """Test making a symbolic link if a directory exists at the + destination + """ + with tempfile.TemporaryDirectory() as tmp_dir: + tmp_path = Path(tmp_dir) + source = tmp_path / 'foo' + dest = tmp_path / 'bar' + source.mkdir() + dest.mkdir() + idf_converter.IDFConversionManager.make_symlink(source, dest) + self.assertTrue(dest.is_symlink()) + self.assertEqual(dest.resolve(), source) + + def test_make_symlink_replace_file(self): + """Test making a symbolic link if a file exists at the + destination + """ + with tempfile.TemporaryDirectory() as tmp_dir: + tmp_path = Path(tmp_dir) + source = tmp_path / 'foo' + dest = tmp_path / 'bar' + source.mkdir() + dest.touch() + idf_converter.IDFConversionManager.make_symlink(source, dest) + self.assertTrue(dest.is_symlink()) + self.assertEqual(dest.resolve(), source) + + + def test_no_download_arg(self): + """Test that the download does not happen if + `download_auxiliary` is False """ sys_modules = sys.modules.copy() del sys_modules['unittest'] with mock.patch('sys.modules', sys_modules), \ mock.patch('geospaas_processing.converters.idf.converter' '.IDFConversionManager.download_auxiliary_files') as mock_download: - idf_converter.IDFConversionManager('') + idf_converter.IDFConversionManager('', download_auxiliary=True) mock_download.assert_called() with mock.patch('geospaas_processing.converters.idf.converter' '.IDFConversionManager.download_auxiliary_files') as mock_download: - idf_converter.IDFConversionManager('') + idf_converter.IDFConversionManager('', download_auxiliary=False) mock_download.assert_not_called()