Skip to content

Commit 9501812

Browse files
authored
Merge pull request #391 from dalito/issue2696-curie-vs-path-on-windows
Fix detection of CURIES vs. absolute paths on Windows
2 parents b2206a4 + cd17c76 commit 9501812

File tree

3 files changed

+85
-53
lines changed

3 files changed

+85
-53
lines changed

.github/workflows/test-upstream.yaml

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
run: |
4343
set +e
4444
set +o pipefail
45-
45+
4646
UPSTREAM_BRANCH=$( \
4747
echo "$PR_BODY" | \
4848
head -2 | \
@@ -52,12 +52,12 @@ jobs:
5252
)
5353
echo "Got upstream branch:"
5454
echo $UPSTREAM_BRANCH
55-
55+
5656
if [[ -z "$UPSTREAM_BRANCH" ]]; then
5757
echo "Using main as default"
5858
UPSTREAM_BRANCH="main"
5959
fi
60-
60+
6161
UPSTREAM_REPO=$( \
6262
echo "$PR_BODY" | \
6363
head -2 | \
@@ -67,7 +67,7 @@ jobs:
6767
)
6868
echo "Got upstream repo:"
6969
echo $UPSTREAM_REPO
70-
70+
7171
if [[ -z "$UPSTREAM_REPO" ]]; then
7272
echo "Using linkml/linkml as default"
7373
UPSTREAM_REPO="linkml/linkml"
@@ -128,11 +128,6 @@ jobs:
128128
path: linkml/.venv
129129
key: venv-${{ matrix.python-version }}-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
130130

131-
# make extra sure we're removing any old version of linkml-runtime that exists
132-
- name: uninstall potentially cached linkml-runtime
133-
working-directory: linkml
134-
run: poetry run pip uninstall -y linkml-runtime
135-
136131
# we are not using linkml-runtime's lockfile, but simulating what will happen
137132
# when we merge this and update linkml's lockfile
138133
- name: add linkml-runtime to lockfile
@@ -145,7 +140,7 @@ jobs:
145140
# the cache will still speedup the rest of the installation
146141
- name: install linkml
147142
working-directory: linkml
148-
run: poetry install --no-interaction -E tests
143+
run: poetry sync --no-interaction --all-extras
149144

150145
- name: print linkml-runtime version
151146
working-directory: linkml

linkml_runtime/utils/context_utils.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
import yaml
77
from jsonasobj2 import JsonObj, loads
88

9+
from typing import TYPE_CHECKING
10+
11+
if TYPE_CHECKING:
12+
from linkml_runtime.utils.namespaces import Namespaces
13+
14+
915
CONTEXT_TYPE = Union[str, dict, JsonObj]
1016
CONTEXTS_PARAM_TYPE = Optional[Union[CONTEXT_TYPE, list[CONTEXT_TYPE]]]
1117

@@ -50,7 +56,7 @@ def to_file_uri(fname: str) -> str:
5056
JsonObj(**{"@context": context_list[0] if len(context_list) == 1 else context_list})
5157

5258

53-
def map_import(importmap: dict[str, str], namespaces: Callable[[None], "Namespaces"], imp: Any) -> str:
59+
def map_import(importmap: dict[str, str], namespaces: Callable[[], "Namespaces"], imp: Any) -> str:
5460
"""
5561
lookup an import in an importmap.
5662
@@ -73,7 +79,8 @@ def map_import(importmap: dict[str, str], namespaces: Callable[[None], "Namespac
7379
else:
7480
sname = os.path.join(expanded_prefix, lname)
7581
sname = importmap.get(sname, sname) # Import map may use CURIE
76-
sname = str(namespaces().uri_for(sname)) if ':' in sname else sname
82+
if ':' in sname and not ":\\" in sname: # Don't interpret Windows paths as CURIEs
83+
sname = str(namespaces().uri_for(sname))
7784
return importmap.get(sname, sname) # It may also use URI or other forms
7885

7986

@@ -103,7 +110,7 @@ def parse_import_map(map_: Optional[Union[str, dict[str, str], TextIOWrapper]],
103110
if base:
104111
outmap = dict()
105112
for k, v in rval.items():
106-
if ':' not in v:
113+
if ':' not in v or ":\\" in v: # Don't interpret Windows paths as CURIEs
107114
v = os.path.join(os.path.abspath(base), v)
108115
outmap[k] = v
109116
rval = outmap
Lines changed: 70 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
import unittest
1+
import os
2+
import pytest
23

34
from jsonasobj2 import JsonObj, loads
5+
from rdflib import URIRef
6+
7+
from linkml_runtime.linkml_model.meta import ClassDefinition, Prefix, SchemaDefinition
8+
from linkml_runtime.utils.context_utils import map_import, merge_contexts
9+
from linkml_runtime.utils.namespaces import Namespaces
410

5-
from linkml_runtime.utils.context_utils import merge_contexts
611
from tests.test_utils import METAMODEL_CONTEXT_URI, META_BASE_URI
712

813
json_1 = '{ "ex": "http://example.org/test/", "ex2": "http://example.org/test2/" }'
@@ -26,43 +31,47 @@
2631
}"""
2732

