Skip to content

Commit

Permalink
Merge pull request #15 from linkml/issue-14
Browse files Browse the repository at this point in the history
issue 14
  • Loading branch information
cmungall authored Feb 2, 2022
2 parents 6c3b38d + 03b58b5 commit b02760e
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 24 deletions.
9 changes: 8 additions & 1 deletion schemasheets/conf/configschema.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Auto generated from configschema.yaml by pythongen.py version: 0.9.0
# Generation date: 2022-01-03T11:25:54
# Generation date: 2022-02-02T11:11:10
# Schema: configschema
#
# id: https://w3id.org/linkml/configschema
Expand Down Expand Up @@ -70,6 +70,7 @@ class ColumnSettings(YAMLRoot):
suffix: Optional[str] = None
template: Optional[str] = None
vmap: Optional[Union[Dict[Union[str, ValueMapMapKey], Union[dict, "ValueMap"]], List[Union[dict, "ValueMap"]]]] = empty_dict()
inner_key: Optional[str] = None
applies_to_class: Optional[str] = None
applies_to_slot: Optional[str] = None
tag: Optional[str] = None
Expand All @@ -89,6 +90,9 @@ def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):

self._normalize_inlined_as_dict(slot_name="vmap", slot_type=ValueMap, key_name="map_key", keyed=True)

if self.inner_key is not None and not isinstance(self.inner_key, str):
self.inner_key = str(self.inner_key)

if self.applies_to_class is not None and not isinstance(self.applies_to_class, str):
self.applies_to_class = str(self.applies_to_class)

Expand Down Expand Up @@ -225,6 +229,9 @@ class slots:
slots.columnSettings__vmap = Slot(uri=THIS.vmap, name="columnSettings__vmap", curie=THIS.curie('vmap'),
model_uri=THIS.columnSettings__vmap, domain=None, range=Optional[Union[Dict[Union[str, ValueMapMapKey], Union[dict, ValueMap]], List[Union[dict, ValueMap]]]])

slots.columnSettings__inner_key = Slot(uri=THIS.inner_key, name="columnSettings__inner_key", curie=THIS.curie('inner_key'),
model_uri=THIS.columnSettings__inner_key, domain=None, range=Optional[str])

slots.columnSettings__applies_to_class = Slot(uri=THIS.applies_to_class, name="columnSettings__applies_to_class", curie=THIS.curie('applies_to_class'),
model_uri=THIS.columnSettings__applies_to_class, domain=None, range=Optional[str])

Expand Down
4 changes: 4 additions & 0 deletions schemasheets/conf/configschema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ classes:
range: ValueMap
multivalued: true
inlined: true
inner_key:
range: string
description: |-
for complex fields such as annotations that are modeled as dicts, this is used to specify which key in the dict the value should be applied to
applies_to_class:
description: |-
if a value C is specified, then this column in the relevant row is interpreted as
Expand Down
27 changes: 20 additions & 7 deletions schemasheets/schemamaker.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
SlotDefinition, EnumDefinition, PermissibleValue, SubsetDefinition, TypeDefinition, Element
from linkml_runtime.utils.schemaview import SchemaView

from schemasheets.utils.configschema import ColumnSettings, Shortcuts, Cardinality
from schemasheets.conf.configschema import ColumnSettings, Shortcuts, Cardinality
from schemasheets.utils.prefixtool import guess_prefix_expansion


