Skip to content

Commit

Permalink
feat(loader): Derive entrypoint from filehandler's listing
Browse files Browse the repository at this point in the history
This commit makes the MelodyLoader use the new FileHandler capability to
enumerate files in order to automatically derive the `entrypoint` in
more cases. It will now look into the filehandler's root directory, and
if there is exactly one `.aird` file, that becomes the new entrypoint.

If there is more than one `.aird` file in the root directory, an error
will be raised, and the same is true if the root directory does not
directly contain any `.aird` files. In these cases, it is still
necessary to manually specify the `entrypoint` at load time.
  • Loading branch information
Wuestengecko committed Jul 17, 2023
1 parent f04debb commit edd2c3c
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 23 deletions.
61 changes: 39 additions & 22 deletions capellambse/loader/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import capellambse
import capellambse._namespaces as _n
from capellambse import filehandler, helpers
from capellambse.filehandler import local
from capellambse.loader import exs
from capellambse.loader.modelinfo import ModelInfo

Expand Down Expand Up @@ -86,6 +85,41 @@
METADATA_TAG = f"{{{_n.NAMESPACES['metadata']}}}Metadata"


def _derive_entrypoint(
path: str | os.PathLike | filehandler.FileHandler,
entrypoint: str | pathlib.PurePosixPath | None = None,
) -> tuple[filehandler.FileHandler, pathlib.PurePosixPath]:
if entrypoint:
if not isinstance(path, filehandler.FileHandler):
path = filehandler.get_filehandler(path)
entrypoint = helpers.normalize_pure_path(entrypoint)
return path, entrypoint

if not isinstance(path, filehandler.FileHandler):
path = os.fspath(path)
protocol, nested_path = filehandler.split_protocol(path)
if protocol == "file":
assert isinstance(nested_path, pathlib.Path)
if nested_path.suffix == ".aird":
entrypoint = pathlib.PurePosixPath(nested_path.name)
path = nested_path.parent
return filehandler.get_filehandler(path), entrypoint
elif nested_path.is_file():
raise ValueError(
f"Invalid entrypoint: Not an .aird file: {nested_path}"
)
path = filehandler.get_filehandler(path)

aird_files = [i for i in path.iterdir() if i.name.endswith(".aird")]
if not aird_files:
raise ValueError("No .aird file found, specify entrypoint")
if len(aird_files) > 1:
raise ValueError("Multiple .aird files found, specify entrypoint")
entrypoint = pathlib.PurePosixPath(aird_files[0])

return path, entrypoint


def _verify_extension(filename: pathlib.PurePosixPath) -> None:
"""Check whether ``filename`` has a valid extension."""
file = pathlib.PurePosixPath(filename)
Expand Down Expand Up @@ -382,10 +416,10 @@ def __init__(
"ignore_duplicate_uuids_and_void_all_warranties", False
)

if isinstance(path, filehandler.FileHandler):
handler = path
else:
handler = filehandler.get_filehandler(path, **kwargs)
handler, self.entrypoint = _derive_entrypoint(path, entrypoint)
if self.entrypoint.suffix != ".aird":
raise ValueError("Invalid entrypoint, specify the ``.aird`` file")

self.resources = ResourceLocationManager({"\0": handler})
for resname, reshdl in (resources or {}).items():
if not resname:
Expand All @@ -399,9 +433,6 @@ def __init__(
self.resources[resname] = filehandler.get_filehandler(**reshdl)
else:
self.resources[resname] = reshdl
self.entrypoint = self.__derive_entrypoint(entrypoint)
if self.entrypoint.suffix != ".aird":
raise ValueError("Invalid entrypoint, specify the ``.aird`` file")

self.trees: dict[pathlib.PurePosixPath, ModelFile] = {}
self.__load_referenced_files(
Expand Down Expand Up @@ -432,20 +463,6 @@ def check_duplicate_uuids(self):
" - check the 'resources' for duplicate models"
)

def __derive_entrypoint(
self, entrypoint: str | pathlib.PurePosixPath | None
) -> pathlib.PurePosixPath:
if entrypoint:
return helpers.normalize_pure_path(entrypoint)

if isinstance(self.filehandler, local.LocalFileHandler):
basedir = self.filehandler.path
assert isinstance(basedir, pathlib.Path)
self.filehandler.path = basedir.parent
return helpers.normalize_pure_path(basedir.name)

raise ValueError("This type of file handler needs an ``entrypoint``")

def __load_referenced_files(
self, resource_path: pathlib.PurePosixPath
) -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_model_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def test_model_loading_via_LocalFileHandler(path: str | pathlib.Path):
capellambse.MelodyModel(path)


@pytest.mark.parametrize("suffix", [".capella", ".melodymodel"])
@pytest.mark.parametrize("suffix", [".afm", ".capella"])
def test_model_loading_with_invalid_entrypoint_fails(suffix: str):
with pytest.raises(ValueError, match="(?i)invalid entrypoint"):
capellambse.MelodyModel(TEST_MODEL_5_0.with_suffix(suffix))
Expand Down

0 comments on commit edd2c3c

Please sign in to comment.