2833

29-
class ContextUtilsTestCase(unittest.TestCase):
30-
def test_merge_contexts(self):
31-
self.assertIsNone(merge_contexts())
32-
self.assertEqual('file://local.jsonld', merge_contexts("local.jsonld")['@context'])
33-
self.assertEqual('file://local.jsonld', merge_contexts(["local.jsonld"])['@context'])
34-
self.assertEqual(METAMODEL_CONTEXT_URI, merge_contexts(METAMODEL_CONTEXT_URI)['@context'])
35-
self.assertEqual(METAMODEL_CONTEXT_URI, merge_contexts([METAMODEL_CONTEXT_URI])['@context'])
36-
self.assertEqual(JsonObj(ex='http://example.org/test/', ex2='http://example.org/test2/'),
37-
merge_contexts(json_1)['@context'])
38-
self.assertEqual(JsonObj(ex='http://example.org/test/', ex2='http://example.org/test2/'),
39-
merge_contexts([json_1])['@context'])
40-
self.assertEqual(JsonObj(ex='http://example.org/test3/', ex2=JsonObj(**{'@id': 'http://example.org/test4/'})),
41-
merge_contexts(json_2)['@context'])
42-
self.assertEqual(JsonObj(ex='http://example.org/test3/', ex2=JsonObj(**{'@id': 'http://example.org/test4/'})),
43-
merge_contexts([json_2])['@context'])
44-
self.assertEqual([f'file://local.jsonld',
45-
'https://w3id.org/linkml/meta.context.jsonld',
46-
JsonObj(ex='http://example.org/test/', ex2='http://example.org/test2/'),
47-
JsonObj(ex='http://example.org/test3/', ex2=JsonObj(**{'@id': 'http://example.org/test4/'}))],
48-
merge_contexts(["local.jsonld", METAMODEL_CONTEXT_URI, json_1, json_2])['@context'])
49-
self.assertEqual(loads(context_output),
50-
merge_contexts(["local.jsonld", METAMODEL_CONTEXT_URI, json_1, json_2]))
34+
def test_merge_contexts():
35+
assert merge_contexts() is None
36+
assert "file://local.jsonld" == merge_contexts("local.jsonld")["@context"]
37+
assert "file://local.jsonld" == merge_contexts(["local.jsonld"])["@context"]
38+
assert METAMODEL_CONTEXT_URI == merge_contexts(METAMODEL_CONTEXT_URI)["@context"]
39+
assert METAMODEL_CONTEXT_URI == merge_contexts([METAMODEL_CONTEXT_URI])["@context"]
40+
assert JsonObj(ex="http://example.org/test/", ex2="http://example.org/test2/") == merge_contexts(json_1)["@context"]
41+
assert (
42+
JsonObj(ex="http://example.org/test/", ex2="http://example.org/test2/") == merge_contexts([json_1])["@context"]
43+
)
44+
assert (
45+
JsonObj(ex="http://example.org/test3/", ex2=JsonObj(**{"@id": "http://example.org/test4/"}))
46+
== merge_contexts(json_2)["@context"]
47+
)
48+
assert (
49+
JsonObj(ex="http://example.org/test3/", ex2=JsonObj(**{"@id": "http://example.org/test4/"}))
50+
== merge_contexts([json_2])["@context"]
51+
)
52+
assert [
53+
f"file://local.jsonld",
54+
"https://w3id.org/linkml/meta.context.jsonld",
55+
JsonObj(ex="http://example.org/test/", ex2="http://example.org/test2/"),
56+
JsonObj(ex="http://example.org/test3/", ex2=JsonObj(**{"@id": "http://example.org/test4/"})),
57+
] == merge_contexts(["local.jsonld", METAMODEL_CONTEXT_URI, json_1, json_2])["@context"]
58+
assert loads(context_output) == merge_contexts(["local.jsonld", METAMODEL_CONTEXT_URI, json_1, json_2])
59+
# Dups are not removed
60+
assert JsonObj(
61+
**{
62+
"@context": [
63+
JsonObj(ex="http://example.org/test/", ex2="http://example.org/test2/"),
64+
JsonObj(ex="http://example.org/test/", ex2="http://example.org/test2/"),
65+
]
66+
}
67+
) == merge_contexts([json_1, json_1])
68+
assert "file://local.jsonld", merge_contexts("local.jsonld")["@context"]
5169

