Skip to content

Commit 7c368fe

Browse files
authored
Merge pull request #832 from dcs4cop/forman-828-fix_module_loading_from_s3
Fix module loading from S3
2 parents 37e1465 + 4bf842b commit 7c368fe

File tree

3 files changed

+60
-15
lines changed

3 files changed

+60
-15
lines changed

CHANGES.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
## Changes in 1.0.1 (in development)
22

3+
### Fixes
4+
5+
* Fixed recurring issue where xcube server was unable to locate Python
6+
code downloaded from S3 when configuring dynamically computed dataset
7+
(configuration `FileSystem: memory`) or augmenting existing datasets
8+
by dynamically computed variables (configuration `Augmentation`). (#828)
9+
310

411
## Changes in 1.0.0
512

test/core/byoa/test_fileset.py

+21-6
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
import os
22
import os.path
3-
import os.path
43
import unittest
4+
import zipfile
5+
6+
import fsspec
57

6-
from xcube.core.byoa.constants import TEMP_FILE_PREFIX
78
from xcube.core.byoa import FileSet
8-
import os
9-
import os.path
10-
import zipfile
9+
from xcube.core.byoa.constants import TEMP_FILE_PREFIX
1110
from xcube.core.dsio import rimraf
1211

1312
PARENT_DIR = os.path.dirname(__file__)
1413

1514

1615
class FileSetToLocalTest(unittest.TestCase):
17-
1816
test_dir = os.path.join(os.path.dirname(__file__), 'test-data')
1917

2018
def setUp(self) -> None:
@@ -47,6 +45,23 @@ def test_to_local_from_local_dir(self):
4745
local_file_set = file_set.to_local()
4846
self.assertIs(local_file_set, file_set)
4947

48+
def test_to_local_from_memory_dir(self):
49+
mem_fs: fsspec.AbstractFileSystem = fsspec.filesystem("memory")
50+
mem_fs.mkdir("package")
51+
mem_fs.touch("package/__init__.py")
52+
mem_fs.touch("package/module1.py")
53+
mem_fs.mkdir("package/module2")
54+
mem_fs.touch("package/module2/__init__.py")
55+
file_set = FileSet("memory://package")
56+
local_file_set = file_set.to_local()
57+
self.assertTrue(os.path.isdir(local_file_set.path))
58+
self.assertTrue(os.path.isfile(local_file_set.path
59+
+ "/__init__.py"))
60+
self.assertTrue(os.path.isfile(local_file_set.path
61+
+ "/module1.py"))
62+
self.assertTrue(os.path.isfile(local_file_set.path
63+
+ "/module2/__init__.py"))
64+
5065
def test_to_local_from_local_flat_zip(self):
5166
zip_path = self._make_zip()
5267
file_set = FileSet(zip_path)

xcube/core/byoa/fileset.py

+32-9
Original file line numberDiff line numberDiff line change
@@ -257,15 +257,38 @@ def to_local(self) -> 'FileSet':
257257
if fs.isdir(root):
258258
temp_dir = new_temp_dir(prefix=TEMP_FILE_PREFIX,
259259
suffix=temp_file_suffix)
260-
# Note, AbstractFileSystem.get() behaves
261-
# unpredictably. Sometimes it will create a new directory
262-
# named after root in temp_dir (e.g. this is the case
263-
# if temp_dir exists). To avoid this, we add a non-existing
264-
# directory here:
265-
temp_dir += "/data"
266-
# TODO: replace by loop so we can apply includes/excludes
267-
# before downloading actual files. See impl of fs.get().
268-
fs.get(root + "/*", temp_dir, recursive=True)
260+
261+
# Note, actually want to use
262+
# fs.get(root + "/*", temp_dir, recursive=True)
263+
# here, but fs.get() behaves unpredictably with
264+
# fsspec=2023.3.0 and s3fs=2023.3.0.
265+
# Sometimes it will create a new subdirectory in temp_dir
266+
# named after last path element of root, sometimes not.
267+
# Behaviour randomly changes if
268+
# - temp_dir exists or not
269+
# - root or temp_dir paths end with a slash
270+
# - whether root or temp_dir are absolute path or not.
271+
#
272+
# See https://github.com/dcs4cop/xcube/issues/828
273+
#
274+
# Workaround used here is to manually download the directory.
275+
276+
def get_files(source: str, target: str):
277+
source_items = fs.listdir(source, detail=True)
278+
for source_item in source_items:
279+
source_path = source_item["name"]
280+
source_type = source_item["type"]
281+
source_name = source_path.replace("\\", "/") \
282+
.split("/")[-1]
283+
target_path = os.path.join(target, source_name)
284+
if source_type == "file":
285+
fs.get_file(source_path, target_path)
286+
elif source_type == "directory":
287+
os.mkdir(target_path)
288+
get_files(source_path, target_path)
289+
290+
get_files(root, temp_dir)
291+
269292
return FileSet(temp_dir,
270293
sub_path=self.sub_path,
271294
includes=self.includes,

0 commit comments

Comments
 (0)