diff --git a/girder_worker_utils/tests/contrib/girder_io_test.py b/girder_worker_utils/tests/contrib/girder_io_test.py index bbc41f3..7d2e899 100644 --- a/girder_worker_utils/tests/contrib/girder_io_test.py +++ b/girder_worker_utils/tests/contrib/girder_io_test.py @@ -1,56 +1,11 @@ -import os -import sys -import types - import girder_client import mock +import os import pytest from girder_worker_utils.transforms.contrib import girder_io -@pytest.fixture -def mock_file_model(): - girder = types.ModuleType('girder') - girder.models = types.ModuleType('models') - girder.models.file = types.ModuleType('file') - sys.modules['girder'] = girder - sys.modules['girder.models'] = girder.models - sys.modules['girder.models.file'] = girder.models.file - girder.exceptions = types.ModuleType('exceptions') - sys.modules['girder.exceptions'] = girder.exceptions - - def fileObject(): - pass - - girder.models.file.File = lambda: fileObject - return girder.models.file.File() - - -@pytest.fixture -def mock_file_load(mock_file_model): - from girder.models.file import File - - def load(*args, **kwargs): - return {'name': 'the_name'} - - File().load = load - return File() - - -@pytest.fixture -def mock_file_getLocalFilePath(mock_file_model): - import girder.exceptions - from girder.models.file import File - - girder.exceptions.FilePathException = Exception - - def getLocalFilePath(*args, **kwargs): - return os.path.realpath(__file__) - - File().getLocalFilePath = getLocalFilePath - - @pytest.fixture def mock_gc(): return mock.MagicMock(spec=girder_client.GirderClient) @@ -62,9 +17,9 @@ def mock_rmtree(): yield rmtree -def test_GirderFileIdAllowDirect_without_env( - mock_gc, mock_rmtree, mock_file_load, mock_file_getLocalFilePath): - t = girder_io.GirderFileIdAllowDirect(_id='the_id', gc=mock_gc) +def test_GirderFileIdAllowDirect_without_env(mock_gc, mock_rmtree): + local_path = os.path.abspath(__file__) + t = girder_io.GirderFileIdAllowDirect('the_id', 'the_name', local_path, gc=mock_gc) t.transform() mock_gc.downloadFile.assert_called_once() assert 'the_id' in mock_gc.downloadFile.call_args[0] @@ -74,10 +29,21 @@ def test_GirderFileIdAllowDirect_without_env( @mock.patch.dict(os.environ, {'GW_DIRECT_PATHS': 'true'}) -def test_GirderFileIdAllowDirect_with_env( - mock_gc, mock_rmtree, mock_file_load, mock_file_getLocalFilePath): - t = girder_io.GirderFileIdAllowDirect(_id='the_id', gc=mock_gc) +def test_GirderFileIdAllowDirect_with_env(mock_gc, mock_rmtree): + local_path = os.path.abspath(__file__) + t = girder_io.GirderFileIdAllowDirect('the_id', 'the_name', local_path, gc=mock_gc) t.transform() mock_gc.downloadFile.assert_not_called() t.cleanup() mock_rmtree.assert_not_called() + + +@mock.patch.dict(os.environ, {'GW_DIRECT_PATHS': 'true'}) +def test_GirderFileIdAllowDirect_with_env_and_unreachable_file(mock_gc, mock_rmtree): + t = girder_io.GirderFileIdAllowDirect('the_id', 'the_name', 'the_path', gc=mock_gc) + t.transform() + mock_gc.downloadFile.assert_called_once() + assert 'the_id' in mock_gc.downloadFile.call_args[0] + mock_rmtree.assert_not_called() + t.cleanup() + mock_rmtree.assert_called_once() diff --git a/girder_worker_utils/transforms/contrib/girder_io.py b/girder_worker_utils/transforms/contrib/girder_io.py index 06a5e5c..c5048c1 100644 --- a/girder_worker_utils/transforms/contrib/girder_io.py +++ b/girder_worker_utils/transforms/contrib/girder_io.py @@ -9,29 +9,37 @@ class GirderFileIdAllowDirect(GirderClientTransform): """ This transform either uses direct path to access a file, if possible and allowed, or downloads a Girder File to the local machine and passes its - local path into the function. + local path into the function. The direct path is only used if the + GW_DIRECT_PATHS environment variable is set. WARNING: if a direct path is used, the task MUST NOT modify the file. It is the resposibility of the user of this transform to ensure tasks treat files as read-only. + To use this transform from Girder, it should be called via something like: + ``` + try: + local_path = File().getLocalFilePath(file) + except FilePathException: + local_path = None + input_path = GirderFileIdAllowDirect( + str(file['_id']), file['name'], local_path) + ``` + :param _id: The ID of the file to download. :type _id: str + :param name: The name of the file. If the file must be downloaded, the + extension is preserved. + :type name: str + :param local_path: If specified and the path exists and is reachable by + after the transform, the file is accessed directly. + :type local_path: str """ - def __init__(self, _id, **kwargs): + def __init__(self, _id, name='', local_path=None, **kwargs): super(GirderFileIdAllowDirect, self).__init__(**kwargs) - from girder.models.file import File - from girder.exceptions import FilePathException self.file_id = _id - file = File().load(self.file_id, force=True) - # Store the original file name so that, if downloading the file, the - # extension can be preserved. - self.file_name = file['name'] - try: - # Add a local file path if direct paths are allowed - self.local_file_path = File().getLocalFilePath(file) - except FilePathException: - self.local_file_path = None + self.file_name = name + self.local_file_path = local_path def _repr_model_(self): if self.local_file_path: