Skip to content

Commit 4c4bbc9

Browse files
Merge pull request #478 from linkml/schemaview_get_string_type
schemaview.py: add get_string_type to retrieve typedef for strings
2 parents 65cd85e + 27dbda8 commit 4c4bbc9

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

linkml_runtime/utils/schemaview.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,6 +1831,33 @@ def get_type_designator_slot(self, cn: CLASS_NAME, imports: bool = True) -> Slot
18311831
return s
18321832
return None
18331833

1834+
@lru_cache(None)
1835+
def _get_string_type(self) -> TypeDefinition:
1836+
"""Get the type used for representing strings.
1837+
1838+
This can be used for (e.g.) retrieving the appropriate type for a slot where the range is an enum.
1839+
1840+
The method assumes that the string type will either be called "string" or
1841+
will have the URI "xsd:string", as is the case for the "string" type in linkml:types.
1842+
1843+
This method throws an error if there is anything other than one type that fits the criteria.
1844+
1845+
:return: the "string" type object
1846+
:rtype: TypeDefinition
1847+
"""
1848+
str_type = self.get_type("string")
1849+
if str_type:
1850+
return str_type
1851+
1852+
# if there isn't a type named "string", search for a type with the URI xsd:string
1853+
str_type_arr = [v for v in self.all_types().values() if v.uri == "xsd:string"]
1854+
if len(str_type_arr) == 1:
1855+
return str_type_arr[0]
1856+
1857+
# zero or more than one potential "string" type found
1858+
err_msg = f"Cannot find a suitable 'string' type: no types with name 'string' {'and more than one type with' if str_type_arr else 'or'} uri 'xsd:string'."
1859+
raise ValueError(err_msg)
1860+
18341861
def is_inlined(self, slot: SlotDefinition, imports: bool = True) -> bool:
18351862
"""Return true if slot is inferred or asserted inline.
18361863

tests/test_utils/test_schemaview.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import logging
6+
from contextlib import nullcontext
67
from copy import deepcopy
78
from pathlib import Path
89
from typing import Any
@@ -2126,6 +2127,84 @@ def test_slot_range(
21262127
"""End of range-related tests. Phew!"""
21272128

21282129

2130+
@pytest.fixture(scope="module")
2131+
def enum_string_type_schema() -> str:
2132+
"""Fixture for testing Enum root types."""
2133+
return """
2134+
id: https://example.com/induced_slot_range_root_types_enums
2135+
name: enum_test
2136+
2137+
prefixes:
2138+
xsd: http://www.w3.org/2001/XMLSchema#
2139+
linkml: https://www.w3.org/linkml
2140+
2141+
slots:
2142+
slot_range_enum:
2143+
range: EnumRange
2144+
2145+
slot_range_multi_enum:
2146+
range: Any
2147+
exactly_one_of:
2148+
- range: EnumRange
2149+
- range: AnotherEnumRange
2150+
- range: EnumTheThirdRange
2151+
2152+
classes:
2153+
Any:
2154+
class_uri: linkml:Any
2155+
2156+
TestClass:
2157+
slots:
2158+
- slot_range_enum
2159+
- slot_range_multi_enum
2160+
2161+
enums:
2162+
EnumRange:
2163+
AnotherEnumRange:
2164+
EnumTheThirdRange:
2165+
2166+
"""
2167+
2168+
2169+
@pytest.mark.parametrize(
2170+
("expected", "text_for_schema"),
2171+
[
2172+
(nullcontext("string"), "\ntypes:\n string:\n base: str\n"),
2173+
# retrieve the string using the type URI
2174+
(nullcontext("stringiformes"), "\ntypes:\n stringiformes:\n uri: xsd:string\n base: str\n"),
2175+
# retrieve the string from the imported linkml:types "string"
2176+
(nullcontext("string"), "\nimports:\n - linkml:types\n"),
2177+
# raise an error if there is no "string" type in the schema
2178+
(
2179+
pytest.raises(
2180+
ValueError,
2181+
match="Cannot find a suitable 'string' type: no types with name 'string' or uri 'xsd:string'.",
2182+
),
2183+
"\ntypes:\n\n",
2184+
),
2185+
# raise an error if there are several potential "string" types
2186+
(
2187+
pytest.raises(
2188+
ValueError,
2189+
match="Cannot find a suitable 'string' type: no types with name 'string' and more than one type with uri 'xsd:string'.",
2190+
),
2191+
"types:\n curie:\n uri: xsd:string\n"
2192+
"\n characters:\n uri: xsd:string\n"
2193+
"\n char_seq:\n uri: xsd:string\n",
2194+
),
2195+
],
2196+
)
2197+
def test_induced_get_string_type(enum_string_type_schema: str, expected: Any, text_for_schema: str) -> None:
2198+
"""Ensure that an appropriate string type exists in the schema.
2199+
2200+
Ensures that the appropriate error is thrown if there is no clear string type in a schema.
2201+
"""
2202+
sv = SchemaView(enum_string_type_schema + text_for_schema)
2203+
2204+
with expected as e:
2205+
assert sv._get_string_type() == sv.get_type(e)
2206+
2207+
21292208
def test_permissible_value_relationships(schema_view_no_imports: SchemaView) -> None:
21302209
"""Test relationships between permissible values.
21312210

0 commit comments

Comments
 (0)