Skip to content

Commit ff6ff6f

Browse files
authored
Merge pull request #368 from will-0/fix-multilayer-relative-imports
Fix multilayer relative imports
2 parents c35816f + 4e45c49 commit ff6ff6f

File tree

6 files changed

+51
-6
lines changed

6 files changed

+51
-6
lines changed

linkml_runtime/utils/schemaview.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from typing import Optional, TypeVar
1111
from collections.abc import Mapping
1212
import warnings
13+
from urllib.parse import urlparse
1314

1415
from linkml_runtime.utils.namespaces import Namespaces
1516
from deprecated.classic import deprecated
@@ -107,6 +108,25 @@ def is_absolute_path(path: str) -> bool:
107108
drive, tail = os.path.splitdrive(norm_path)
108109
return bool(drive and tail)
109110

111+
def _resolve_import(source_sch: str, imported_sch: str) -> str:
112+
if os.path.isabs(imported_sch):
113+
# Absolute import paths are not modified
114+
return imported_sch
115+
if urlparse(imported_sch).scheme:
116+
# File with URL schemes are not modified
117+
return imported_sch
118+
119+
if WINDOWS:
120+
path = PurePath(os.path.normpath(PurePath(source_sch).parent / imported_sch)).as_posix()
121+
else:
122+
path = os.path.normpath(str(Path(source_sch).parent / imported_sch))
123+
124+
if imported_sch.startswith(".") and not path.startswith("."):
125+
# Above condition handles cases where both source schema and imported schema are relative paths: these should remain relative
126+
return f"./{path}"
127+
128+
return path
129+
110130

111131
@dataclass
112132
class SchemaUsage:
@@ -306,12 +326,7 @@ def imports_closure(self, imports: bool = True, traverse: Optional[bool] = None,
306326
# - subdir/types.yaml
307327
# we should treat the two `types.yaml` as separate schemas from the POV of the
308328
# origin schema.
309-
if sn.startswith('.') and ':' not in i:
310-
if WINDOWS:
311-
# This cannot be simplified. os.path.normpath() must be called before .as_posix()
312-
i = PurePath(os.path.normpath(PurePath(sn).parent / i)).as_posix()
313-
else:
314-
i = os.path.normpath(str(Path(sn).parent / i))
329+
i = _resolve_import(sn, i)
315330
todo.append(i)
316331

317332
# add item to closure
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
id: greatgrandchild
2+
name: greatgrandchild
3+
title: greatgrandchild
4+
imports:
5+
- linkml:types
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
id: grandchild
2+
name: grandchild
3+
title: grandchild
4+
imports:
5+
- linkml:types
6+
- ./L4_2_0_0_0/greatgrandchild
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
id: child
2+
name: child
3+
title: child
4+
imports:
5+
- linkml:types
6+
- ./L3_2_0_0/grandchild
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
id: main
2+
name: main
3+
title: main
4+
imports:
5+
- linkml:types
6+
- ./L2_2_0/child

tests/test_utils/test_schemaview.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
SCHEMA_WITH_STRUCTURED_PATTERNS = Path(INPUT_DIR) / "pattern-example.yaml"
2323
SCHEMA_IMPORT_TREE = Path(INPUT_DIR) / 'imports' / 'main.yaml'
2424
SCHEMA_RELATIVE_IMPORT_TREE = Path(INPUT_DIR) / 'imports_relative' / 'L0_0' / 'L1_0_0' / 'main.yaml'
25+
SCHEMA_RELATIVE_IMPORT_TREE2 = Path(INPUT_DIR) / 'imports_relative' / 'L0_2' / 'main.yaml'
26+
2527

2628
yaml_loader = YAMLLoader()
2729
IS_CURRENT = 'is current'
@@ -553,6 +555,11 @@ def test_imports_relative():
553555
assert 'L2100Index' in classes
554556
assert 'L2101Index' in classes
555557

558+
def test_imports_relative_load():
559+
"""Relative imports from relative imports should load without FileNotFoundError."""
560+
sv = SchemaView(SCHEMA_RELATIVE_IMPORT_TREE2)
561+
sv.imports_closure(imports=True)
562+
556563

557564
def test_direct_remote_imports():
558565
"""Tests that building a SchemaView directly from a remote URL works."""

0 commit comments

Comments
 (0)