Expand Down Expand Up @@ -245,9 +245,7 @@ def merge_sheet(self, file_name: str, delimiter='\t') -> None:
if v is not None and v.startswith('>'):
v = v.replace('>', '')
if v:
#print(f'PARSING: {v}')
meta_obj = yaml.safe_load(v)
#print(f'PARSING: {v} => {meta_obj}')
table_config.add_info(k, meta_obj)
else:
logging.debug(f'Empty val {v} for {k} in {row}')
Expand Down Expand Up @@ -286,16 +284,31 @@ def add_row(self, row: Dict[str, Any], table_config: TableConfig):
if cc.maps_to == 'cardinality':
self.set_cardinality(actual_element, v)
elif cc.metaslot:
if isinstance(v, list):
if cc.maps_to == 'annotations' and not cc.settings.inner_key:
anns = yaml.load(v[0])
for ann_key, ann_val in anns.items():
actual_element.annotations[ann_key] = ann_val
elif isinstance(v, list):
#print(f'SETTING {k} to {v}')
setattr(actual_element, cc.maps_to, getattr(actual_element, cc.maps_to, []) + v)
elif isinstance(v, dict):
for v_k, v_v in v.items():
curr_dict = getattr(actual_element, cc.maps_to)
curr_dict[v_k] = v_v
else:
curr_val = getattr(actual_element, cc.maps_to)
if cc.settings.inner_key:
curr_val = getattr(actual_element, cc.maps_to).get(cc.settings.inner_key, None)
else:
curr_val = getattr(actual_element, cc.maps_to)
if curr_val and curr_val != 'TEMP' and curr_val != v and \
not isinstance(actual_element, SchemaDefinition) and \
not isinstance(actual_element, Prefix):
logging.warning(f'Overwriting value for {k}, was {curr_val}, now {v}')
raise ValueError(f'Cannot reset value for {k}, was {curr_val}, now {v}')
setattr(actual_element, cc.maps_to, v)
if cc.settings.inner_key:
getattr(actual_element, cc.maps_to)[cc.settings.inner_key] = v
else:
setattr(actual_element, cc.maps_to, v)
elif cc.is_element_type:
logging.debug(f'Already accounted for {k}')
elif cc.maps_to == 'metatype':
Expand Down Expand Up @@ -493,7 +506,7 @@ def normalize_value(self, v: str, column_config: ColumnConfig = None) -> Any:
v = bmap[v.lower()]
else:
v = bool(v)
if metaslot and metaslot.multivalued:
if metaslot and metaslot.multivalued and not column_config.settings.inner_key:
if not isinstance(v, list):
if v is None:
v = []
Expand Down
30 changes: 15 additions & 15 deletions tests/input/personinfo.tsv
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
record field key multiplicity range parents desc schema.org wikidata belongs status notes
> class slot identifier cardinality range is_a description exact_mappings: {curie_prefix: sdo} exact_mappings: {curie_prefix: wikidata} in_subset status ignore
> curie_prefix: wikidata vmap: {T: testing, R: release}
id yes 1 string any identifier identifier
description no 0..1 string a textual description description
Person n/a n/a n/a a person,living or dead Person Q215627 R
Person id yes 1 string identifier for a person identifier
Person|Organization name no 1 string full name name
Person age no 0..1 decimal age in years
Person gender no 0..1 decimal age in years
Person has medical history no 0..* MedicalEvent medical history T
Event grouping class for events Q1656682 a R
MedicalEvent n/a n/a n/a Event a medical encounter b T
ForProfit Organization
NonProfit Organization Q163740 foo
record field key multiplicity range parents desc schema.org wikidata belongs status special special2 notes
> class slot identifier cardinality range is_a description exact_mappings: {curie_prefix: sdo} exact_mappings: {curie_prefix: wikidata} in_subset status annotations annotations ignore
> curie_prefix: wikidata vmap: {T: testing, R: release} inner_key: special inner_key: special2
id yes 1 string any identifier identifier
description no 0..1 string a textual description description my_val my_val2
Person n/a n/a n/a a person,living or dead Person Q215627 R
Person id yes 1 string identifier for a person identifier
Person|Organization name no 1 string full name name my_val
Person age no 0..1 decimal age in years
Person gender no 0..1 decimal age in years
Person has medical history no 0..* MedicalEvent medical history T
Event grouping class for events Q1656682 a R
MedicalEvent n/a n/a n/a Event a medical encounter b T
ForProfit Organization
NonProfit Organization Q163740 foo
2 changes: 1 addition & 1 deletion tests/input/personinfo_with_types.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ F age Person no 0..1 decimal age in years
F gender Person no 0..1 decimal age in years
F has medical history Person no 0..* MedicalEvent medical history T
C Person a person,living or dead Person Q215627 R
C Event grouping class for events Q1656682 a R
C Event grouping class for events Q1656682 a R
C MedicalEvent Event a medical encounter b T
C ForProfit Organization
C NonProfit Organization Q163740 foo
5 changes: 5 additions & 0 deletions tests/test_schemamaker.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ def test_classes_slots():
assert person_cls.slot_usage['id'].identifier
assert person_cls.slot_usage['has medical history'].multivalued
assert person_cls.status == 'release'
anns = schema.slots['description'].annotations
assert anns
assert anns['special']
assert anns['special'] == 'my_val'
assert anns['special2'] == 'my_val2'
assert not person_cls.slot_usage['has medical history'].required
assert person_cls.slot_usage['has medical history'].status == 'testing'
assert 'name' in organization_cls.slots
Expand Down

0 comments on commit b02760e

Please sign in to comment.