52-
# Dups are not removed
53-
self.assertEqual(
54-
JsonObj(**{'@context': [JsonObj(ex='http://example.org/test/', ex2='http://example.org/test2/'),
55-
JsonObj(ex='http://example.org/test/', ex2='http://example.org/test2/')]}),
56-
merge_contexts([json_1, json_1]))
57-
self.assertEqual('file://local.jsonld', merge_contexts("local.jsonld")['@context'])
5870

59-
def test_merge_contexts_base(self):
60-
self.assertEqual(
61-
JsonObj(**{'@context':
62-
JsonObj(**{'@base': 'file://relloc'})}),
63-
merge_contexts(base='file://relloc'))
64-
self.assertEqual(loads(f'{{"@context": {{"@base": "{META_BASE_URI}"}}}}'), merge_contexts(base=META_BASE_URI))
65-
self.assertEqual(loads("""
71+
def test_merge_contexts_base():
72+
assert JsonObj(**{"@context": JsonObj(**{"@base": "file://relloc"})}) == merge_contexts(base="file://relloc")
73+
assert loads(f'{{"@context": {{"@base": "{META_BASE_URI}"}}}}') == merge_contexts(base=META_BASE_URI)
74+
assert loads("""
6675
{"@context": [
6776
"https://w3id.org/linkml/meta.context.jsonld",
6877
{
@@ -79,8 +88,29 @@ def test_merge_contexts_base(self):
7988
"@base": "https://w3id.org/linkml/"
8089
}
8190
]
82-
}"""), merge_contexts([METAMODEL_CONTEXT_URI, json_1, json_2], base=META_BASE_URI))
91+
}""") == merge_contexts([METAMODEL_CONTEXT_URI, json_1, json_2], base=META_BASE_URI)
92+
93+
94+
@pytest.mark.parametrize(
95+
("imp", "result"),
96+
[
97+
("linkml:types", f"C:\\temp\\linkml_model\\model\\schema{os.sep}types"),
98+
("ex_file", "/tmp/example/schema"),
99+
("_types", "https://w3id.org/linkml/types"),
100+
],
101+
)
102+
def test_map_import(imp, result):
103+
importmap = {
104+
"linkml:": "C:\\temp\\linkml_model\\model\\schema",
105+
"ex_file": "/tmp/example/schema",
106+
"_types": "linkml:types",
107+
}
83108

109+
def namespaces():
110+
ns = Namespaces()
111+
ns["linkml"] = URIRef("https://w3id.org/linkml/")
112+
ns["ex_file"] = URIRef("https://example.org/file/")
113+
ns["_types"] = URIRef("https://w3id.org/linkml/types/")
114+
return ns
84115

85-
if __name__ == '__main__':
86-
unittest.main()
116+
assert map_import(importmap, namespaces, imp) == result

0 commit comments

Comments
 (0)