diff --git a/Makefile b/Makefile index 90993e9..4119291 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,6 @@ deploy: all deploy-gh-doc # TODO: make this default src/linkml_map/datamodel/transformer_model.py: src/linkml_map/datamodel/transformer_model.yaml - # $(RUN) gen-pydantic --pydantic-version 2 $< > $@.tmp && mv $@.tmp $@ $(RUN) gen-pydantic $< > $@.tmp && mv $@.tmp $@ # generates all project files diff --git a/src/linkml_map/compiler/graphviz_compiler.py b/src/linkml_map/compiler/graphviz_compiler.py index 846abdd..a92a8b8 100644 --- a/src/linkml_map/compiler/graphviz_compiler.py +++ b/src/linkml_map/compiler/graphviz_compiler.py @@ -84,20 +84,21 @@ def compile( continue source_record = Record(name=source_cn, source="source") target_record = Record(name=target_cn, source="target") - for sd in cd.slot_derivations.values(): - target_slot = sd.name - target_id = f"{target_record.id}:{target_slot}" - source_slot = sd.populated_from - if source_slot: - source_id = f"{source_record.id}:{source_slot}" - dg.edge(source_id, target_id) - elif sd.expr: - # TODO: do this in a less hacky way - tokens = re.findall(r"\w+", sd.expr) - for token in tokens: - if token not in source_schemaview.all_slots(): - continue - dg.edge(f"{source_record.id}:{token}", target_id, style="dashed") + if cd.slot_derivations: + for sd in cd.slot_derivations.values(): + target_slot = sd.name + target_id = f"{target_record.id}:{target_slot}" + source_slot = sd.populated_from + if source_slot: + source_id = f"{source_record.id}:{source_slot}" + dg.edge(source_id, target_id) + elif sd.expr: + # TODO: do this in a less hacky way + tokens = re.findall(r"\w+", sd.expr) + for token in tokens: + if token not in source_schemaview.all_slots(): + continue + dg.edge(f"{source_record.id}:{token}", target_id, style="dashed") return GraphvizObject(digraph=dg, serialization=dg.source) def add_records(self, schemaview: SchemaView, source: str) -> list[Record]: diff --git a/src/linkml_map/compiler/sql_compiler.py b/src/linkml_map/compiler/sql_compiler.py index 2562f0f..4b95ae3 100644 --- a/src/linkml_map/compiler/sql_compiler.py +++ b/src/linkml_map/compiler/sql_compiler.py @@ -61,8 +61,9 @@ def compile_class( else: stmt += f"INSERT INTO {cd.name} SELECT \n" col_trs = [] - for sd in cd.slot_derivations.values(): - col_trs.append(self.compile_slot_derivation(sd)) + if cd.slot_derivations is not None: + for sd in cd.slot_derivations.values(): + col_trs.append(self.compile_slot_derivation(sd)) if not col_trs: return stmt += ", \n".join(col_trs) diff --git a/src/linkml_map/compiler/templates/markdown.j2 b/src/linkml_map/compiler/templates/markdown.j2 index 90e2f6b..eab7bc2 100644 --- a/src/linkml_map/compiler/templates/markdown.j2 +++ b/src/linkml_map/compiler/templates/markdown.j2 @@ -7,19 +7,25 @@ | Target | Target Range | Source | Source Range | Info | | ------ | ------ | ---- | ---- | ---- | + {%- if cd.slot_derivations is not none %} {%- for sd in cd.slot_derivations.values() %} | {{ sd.name }} | | {{ sd.range }} | {% if sd.expr is not none %} [expression] {% else %} {{ sd.populated_from }} {% endif %} | . | . | {%- endfor -%} + {%- endif %} {% endfor %} ## Enum Mappings +{%- if spec.enum_derivations is not none %} {% for ed in spec.enum_derivations.values() %} ### Target enum {{ ed.name }} | Target | Source | Info | | ------ | ------ | ---- | + {%- if ed.permissible_value_derivations is not none %} {%- for pvd in ed.permissible_value_derivations.values() %} | {{ pvd.name }} | {{ pvd.populated_from }} | . | {%- endfor -%} + {%- endif %} {% endfor %} +{%- endif %} diff --git a/src/linkml_map/datamodel/transformer_model.py b/src/linkml_map/datamodel/transformer_model.py index fbcfbf8..5973b5b 100644 --- a/src/linkml_map/datamodel/transformer_model.py +++ b/src/linkml_map/datamodel/transformer_model.py @@ -1,18 +1,32 @@ -from __future__ import annotations +from __future__ import annotations import re import sys -from datetime import date, datetime -from decimal import Decimal -from enum import Enum -from typing import Any, ClassVar, Dict, List, Literal, Optional, Union +from datetime import ( + date, + datetime, + time +) +from decimal import Decimal +from enum import Enum +from typing import ( + Any, + ClassVar, + Dict, + List, + Literal, + Optional, + Union +) -from pydantic.version import VERSION as PYDANTIC_VERSION +from pydantic import ( + BaseModel, + ConfigDict, + Field, + RootModel, + field_validator +) -if int(PYDANTIC_VERSION[0]) >= 2: - from pydantic import BaseModel, ConfigDict, Field, RootModel, field_validator -else: - from pydantic import BaseModel, Field, validator metamodel_version = "None" version = "None" @@ -20,56 +34,82 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( - validate_assignment=True, - validate_default=True, - extra="forbid", - arbitrary_types_allowed=True, - use_enum_values=True, - strict=False, + validate_assignment = True, + validate_default = True, + extra = "forbid", + arbitrary_types_allowed = True, + use_enum_values = True, + strict = False, ) pass + + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} model_config = ConfigDict(frozen=True) - def __getattr__(self, key: str): + def __getattr__(self, key:str): return getattr(self.root, key) - def __getitem__(self, key: str): + def __getitem__(self, key:str): return self.root[key] - def __setitem__(self, key: str, value): + def __setitem__(self, key:str, value): self.root[key] = value - -linkml_meta = LinkMLMeta( - { - "default_prefix": "https://w3id.org/linkml/transformer/", - "description": "Datamodel for LinkML schema mappings and transformations.\n" - "\n" - "A mapper generates instances of a *target* data model from\n" - "instances of a *source* data model. This transformation " - "process\n" - "is guided by a *TransformationSpecification*.\n" - "\n" - "The specification is independent of any one method for " - "transforming\n" - "data. It allows different approaches, including:\n" - "\n" - "- direct implementation, transforming python or json objects\n" - "- translation of the specification into SQL commands, to " - "operate on relations\n" - "- translation of the specification into SPARQL CONSTRUCTs, to " - "operate on triples\n" - "- translation into another specification language, such as " - "R2RML", - "id": "https://w3id.org/linkml/transformer", - "name": "linkml-map", - } -) - + def __contains__(self, key:str) -> bool: + return key in self.root + + +linkml_meta = LinkMLMeta({'default_prefix': 'linkmlmap', + 'description': 'Datamodel for LinkML schema mappings and transformations.\n' + '\n' + 'A mapper generates instances of a *target* data model from\n' + 'instances of a *source* data model. This transformation ' + 'process\n' + 'is guided by a *TransformationSpecification*.\n' + '\n' + 'The specification is independent of any one method for ' + 'transforming\n' + 'data. It allows different approaches, including:\n' + '\n' + '- direct implementation, transforming python or json objects\n' + '- translation of the specification into SQL commands, to ' + 'operate on relations\n' + '- translation of the specification into SPARQL CONSTRUCTs, to ' + 'operate on triples\n' + '- translation into another specification language, such as ' + 'R2RML', + 'id': 'https://w3id.org/linkml/transformer', + 'imports': ['linkml:types'], + 'name': 'linkml-map', + 'prefixes': {'STATO': {'prefix_prefix': 'STATO', + 'prefix_reference': 'http://purl.obolibrary.org/obo/STATO_'}, + 'dcterms': {'prefix_prefix': 'dcterms', + 'prefix_reference': 'http://purl.org/dc/terms/'}, + 'linkml': {'prefix_prefix': 'linkml', + 'prefix_reference': 'https://w3id.org/linkml/'}, + 'linkmlmap': {'prefix_prefix': 'linkmlmap', + 'prefix_reference': 'https://w3id.org/linkml/transformer/'}, + 'rdfs': {'prefix_prefix': 'rdfs', + 'prefix_reference': 'http://www.w3.org/2000/01/rdf-schema#'}, + 'schema': {'prefix_prefix': 'schema', + 'prefix_reference': 'http://schema.org/'}, + 'sh': {'prefix_prefix': 'sh', + 'prefix_reference': 'http://www.w3.org/ns/shacl#'}}, + 'source_file': 'src/linkml_map/datamodel/transformer_model.yaml', + 'title': 'LinkML Map Data Model', + 'types': {'ClassReference': {'from_schema': 'https://w3id.org/linkml/transformer', + 'name': 'ClassReference', + 'typeof': 'string'}, + 'EnumReference': {'from_schema': 'https://w3id.org/linkml/transformer', + 'name': 'EnumReference', + 'typeof': 'string'}, + 'SlotReference': {'from_schema': 'https://w3id.org/linkml/transformer', + 'name': 'SlotReference', + 'typeof': 'string'}}} ) class CollectionType(str, Enum): SingleValued = "SingleValued" @@ -111,1512 +151,513 @@ class PivotDirectionType(str, Enum): UNMELT = "UNMELT" + class SpecificationComponent(ConfiguredBaseModel): - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"abstract": True, "from_schema": "https://w3id.org/linkml/transformer"} - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'abstract': True, 'from_schema': 'https://w3id.org/linkml/transformer'}) - description: Optional[str] = Field( - None, - description="""description of the specification component""", - json_schema_extra={ - "linkml_meta": { - "alias": "description", - "domain_of": ["SpecificationComponent"], - "slot_uri": "dcterms:description", - } - }, - ) - implements: Optional[List[str]] = Field( - default_factory=list, - description="""A reference to a specification that this component implements.""", - json_schema_extra={ - "linkml_meta": {"alias": "implements", "domain_of": ["SpecificationComponent"]} - }, - ) - comments: Optional[List[str]] = Field( - default_factory=list, - description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", - json_schema_extra={ - "linkml_meta": { - "alias": "comments", - "domain_of": ["SpecificationComponent"], - "slot_uri": "rdfs:comment", - } - }, - ) + description: Optional[str] = Field(default=None, description="""description of the specification component""", json_schema_extra = { "linkml_meta": {'alias': 'description', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'dcterms:description'} }) + implements: Optional[List[str]] = Field(default=None, description="""A reference to a specification that this component implements.""", json_schema_extra = { "linkml_meta": {'alias': 'implements', 'domain_of': ['SpecificationComponent']} }) + comments: Optional[List[str]] = Field(default=None, description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", json_schema_extra = { "linkml_meta": {'alias': 'comments', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'rdfs:comment'} }) class TransformationSpecification(SpecificationComponent): """ A collection of mappings between source and target classes """ - - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer", "tree_root": True} - ) - - id: Optional[str] = Field( - None, - description="""Unique identifier for this transformation specification""", - json_schema_extra={ - "linkml_meta": { - "alias": "id", - "domain_of": ["TransformationSpecification"], - "slot_uri": "schema:identifier", - } - }, - ) - title: Optional[str] = Field( - None, - description="""human readable title for this transformation specification""", - json_schema_extra={ - "linkml_meta": { - "alias": "title", - "domain_of": ["TransformationSpecification"], - "slot_uri": "dcterms:title", - } - }, - ) - prefixes: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""maps prefixes to URL expansions""", - json_schema_extra={ - "linkml_meta": { - "alias": "prefixes", - "domain_of": ["TransformationSpecification"], - "slot_uri": "sh:declare", - } - }, - ) - source_schema: Optional[str] = Field( - None, - description="""name of the schema that describes the source (input) objects""", - json_schema_extra={ - "linkml_meta": {"alias": "source_schema", "domain_of": ["TransformationSpecification"]} - }, - ) - target_schema: Optional[str] = Field( - None, - description="""name of the schema that describes the target (output) objects""", - json_schema_extra={ - "linkml_meta": {"alias": "target_schema", "domain_of": ["TransformationSpecification"]} - }, - ) - class_derivations: Optional[Dict[str, ClassDerivation]] = Field( - default_factory=dict, - description="""Instructions on how to derive a set of classes in the target schema from classes in the source schema.""", - json_schema_extra={ - "linkml_meta": { - "alias": "class_derivations", - "domain_of": ["TransformationSpecification"], - } - }, - ) - enum_derivations: Optional[Dict[str, EnumDerivation]] = Field( - default_factory=dict, - description="""Instructions on how to derive a set of enums in the target schema""", - json_schema_extra={ - "linkml_meta": { - "alias": "enum_derivations", - "domain_of": ["TransformationSpecification"], - } - }, - ) - slot_derivations: Optional[Dict[str, SlotDerivation]] = Field( - default_factory=dict, - description="""Instructions on how to derive a set of top level slots in the target schema""", - json_schema_extra={ - "linkml_meta": { - "alias": "slot_derivations", - "domain_of": ["TransformationSpecification", "ClassDerivation"], - } - }, - ) - copy_directives: Optional[Dict[str, CopyDirective]] = Field(default_factory=dict) - description: Optional[str] = Field( - None, - description="""description of the specification component""", - json_schema_extra={ - "linkml_meta": { - "alias": "description", - "domain_of": ["SpecificationComponent"], - "slot_uri": "dcterms:description", - } - }, - ) - implements: Optional[List[str]] = Field( - default_factory=list, - description="""A reference to a specification that this component implements.""", - json_schema_extra={ - "linkml_meta": {"alias": "implements", "domain_of": ["SpecificationComponent"]} - }, - ) - comments: Optional[List[str]] = Field( - default_factory=list, - description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", - json_schema_extra={ - "linkml_meta": { - "alias": "comments", - "domain_of": ["SpecificationComponent"], - "slot_uri": "rdfs:comment", - } - }, - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer', 'tree_root': True}) + + id: Optional[str] = Field(default=None, description="""Unique identifier for this transformation specification""", json_schema_extra = { "linkml_meta": {'alias': 'id', + 'domain_of': ['TransformationSpecification'], + 'slot_uri': 'schema:identifier'} }) + title: Optional[str] = Field(default=None, description="""human readable title for this transformation specification""", json_schema_extra = { "linkml_meta": {'alias': 'title', + 'domain_of': ['TransformationSpecification'], + 'slot_uri': 'dcterms:title'} }) + prefixes: Optional[Dict[str, KeyVal]] = Field(default=None, description="""maps prefixes to URL expansions""", json_schema_extra = { "linkml_meta": {'alias': 'prefixes', + 'domain_of': ['TransformationSpecification'], + 'slot_uri': 'sh:declare'} }) + copy_directives: Optional[Dict[str, CopyDirective]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'copy_directives', + 'domain_of': ['TransformationSpecification', 'ElementDerivation']} }) + source_schema: Optional[str] = Field(default=None, description="""name of the schema that describes the source (input) objects""", json_schema_extra = { "linkml_meta": {'alias': 'source_schema', 'domain_of': ['TransformationSpecification']} }) + target_schema: Optional[str] = Field(default=None, description="""name of the schema that describes the target (output) objects""", json_schema_extra = { "linkml_meta": {'alias': 'target_schema', 'domain_of': ['TransformationSpecification']} }) + class_derivations: Optional[Dict[str, ClassDerivation]] = Field(default=None, description="""Instructions on how to derive a set of classes in the target schema from classes in the source schema.""", json_schema_extra = { "linkml_meta": {'alias': 'class_derivations', + 'domain_of': ['TransformationSpecification', 'ObjectDerivation']} }) + enum_derivations: Optional[Dict[str, EnumDerivation]] = Field(default=None, description="""Instructions on how to derive a set of enums in the target schema""", json_schema_extra = { "linkml_meta": {'alias': 'enum_derivations', 'domain_of': ['TransformationSpecification']} }) + slot_derivations: Optional[Dict[str, SlotDerivation]] = Field(default=None, description="""Instructions on how to derive a set of top level slots in the target schema""", json_schema_extra = { "linkml_meta": {'alias': 'slot_derivations', + 'domain_of': ['TransformationSpecification', 'ClassDerivation']} }) + description: Optional[str] = Field(default=None, description="""description of the specification component""", json_schema_extra = { "linkml_meta": {'alias': 'description', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'dcterms:description'} }) + implements: Optional[List[str]] = Field(default=None, description="""A reference to a specification that this component implements.""", json_schema_extra = { "linkml_meta": {'alias': 'implements', 'domain_of': ['SpecificationComponent']} }) + comments: Optional[List[str]] = Field(default=None, description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", json_schema_extra = { "linkml_meta": {'alias': 'comments', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'rdfs:comment'} }) class ElementDerivation(SpecificationComponent): """ An abstract grouping for classes that provide a specification of how to derive a target element from a source element. """ - - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"abstract": True, "from_schema": "https://w3id.org/linkml/transformer"} - ) - - name: str = Field( - ..., - description="""Name of the element in the target schema""", - json_schema_extra={ - "linkml_meta": { - "alias": "name", - "domain_of": [ - "ElementDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - copy_directives: Optional[Dict[str, CopyDirective]] = Field( - default_factory=dict, - json_schema_extra={ - "linkml_meta": {"alias": "copy_directives", "domain_of": ["ElementDerivation"]} - }, - ) - overrides: Optional[Any] = Field( - None, - description="""overrides source schema slots""", - json_schema_extra={ - "linkml_meta": {"alias": "overrides", "domain_of": ["ElementDerivation"]} - }, - ) - is_a: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "is_a", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:is_a", - } - }, - ) - mixins: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": { - "alias": "mixins", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:mixins", - } - }, - ) - value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table that is applied directly to mappings, in order of precedence""", - json_schema_extra={ - "linkml_meta": {"alias": "value_mappings", "domain_of": ["ElementDerivation"]} - }, - ) - expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_value_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys and values are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_expression_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - mirror_source: Optional[bool] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "mirror_source", "domain_of": ["ElementDerivation"]} - }, - ) - description: Optional[str] = Field( - None, - description="""description of the specification component""", - json_schema_extra={ - "linkml_meta": { - "alias": "description", - "domain_of": ["SpecificationComponent"], - "slot_uri": "dcterms:description", - } - }, - ) - implements: Optional[List[str]] = Field( - default_factory=list, - description="""A reference to a specification that this component implements.""", - json_schema_extra={ - "linkml_meta": {"alias": "implements", "domain_of": ["SpecificationComponent"]} - }, - ) - comments: Optional[List[str]] = Field( - default_factory=list, - description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", - json_schema_extra={ - "linkml_meta": { - "alias": "comments", - "domain_of": ["SpecificationComponent"], - "slot_uri": "rdfs:comment", - } - }, - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'abstract': True, 'from_schema': 'https://w3id.org/linkml/transformer'}) + + name: str = Field(default=..., description="""Name of the element in the target schema""", json_schema_extra = { "linkml_meta": {'alias': 'name', + 'domain_of': ['ElementDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + copy_directives: Optional[Dict[str, CopyDirective]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'copy_directives', + 'domain_of': ['TransformationSpecification', 'ElementDerivation']} }) + overrides: Optional[Any] = Field(default=None, description="""overrides source schema slots""", json_schema_extra = { "linkml_meta": {'alias': 'overrides', 'domain_of': ['ElementDerivation']} }) + is_a: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'is_a', 'domain_of': ['ElementDerivation'], 'slot_uri': 'linkml:is_a'} }) + mixins: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mixins', + 'domain_of': ['ElementDerivation'], + 'slot_uri': 'linkml:mixins'} }) + value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table that is applied directly to mappings, in order of precedence""", json_schema_extra = { "linkml_meta": {'alias': 'value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys and values are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_expression_mappings', + 'domain_of': ['ElementDerivation']} }) + mirror_source: Optional[bool] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mirror_source', 'domain_of': ['ElementDerivation']} }) + description: Optional[str] = Field(default=None, description="""description of the specification component""", json_schema_extra = { "linkml_meta": {'alias': 'description', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'dcterms:description'} }) + implements: Optional[List[str]] = Field(default=None, description="""A reference to a specification that this component implements.""", json_schema_extra = { "linkml_meta": {'alias': 'implements', 'domain_of': ['SpecificationComponent']} }) + comments: Optional[List[str]] = Field(default=None, description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", json_schema_extra = { "linkml_meta": {'alias': 'comments', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'rdfs:comment'} }) class ClassDerivation(ElementDerivation): """ A specification of how to derive a target class from a source class. """ + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer'}) + + populated_from: Optional[str] = Field(default=None, description="""Name of the class in the source schema""", json_schema_extra = { "linkml_meta": {'alias': 'populated_from', + 'domain_of': ['ClassDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + sources: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'sources', + 'domain_of': ['ClassDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + joins: Optional[Dict[str, AliasedClass]] = Field(default=None, description="""Additional classes to be joined to derive instances of the target class""", json_schema_extra = { "linkml_meta": {'alias': 'joins', + 'comments': ['not yet implemented'], + 'domain_of': ['ClassDerivation']} }) + slot_derivations: Optional[Dict[str, SlotDerivation]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'slot_derivations', + 'domain_of': ['TransformationSpecification', 'ClassDerivation']} }) + target_definition: Optional[Any] = Field(default=None, description="""LinkML class definition object for this slot.""", json_schema_extra = { "linkml_meta": {'alias': 'target_definition', + 'comments': ['currently defined as Any to avoid coupling with metamodel'], + 'domain_of': ['ClassDerivation', 'SlotDerivation']} }) + name: str = Field(default=..., description="""Name of the element in the target schema""", json_schema_extra = { "linkml_meta": {'alias': 'name', + 'domain_of': ['ElementDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + copy_directives: Optional[Dict[str, CopyDirective]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'copy_directives', + 'domain_of': ['TransformationSpecification', 'ElementDerivation']} }) + overrides: Optional[Any] = Field(default=None, description="""overrides source schema slots""", json_schema_extra = { "linkml_meta": {'alias': 'overrides', 'domain_of': ['ElementDerivation']} }) + is_a: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'is_a', 'domain_of': ['ElementDerivation'], 'slot_uri': 'linkml:is_a'} }) + mixins: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mixins', + 'domain_of': ['ElementDerivation'], + 'slot_uri': 'linkml:mixins'} }) + value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table that is applied directly to mappings, in order of precedence""", json_schema_extra = { "linkml_meta": {'alias': 'value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys and values are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_expression_mappings', + 'domain_of': ['ElementDerivation']} }) + mirror_source: Optional[bool] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mirror_source', 'domain_of': ['ElementDerivation']} }) + description: Optional[str] = Field(default=None, description="""description of the specification component""", json_schema_extra = { "linkml_meta": {'alias': 'description', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'dcterms:description'} }) + implements: Optional[List[str]] = Field(default=None, description="""A reference to a specification that this component implements.""", json_schema_extra = { "linkml_meta": {'alias': 'implements', 'domain_of': ['SpecificationComponent']} }) + comments: Optional[List[str]] = Field(default=None, description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", json_schema_extra = { "linkml_meta": {'alias': 'comments', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'rdfs:comment'} }) + + +class ObjectDerivation(ElementDerivation): + """ + Temporary placeholder for object_derivations + """ + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer'}) + + class_derivations: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'class_derivations', + 'domain_of': ['TransformationSpecification', 'ObjectDerivation']} }) + name: str = Field(default=..., description="""Name of the element in the target schema""", json_schema_extra = { "linkml_meta": {'alias': 'name', + 'domain_of': ['ElementDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + copy_directives: Optional[Dict[str, CopyDirective]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'copy_directives', + 'domain_of': ['TransformationSpecification', 'ElementDerivation']} }) + overrides: Optional[Any] = Field(default=None, description="""overrides source schema slots""", json_schema_extra = { "linkml_meta": {'alias': 'overrides', 'domain_of': ['ElementDerivation']} }) + is_a: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'is_a', 'domain_of': ['ElementDerivation'], 'slot_uri': 'linkml:is_a'} }) + mixins: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mixins', + 'domain_of': ['ElementDerivation'], + 'slot_uri': 'linkml:mixins'} }) + value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table that is applied directly to mappings, in order of precedence""", json_schema_extra = { "linkml_meta": {'alias': 'value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys and values are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_expression_mappings', + 'domain_of': ['ElementDerivation']} }) + mirror_source: Optional[bool] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mirror_source', 'domain_of': ['ElementDerivation']} }) + description: Optional[str] = Field(default=None, description="""description of the specification component""", json_schema_extra = { "linkml_meta": {'alias': 'description', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'dcterms:description'} }) + implements: Optional[List[str]] = Field(default=None, description="""A reference to a specification that this component implements.""", json_schema_extra = { "linkml_meta": {'alias': 'implements', 'domain_of': ['SpecificationComponent']} }) + comments: Optional[List[str]] = Field(default=None, description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", json_schema_extra = { "linkml_meta": {'alias': 'comments', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'rdfs:comment'} }) - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer"} - ) - - populated_from: Optional[str] = Field( - None, - description="""Name of the class in the source schema""", - json_schema_extra={ - "linkml_meta": { - "alias": "populated_from", - "domain_of": [ - "ClassDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - sources: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": { - "alias": "sources", - "domain_of": [ - "ClassDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - joins: Optional[Dict[str, AliasedClass]] = Field( - default_factory=dict, - description="""Additional classes to be joined to derive instances of the target class""", - json_schema_extra={ - "linkml_meta": { - "alias": "joins", - "comments": ["not yet implemented"], - "domain_of": ["ClassDerivation"], - } - }, - ) - slot_derivations: Optional[Dict[str, SlotDerivation]] = Field( - default_factory=dict, - json_schema_extra={ - "linkml_meta": { - "alias": "slot_derivations", - "domain_of": ["TransformationSpecification", "ClassDerivation"], - } - }, - ) - target_definition: Optional[Any] = Field( - None, - description="""LinkML class definition object for this slot.""", - json_schema_extra={ - "linkml_meta": { - "alias": "target_definition", - "comments": ["currently defined as Any to avoid coupling with metamodel"], - "domain_of": ["ClassDerivation", "SlotDerivation"], - } - }, - ) - name: str = Field( - ..., - description="""Name of the element in the target schema""", - json_schema_extra={ - "linkml_meta": { - "alias": "name", - "domain_of": [ - "ElementDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - copy_directives: Optional[Dict[str, CopyDirective]] = Field( - default_factory=dict, - json_schema_extra={ - "linkml_meta": {"alias": "copy_directives", "domain_of": ["ElementDerivation"]} - }, - ) - overrides: Optional[Any] = Field( - None, - description="""overrides source schema slots""", - json_schema_extra={ - "linkml_meta": {"alias": "overrides", "domain_of": ["ElementDerivation"]} - }, - ) - is_a: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "is_a", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:is_a", - } - }, - ) - mixins: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": { - "alias": "mixins", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:mixins", - } - }, - ) - value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table that is applied directly to mappings, in order of precedence""", - json_schema_extra={ - "linkml_meta": {"alias": "value_mappings", "domain_of": ["ElementDerivation"]} - }, - ) - expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_value_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys and values are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_expression_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - mirror_source: Optional[bool] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "mirror_source", "domain_of": ["ElementDerivation"]} - }, - ) - description: Optional[str] = Field( - None, - description="""description of the specification component""", - json_schema_extra={ - "linkml_meta": { - "alias": "description", - "domain_of": ["SpecificationComponent"], - "slot_uri": "dcterms:description", - } - }, - ) - implements: Optional[List[str]] = Field( - default_factory=list, - description="""A reference to a specification that this component implements.""", - json_schema_extra={ - "linkml_meta": {"alias": "implements", "domain_of": ["SpecificationComponent"]} - }, - ) - comments: Optional[List[str]] = Field( - default_factory=list, - description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", - json_schema_extra={ - "linkml_meta": { - "alias": "comments", - "domain_of": ["SpecificationComponent"], - "slot_uri": "rdfs:comment", - } - }, - ) - -class ObjectDerivation(BaseModel): - class_derivations: Dict[str, ClassDerivation] class AliasedClass(ConfiguredBaseModel): """ alias-class key value pairs for classes """ + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer'}) - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer"} - ) - - alias: str = Field( - ..., - description="""name of the class to be aliased""", - json_schema_extra={"linkml_meta": {"alias": "alias", "domain_of": ["AliasedClass"]}}, - ) - class_named: Optional[str] = Field( - None, - description="""local alias for the class""", - json_schema_extra={"linkml_meta": {"alias": "class_named", "domain_of": ["AliasedClass"]}}, - ) + alias: str = Field(default=..., description="""name of the class to be aliased""", json_schema_extra = { "linkml_meta": {'alias': 'alias', 'domain_of': ['AliasedClass']} }) + class_named: Optional[str] = Field(default=None, description="""local alias for the class""", json_schema_extra = { "linkml_meta": {'alias': 'class_named', 'domain_of': ['AliasedClass']} }) class SlotDerivation(ElementDerivation): """ A specification of how to derive the value of a target slot from a source slot """ - - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer"} - ) - - name: str = Field( - ..., - description="""Target slot name""", - json_schema_extra={ - "linkml_meta": { - "alias": "name", - "domain_of": [ - "ElementDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - populated_from: Optional[str] = Field( - None, - description="""Source slot name""", - json_schema_extra={ - "linkml_meta": { - "alias": "populated_from", - "domain_of": [ - "ClassDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - sources: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": { - "alias": "sources", - "domain_of": [ - "ClassDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - object_derivations: Optional[List[ObjectDerivation]] = None - derived_from: Optional[List[str]] = Field( - default_factory=list, - description="""Source slots that are used to derive this slot. This can be computed from the expr, if the expr is declarative.""", - json_schema_extra={ - "linkml_meta": {"alias": "derived_from", "domain_of": ["SlotDerivation"]} - }, - ) - expr: Optional[str] = Field( - None, - description="""An expression to be evaluated on the source object to derive the target slot. Should be specified using the LinkML expression language.""", - json_schema_extra={ - "linkml_meta": { - "alias": "expr", - "domain_of": ["SlotDerivation", "EnumDerivation", "PermissibleValueDerivation"], - } - }, - ) - value: Optional[Any] = Field( - None, - description="""A constant value to assign to this slot, overriding all other derivations""", - json_schema_extra={ - "linkml_meta": { - "alias": "value", - "domain_of": ["SlotDerivation"] - } - }, - ) - range: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "range", - "domain_of": ["SlotDerivation"], - "slot_uri": "linkml:range", - } - }, - ) - unit_conversion: Optional[UnitConversionConfiguration] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "unit_conversion", "domain_of": ["SlotDerivation"]} - }, - ) - inverse_of: Optional[Inverse] = Field( - None, - description="""Used to specify a class-slot tuple that is the inverse of the derived/target slot. This is used primarily for mapping to relational databases or formalisms that do not allow multiple values. The class representing the repeated element has a foreign key slot inserted in that 'back references' the original multivalued slot.""", - json_schema_extra={"linkml_meta": {"alias": "inverse_of", "domain_of": ["SlotDerivation"]}}, - ) - hide: Optional[bool] = Field( - None, - description="""True if this is suppressed""", - json_schema_extra={ - "linkml_meta": { - "alias": "hide", - "domain_of": ["SlotDerivation", "EnumDerivation", "PermissibleValueDerivation"], - } - }, - ) - type_designator: Optional[bool] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "type_designator", "domain_of": ["SlotDerivation"]} - }, - ) - target_definition: Optional[Any] = Field( - None, - description="""LinkML definition object for this slot.""", - json_schema_extra={ - "linkml_meta": { - "alias": "target_definition", - "comments": ["currently defined as Any to avoid coupling with metamodel"], - "domain_of": ["ClassDerivation", "SlotDerivation"], - } - }, - ) - cast_collection_as: Optional[CollectionType] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "cast_collection_as", "domain_of": ["SlotDerivation"]} - }, - ) - dictionary_key: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "dictionary_key", "domain_of": ["SlotDerivation"]} - }, - ) - stringification: Optional[StringificationConfiguration] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "stringification", "domain_of": ["SlotDerivation"]} - }, - ) - aggregation_operation: Optional[AggregationOperation] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "aggregation_operation", "domain_of": ["SlotDerivation"]} - }, - ) - copy_directives: Optional[Dict[str, CopyDirective]] = Field( - default_factory=dict, - json_schema_extra={ - "linkml_meta": {"alias": "copy_directives", "domain_of": ["ElementDerivation"]} - }, - ) - overrides: Optional[Any] = Field( - None, - description="""overrides source schema slots""", - json_schema_extra={ - "linkml_meta": {"alias": "overrides", "domain_of": ["ElementDerivation"]} - }, - ) - is_a: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "is_a", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:is_a", - } - }, - ) - mixins: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": { - "alias": "mixins", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:mixins", - } - }, - ) - value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table that is applied directly to mappings, in order of precedence""", - json_schema_extra={ - "linkml_meta": {"alias": "value_mappings", "domain_of": ["ElementDerivation"]} - }, - ) - expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_value_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys and values are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_expression_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - mirror_source: Optional[bool] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "mirror_source", "domain_of": ["ElementDerivation"]} - }, - ) - description: Optional[str] = Field( - None, - description="""description of the specification component""", - json_schema_extra={ - "linkml_meta": { - "alias": "description", - "domain_of": ["SpecificationComponent"], - "slot_uri": "dcterms:description", - } - }, - ) - implements: Optional[List[str]] = Field( - default_factory=list, - description="""A reference to a specification that this component implements.""", - json_schema_extra={ - "linkml_meta": {"alias": "implements", "domain_of": ["SpecificationComponent"]} - }, - ) - comments: Optional[List[str]] = Field( - default_factory=list, - description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", - json_schema_extra={ - "linkml_meta": { - "alias": "comments", - "domain_of": ["SpecificationComponent"], - "slot_uri": "rdfs:comment", - } - }, - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer'}) + + name: str = Field(default=..., description="""Target slot name""", json_schema_extra = { "linkml_meta": {'alias': 'name', + 'domain_of': ['ElementDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + populated_from: Optional[str] = Field(default=None, description="""Source slot name""", json_schema_extra = { "linkml_meta": {'alias': 'populated_from', + 'domain_of': ['ClassDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + sources: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'sources', + 'domain_of': ['ClassDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + object_derivations: Optional[List[str]] = Field(default=None, description="""One or more object derivations used to construct the slot value(s), which must be instances of a class.""", json_schema_extra = { "linkml_meta": {'alias': 'object_derivations', 'domain_of': ['SlotDerivation']} }) + derived_from: Optional[List[str]] = Field(default=None, description="""Source slots that are used to derive this slot. This can be computed from the expr, if the expr is declarative.""", json_schema_extra = { "linkml_meta": {'alias': 'derived_from', 'domain_of': ['SlotDerivation']} }) + expr: Optional[str] = Field(default=None, description="""An expression to be evaluated on the source object to derive the target slot. Should be specified using the LinkML expression language.""", json_schema_extra = { "linkml_meta": {'alias': 'expr', + 'domain_of': ['SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + range: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'range', 'domain_of': ['SlotDerivation'], 'slot_uri': 'linkml:range'} }) + unit_conversion: Optional[UnitConversionConfiguration] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'unit_conversion', 'domain_of': ['SlotDerivation']} }) + inverse_of: Optional[Inverse] = Field(default=None, description="""Used to specify a class-slot tuple that is the inverse of the derived/target slot. This is used primarily for mapping to relational databases or formalisms that do not allow multiple values. The class representing the repeated element has a foreign key slot inserted in that 'back references' the original multivalued slot.""", json_schema_extra = { "linkml_meta": {'alias': 'inverse_of', 'domain_of': ['SlotDerivation']} }) + hide: Optional[bool] = Field(default=None, description="""True if this is suppressed""", json_schema_extra = { "linkml_meta": {'alias': 'hide', + 'domain_of': ['SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + type_designator: Optional[bool] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'type_designator', 'domain_of': ['SlotDerivation']} }) + target_definition: Optional[Any] = Field(default=None, description="""LinkML definition object for this slot.""", json_schema_extra = { "linkml_meta": {'alias': 'target_definition', + 'comments': ['currently defined as Any to avoid coupling with metamodel'], + 'domain_of': ['ClassDerivation', 'SlotDerivation']} }) + cast_collection_as: Optional[CollectionType] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'cast_collection_as', 'domain_of': ['SlotDerivation']} }) + dictionary_key: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'dictionary_key', 'domain_of': ['SlotDerivation']} }) + stringification: Optional[StringificationConfiguration] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'stringification', 'domain_of': ['SlotDerivation']} }) + aggregation_operation: Optional[AggregationOperation] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'aggregation_operation', 'domain_of': ['SlotDerivation']} }) + value: Optional[Any] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'value', 'domain_of': ['SlotDerivation', 'KeyVal']} }) + copy_directives: Optional[Dict[str, CopyDirective]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'copy_directives', + 'domain_of': ['TransformationSpecification', 'ElementDerivation']} }) + overrides: Optional[Any] = Field(default=None, description="""overrides source schema slots""", json_schema_extra = { "linkml_meta": {'alias': 'overrides', 'domain_of': ['ElementDerivation']} }) + is_a: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'is_a', 'domain_of': ['ElementDerivation'], 'slot_uri': 'linkml:is_a'} }) + mixins: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mixins', + 'domain_of': ['ElementDerivation'], + 'slot_uri': 'linkml:mixins'} }) + value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table that is applied directly to mappings, in order of precedence""", json_schema_extra = { "linkml_meta": {'alias': 'value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys and values are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_expression_mappings', + 'domain_of': ['ElementDerivation']} }) + mirror_source: Optional[bool] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mirror_source', 'domain_of': ['ElementDerivation']} }) + description: Optional[str] = Field(default=None, description="""description of the specification component""", json_schema_extra = { "linkml_meta": {'alias': 'description', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'dcterms:description'} }) + implements: Optional[List[str]] = Field(default=None, description="""A reference to a specification that this component implements.""", json_schema_extra = { "linkml_meta": {'alias': 'implements', 'domain_of': ['SpecificationComponent']} }) + comments: Optional[List[str]] = Field(default=None, description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", json_schema_extra = { "linkml_meta": {'alias': 'comments', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'rdfs:comment'} }) class EnumDerivation(ElementDerivation): """ A specification of how to derive the value of a target enum from a source enum """ - - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer"} - ) - - name: str = Field( - ..., - description="""Target enum name""", - json_schema_extra={ - "linkml_meta": { - "alias": "name", - "domain_of": [ - "ElementDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - populated_from: Optional[str] = Field( - None, - description="""Source enum name""", - json_schema_extra={ - "linkml_meta": { - "alias": "populated_from", - "domain_of": [ - "ClassDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - sources: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": { - "alias": "sources", - "domain_of": [ - "ClassDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - expr: Optional[str] = Field( - None, - description="""An expression to be evaluated on the source object to derive the target slot. Should be specified using the LinkML expression language.""", - json_schema_extra={ - "linkml_meta": { - "alias": "expr", - "domain_of": ["SlotDerivation", "EnumDerivation", "PermissibleValueDerivation"], - } - }, - ) - hide: Optional[bool] = Field( - None, - description="""True if this is suppressed""", - json_schema_extra={ - "linkml_meta": { - "alias": "hide", - "domain_of": ["SlotDerivation", "EnumDerivation", "PermissibleValueDerivation"], - } - }, - ) - permissible_value_derivations: Optional[Dict[str, PermissibleValueDerivation]] = Field( - default_factory=dict, - description="""Instructions on how to derive a set of PVs in the target schema""", - json_schema_extra={ - "linkml_meta": { - "alias": "permissible_value_derivations", - "domain_of": ["EnumDerivation"], - } - }, - ) - copy_directives: Optional[Dict[str, CopyDirective]] = Field( - default_factory=dict, - json_schema_extra={ - "linkml_meta": {"alias": "copy_directives", "domain_of": ["ElementDerivation"]} - }, - ) - overrides: Optional[Any] = Field( - None, - description="""overrides source schema slots""", - json_schema_extra={ - "linkml_meta": {"alias": "overrides", "domain_of": ["ElementDerivation"]} - }, - ) - is_a: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "is_a", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:is_a", - } - }, - ) - mixins: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": { - "alias": "mixins", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:mixins", - } - }, - ) - value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table that is applied directly to mappings, in order of precedence""", - json_schema_extra={ - "linkml_meta": {"alias": "value_mappings", "domain_of": ["ElementDerivation"]} - }, - ) - expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_value_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys and values are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_expression_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - mirror_source: Optional[bool] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "mirror_source", "domain_of": ["ElementDerivation"]} - }, - ) - description: Optional[str] = Field( - None, - description="""description of the specification component""", - json_schema_extra={ - "linkml_meta": { - "alias": "description", - "domain_of": ["SpecificationComponent"], - "slot_uri": "dcterms:description", - } - }, - ) - implements: Optional[List[str]] = Field( - default_factory=list, - description="""A reference to a specification that this component implements.""", - json_schema_extra={ - "linkml_meta": {"alias": "implements", "domain_of": ["SpecificationComponent"]} - }, - ) - comments: Optional[List[str]] = Field( - default_factory=list, - description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", - json_schema_extra={ - "linkml_meta": { - "alias": "comments", - "domain_of": ["SpecificationComponent"], - "slot_uri": "rdfs:comment", - } - }, - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer'}) + + name: str = Field(default=..., description="""Target enum name""", json_schema_extra = { "linkml_meta": {'alias': 'name', + 'domain_of': ['ElementDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + populated_from: Optional[str] = Field(default=None, description="""Source enum name""", json_schema_extra = { "linkml_meta": {'alias': 'populated_from', + 'domain_of': ['ClassDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + sources: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'sources', + 'domain_of': ['ClassDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + expr: Optional[str] = Field(default=None, description="""An expression to be evaluated on the source object to derive the target slot. Should be specified using the LinkML expression language.""", json_schema_extra = { "linkml_meta": {'alias': 'expr', + 'domain_of': ['SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + hide: Optional[bool] = Field(default=None, description="""True if this is suppressed""", json_schema_extra = { "linkml_meta": {'alias': 'hide', + 'domain_of': ['SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + permissible_value_derivations: Optional[Dict[str, PermissibleValueDerivation]] = Field(default=None, description="""Instructions on how to derive a set of PVs in the target schema""", json_schema_extra = { "linkml_meta": {'alias': 'permissible_value_derivations', 'domain_of': ['EnumDerivation']} }) + copy_directives: Optional[Dict[str, CopyDirective]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'copy_directives', + 'domain_of': ['TransformationSpecification', 'ElementDerivation']} }) + overrides: Optional[Any] = Field(default=None, description="""overrides source schema slots""", json_schema_extra = { "linkml_meta": {'alias': 'overrides', 'domain_of': ['ElementDerivation']} }) + is_a: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'is_a', 'domain_of': ['ElementDerivation'], 'slot_uri': 'linkml:is_a'} }) + mixins: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mixins', + 'domain_of': ['ElementDerivation'], + 'slot_uri': 'linkml:mixins'} }) + value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table that is applied directly to mappings, in order of precedence""", json_schema_extra = { "linkml_meta": {'alias': 'value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys and values are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_expression_mappings', + 'domain_of': ['ElementDerivation']} }) + mirror_source: Optional[bool] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mirror_source', 'domain_of': ['ElementDerivation']} }) + description: Optional[str] = Field(default=None, description="""description of the specification component""", json_schema_extra = { "linkml_meta": {'alias': 'description', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'dcterms:description'} }) + implements: Optional[List[str]] = Field(default=None, description="""A reference to a specification that this component implements.""", json_schema_extra = { "linkml_meta": {'alias': 'implements', 'domain_of': ['SpecificationComponent']} }) + comments: Optional[List[str]] = Field(default=None, description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", json_schema_extra = { "linkml_meta": {'alias': 'comments', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'rdfs:comment'} }) class PermissibleValueDerivation(ElementDerivation): """ A specification of how to derive the value of a PV from a source enum """ - - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - { - "from_schema": "https://w3id.org/linkml/transformer", - "todos": [ - "this is currently under-specified. We will need boolean " - "combinators to express if-then-else" - ], - } - ) - - name: str = Field( - ..., - description="""Target permissible value text""", - json_schema_extra={ - "linkml_meta": { - "alias": "name", - "domain_of": [ - "ElementDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - expr: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "expr", - "domain_of": ["SlotDerivation", "EnumDerivation", "PermissibleValueDerivation"], - } - }, - ) - populated_from: Optional[str] = Field( - None, - description="""Source permissible value""", - json_schema_extra={ - "linkml_meta": { - "alias": "populated_from", - "domain_of": [ - "ClassDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - sources: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": { - "alias": "sources", - "domain_of": [ - "ClassDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - hide: Optional[bool] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "hide", - "domain_of": ["SlotDerivation", "EnumDerivation", "PermissibleValueDerivation"], - } - }, - ) - copy_directives: Optional[Dict[str, CopyDirective]] = Field( - default_factory=dict, - json_schema_extra={ - "linkml_meta": {"alias": "copy_directives", "domain_of": ["ElementDerivation"]} - }, - ) - overrides: Optional[Any] = Field( - None, - description="""overrides source schema slots""", - json_schema_extra={ - "linkml_meta": {"alias": "overrides", "domain_of": ["ElementDerivation"]} - }, - ) - is_a: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "is_a", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:is_a", - } - }, - ) - mixins: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": { - "alias": "mixins", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:mixins", - } - }, - ) - value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table that is applied directly to mappings, in order of precedence""", - json_schema_extra={ - "linkml_meta": {"alias": "value_mappings", "domain_of": ["ElementDerivation"]} - }, - ) - expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_value_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys and values are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_expression_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - mirror_source: Optional[bool] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "mirror_source", "domain_of": ["ElementDerivation"]} - }, - ) - description: Optional[str] = Field( - None, - description="""description of the specification component""", - json_schema_extra={ - "linkml_meta": { - "alias": "description", - "domain_of": ["SpecificationComponent"], - "slot_uri": "dcterms:description", - } - }, - ) - implements: Optional[List[str]] = Field( - default_factory=list, - description="""A reference to a specification that this component implements.""", - json_schema_extra={ - "linkml_meta": {"alias": "implements", "domain_of": ["SpecificationComponent"]} - }, - ) - comments: Optional[List[str]] = Field( - default_factory=list, - description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", - json_schema_extra={ - "linkml_meta": { - "alias": "comments", - "domain_of": ["SpecificationComponent"], - "slot_uri": "rdfs:comment", - } - }, - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer', + 'todos': ['this is currently under-specified. We will need boolean ' + 'combinators to express if-then-else']}) + + name: str = Field(default=..., description="""Target permissible value text""", json_schema_extra = { "linkml_meta": {'alias': 'name', + 'domain_of': ['ElementDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + expr: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'expr', + 'domain_of': ['SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + populated_from: Optional[str] = Field(default=None, description="""Source permissible value""", json_schema_extra = { "linkml_meta": {'alias': 'populated_from', + 'domain_of': ['ClassDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + sources: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'sources', + 'domain_of': ['ClassDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + hide: Optional[bool] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'hide', + 'domain_of': ['SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + copy_directives: Optional[Dict[str, CopyDirective]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'copy_directives', + 'domain_of': ['TransformationSpecification', 'ElementDerivation']} }) + overrides: Optional[Any] = Field(default=None, description="""overrides source schema slots""", json_schema_extra = { "linkml_meta": {'alias': 'overrides', 'domain_of': ['ElementDerivation']} }) + is_a: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'is_a', 'domain_of': ['ElementDerivation'], 'slot_uri': 'linkml:is_a'} }) + mixins: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mixins', + 'domain_of': ['ElementDerivation'], + 'slot_uri': 'linkml:mixins'} }) + value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table that is applied directly to mappings, in order of precedence""", json_schema_extra = { "linkml_meta": {'alias': 'value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys and values are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_expression_mappings', + 'domain_of': ['ElementDerivation']} }) + mirror_source: Optional[bool] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mirror_source', 'domain_of': ['ElementDerivation']} }) + description: Optional[str] = Field(default=None, description="""description of the specification component""", json_schema_extra = { "linkml_meta": {'alias': 'description', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'dcterms:description'} }) + implements: Optional[List[str]] = Field(default=None, description="""A reference to a specification that this component implements.""", json_schema_extra = { "linkml_meta": {'alias': 'implements', 'domain_of': ['SpecificationComponent']} }) + comments: Optional[List[str]] = Field(default=None, description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", json_schema_extra = { "linkml_meta": {'alias': 'comments', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'rdfs:comment'} }) class PrefixDerivation(ElementDerivation): - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer"} - ) - - name: str = Field( - ..., - description="""Name of the element in the target schema""", - json_schema_extra={ - "linkml_meta": { - "alias": "name", - "domain_of": [ - "ElementDerivation", - "SlotDerivation", - "EnumDerivation", - "PermissibleValueDerivation", - ], - } - }, - ) - copy_directives: Optional[Dict[str, CopyDirective]] = Field( - default_factory=dict, - json_schema_extra={ - "linkml_meta": {"alias": "copy_directives", "domain_of": ["ElementDerivation"]} - }, - ) - overrides: Optional[Any] = Field( - None, - description="""overrides source schema slots""", - json_schema_extra={ - "linkml_meta": {"alias": "overrides", "domain_of": ["ElementDerivation"]} - }, - ) - is_a: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "is_a", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:is_a", - } - }, - ) - mixins: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": { - "alias": "mixins", - "domain_of": ["ElementDerivation"], - "slot_uri": "linkml:mixins", - } - }, - ) - value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table that is applied directly to mappings, in order of precedence""", - json_schema_extra={ - "linkml_meta": {"alias": "value_mappings", "domain_of": ["ElementDerivation"]} - }, - ) - expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_value_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field( - default_factory=dict, - description="""A mapping table in which the keys and values are expressions""", - json_schema_extra={ - "linkml_meta": { - "alias": "expression_to_expression_mappings", - "domain_of": ["ElementDerivation"], - } - }, - ) - mirror_source: Optional[bool] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "mirror_source", "domain_of": ["ElementDerivation"]} - }, - ) - description: Optional[str] = Field( - None, - description="""description of the specification component""", - json_schema_extra={ - "linkml_meta": { - "alias": "description", - "domain_of": ["SpecificationComponent"], - "slot_uri": "dcterms:description", - } - }, - ) - implements: Optional[List[str]] = Field( - default_factory=list, - description="""A reference to a specification that this component implements.""", - json_schema_extra={ - "linkml_meta": {"alias": "implements", "domain_of": ["SpecificationComponent"]} - }, - ) - comments: Optional[List[str]] = Field( - default_factory=list, - description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", - json_schema_extra={ - "linkml_meta": { - "alias": "comments", - "domain_of": ["SpecificationComponent"], - "slot_uri": "rdfs:comment", - } - }, - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer'}) + + name: str = Field(default=..., description="""Name of the element in the target schema""", json_schema_extra = { "linkml_meta": {'alias': 'name', + 'domain_of': ['ElementDerivation', + 'SlotDerivation', + 'EnumDerivation', + 'PermissibleValueDerivation']} }) + copy_directives: Optional[Dict[str, CopyDirective]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'copy_directives', + 'domain_of': ['TransformationSpecification', 'ElementDerivation']} }) + overrides: Optional[Any] = Field(default=None, description="""overrides source schema slots""", json_schema_extra = { "linkml_meta": {'alias': 'overrides', 'domain_of': ['ElementDerivation']} }) + is_a: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'is_a', 'domain_of': ['ElementDerivation'], 'slot_uri': 'linkml:is_a'} }) + mixins: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mixins', + 'domain_of': ['ElementDerivation'], + 'slot_uri': 'linkml:mixins'} }) + value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table that is applied directly to mappings, in order of precedence""", json_schema_extra = { "linkml_meta": {'alias': 'value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_value_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_value_mappings', 'domain_of': ['ElementDerivation']} }) + expression_to_expression_mappings: Optional[Dict[str, KeyVal]] = Field(default=None, description="""A mapping table in which the keys and values are expressions""", json_schema_extra = { "linkml_meta": {'alias': 'expression_to_expression_mappings', + 'domain_of': ['ElementDerivation']} }) + mirror_source: Optional[bool] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'mirror_source', 'domain_of': ['ElementDerivation']} }) + description: Optional[str] = Field(default=None, description="""description of the specification component""", json_schema_extra = { "linkml_meta": {'alias': 'description', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'dcterms:description'} }) + implements: Optional[List[str]] = Field(default=None, description="""A reference to a specification that this component implements.""", json_schema_extra = { "linkml_meta": {'alias': 'implements', 'domain_of': ['SpecificationComponent']} }) + comments: Optional[List[str]] = Field(default=None, description="""A list of comments about this component. Comments are free text, and may be used to provide additional information about the component, including instructions for its use.""", json_schema_extra = { "linkml_meta": {'alias': 'comments', + 'domain_of': ['SpecificationComponent'], + 'slot_uri': 'rdfs:comment'} }) class UnitConversionConfiguration(ConfiguredBaseModel): - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer"} - ) - - target_unit: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "target_unit", "domain_of": ["UnitConversionConfiguration"]} - }, - ) - target_unit_scheme: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "target_unit_scheme", - "domain_of": ["UnitConversionConfiguration"], - "examples": [{"value": "ucum"}], - } - }, - ) - source_unit: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "source_unit", "domain_of": ["UnitConversionConfiguration"]} - }, - ) - source_unit_scheme: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "source_unit_scheme", - "domain_of": ["UnitConversionConfiguration"], - "examples": [{"value": "ucum"}], - } - }, - ) - source_unit_slot: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "source_unit_slot", - "domain_of": ["UnitConversionConfiguration"], - } - }, - ) - source_magnitude_slot: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "source_magnitude_slot", - "domain_of": ["UnitConversionConfiguration"], - } - }, - ) - target_unit_slot: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "target_unit_slot", - "domain_of": ["UnitConversionConfiguration"], - } - }, - ) - target_magnitude_slot: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "target_magnitude_slot", - "domain_of": ["UnitConversionConfiguration"], - } - }, - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer'}) + + target_unit: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'target_unit', 'domain_of': ['UnitConversionConfiguration']} }) + target_unit_scheme: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'target_unit_scheme', + 'domain_of': ['UnitConversionConfiguration'], + 'examples': [{'value': 'ucum'}]} }) + source_unit: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'source_unit', 'domain_of': ['UnitConversionConfiguration']} }) + source_unit_scheme: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'source_unit_scheme', + 'domain_of': ['UnitConversionConfiguration'], + 'examples': [{'value': 'ucum'}]} }) + source_unit_slot: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'source_unit_slot', 'domain_of': ['UnitConversionConfiguration']} }) + source_magnitude_slot: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'source_magnitude_slot', 'domain_of': ['UnitConversionConfiguration']} }) + target_unit_slot: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'target_unit_slot', 'domain_of': ['UnitConversionConfiguration']} }) + target_magnitude_slot: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'target_magnitude_slot', 'domain_of': ['UnitConversionConfiguration']} }) class StringificationConfiguration(ConfiguredBaseModel): - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer"} - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer'}) - delimiter: Optional[str] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "delimiter", - "domain_of": ["StringificationConfiguration"], - "examples": [{"value": ","}, {"value": "|"}, {"value": ";"}], - } - }, - ) - reversed: Optional[bool] = Field( - None, - json_schema_extra={ - "linkml_meta": {"alias": "reversed", "domain_of": ["StringificationConfiguration"]} - }, - ) - over_slots: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": {"alias": "over_slots", "domain_of": ["StringificationConfiguration"]} - }, - ) - syntax: Optional[SerializationSyntaxType] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "syntax", - "domain_of": ["StringificationConfiguration"], - "examples": [{"value": "json"}, {"value": "yaml"}], - } - }, - ) + delimiter: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'delimiter', + 'domain_of': ['StringificationConfiguration'], + 'examples': [{'value': ','}, {'value': '|'}, {'value': ';'}]} }) + reversed: Optional[bool] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'reversed', 'domain_of': ['StringificationConfiguration']} }) + over_slots: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'over_slots', 'domain_of': ['StringificationConfiguration']} }) + syntax: Optional[SerializationSyntaxType] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'syntax', + 'domain_of': ['StringificationConfiguration'], + 'examples': [{'value': 'json'}, {'value': 'yaml'}]} }) class Inverse(ConfiguredBaseModel): """ Used for back references in mapping to relational model """ + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'aliases': ['backref', 'back_references'], + 'from_schema': 'https://w3id.org/linkml/transformer'}) - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - { - "aliases": ["backref", "back_references"], - "from_schema": "https://w3id.org/linkml/transformer", - } - ) - - slot_name: Optional[str] = Field( - None, json_schema_extra={"linkml_meta": {"alias": "slot_name", "domain_of": ["Inverse"]}} - ) - class_name: Optional[str] = Field( - None, json_schema_extra={"linkml_meta": {"alias": "class_name", "domain_of": ["Inverse"]}} - ) + slot_name: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'slot_name', 'domain_of': ['Inverse']} }) + class_name: Optional[str] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'class_name', 'domain_of': ['Inverse']} }) class TransformationOperation(ConfiguredBaseModel): - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"abstract": True, "from_schema": "https://w3id.org/linkml/transformer"} - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'abstract': True, 'from_schema': 'https://w3id.org/linkml/transformer'}) pass class AggregationOperation(TransformationOperation): - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer"} - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer'}) - operator: AggregationType = Field( - ..., - json_schema_extra={ - "linkml_meta": {"alias": "operator", "domain_of": ["AggregationOperation"]} - }, - ) - null_handling: Optional[InvalidValueHandlingStrategy] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "null_handling", - "domain_of": ["AggregationOperation", "GroupingOperation"], - } - }, - ) - invalid_value_handling: Optional[InvalidValueHandlingStrategy] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "invalid_value_handling", - "domain_of": ["AggregationOperation"], - } - }, - ) + operator: AggregationType = Field(default=..., json_schema_extra = { "linkml_meta": {'alias': 'operator', 'domain_of': ['AggregationOperation']} }) + null_handling: Optional[InvalidValueHandlingStrategy] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'null_handling', + 'domain_of': ['AggregationOperation', 'GroupingOperation']} }) + invalid_value_handling: Optional[InvalidValueHandlingStrategy] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'invalid_value_handling', 'domain_of': ['AggregationOperation']} }) class GroupingOperation(TransformationOperation): - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer"} - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer'}) - null_handling: Optional[InvalidValueHandlingStrategy] = Field( - None, - json_schema_extra={ - "linkml_meta": { - "alias": "null_handling", - "domain_of": ["AggregationOperation", "GroupingOperation"], - } - }, - ) + null_handling: Optional[InvalidValueHandlingStrategy] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'null_handling', + 'domain_of': ['AggregationOperation', 'GroupingOperation']} }) class PivotOperation(TransformationOperation): - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - { - "aliases": ["melt/unmelt", "reification/dereification"], - "from_schema": "https://w3id.org/linkml/transformer", - } - ) - - direction: PivotDirectionType = Field( - ..., - json_schema_extra={"linkml_meta": {"alias": "direction", "domain_of": ["PivotOperation"]}}, - ) - variable_slot: Optional[str] = Field( - "variable", - description="""Slot to use for the variable column in the melted/long representation. In EAV this is the name of the 'A' variable""", - json_schema_extra={ - "linkml_meta": { - "alias": "variable_slot", - "aliases": ["var_name"], - "domain_of": ["PivotOperation"], - "ifabsent": "string(variable)", - } - }, - ) - value_slot: Optional[str] = Field( - "value", - description="""Slot to use for the value column in the melted/long representation. In EAV this is the name of the 'V' variable""", - json_schema_extra={ - "linkml_meta": { - "alias": "value_slot", - "aliases": ["value_name"], - "domain_of": ["PivotOperation"], - "ifabsent": "string(value)", - } - }, - ) - unmelt_to_class: Optional[str] = Field( - None, - description="""In an unmelt operation, attributes (which are values in the long/melted/EAV representation) must conform to valid attributes in this class""", - json_schema_extra={ - "linkml_meta": {"alias": "unmelt_to_class", "domain_of": ["PivotOperation"]} - }, - ) - unmelt_to_slots: Optional[List[str]] = Field( - default_factory=list, - json_schema_extra={ - "linkml_meta": {"alias": "unmelt_to_slots", "domain_of": ["PivotOperation"]} - }, - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'aliases': ['melt/unmelt', 'reification/dereification'], + 'from_schema': 'https://w3id.org/linkml/transformer'}) + + direction: PivotDirectionType = Field(default=..., json_schema_extra = { "linkml_meta": {'alias': 'direction', 'domain_of': ['PivotOperation']} }) + variable_slot: Optional[str] = Field(default="variable", description="""Slot to use for the variable column in the melted/long representation. In EAV this is the name of the 'A' variable""", json_schema_extra = { "linkml_meta": {'alias': 'variable_slot', + 'aliases': ['var_name'], + 'domain_of': ['PivotOperation'], + 'ifabsent': 'string(variable)'} }) + value_slot: Optional[str] = Field(default="value", description="""Slot to use for the value column in the melted/long representation. In EAV this is the name of the 'V' variable""", json_schema_extra = { "linkml_meta": {'alias': 'value_slot', + 'aliases': ['value_name'], + 'domain_of': ['PivotOperation'], + 'ifabsent': 'string(value)'} }) + unmelt_to_class: Optional[str] = Field(default=None, description="""In an unmelt operation, attributes (which are values in the long/melted/EAV representation) must conform to valid attributes in this class""", json_schema_extra = { "linkml_meta": {'alias': 'unmelt_to_class', 'domain_of': ['PivotOperation']} }) + unmelt_to_slots: Optional[List[str]] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'unmelt_to_slots', 'domain_of': ['PivotOperation']} }) class KeyVal(ConfiguredBaseModel): - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer"} - ) + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer'}) - key: str = Field( - ..., json_schema_extra={"linkml_meta": {"alias": "key", "domain_of": ["KeyVal"]}} - ) - value: Optional[Any] = Field( - None, json_schema_extra={"linkml_meta": {"alias": "value", "domain_of": ["KeyVal"]}} - ) + key: str = Field(default=..., json_schema_extra = { "linkml_meta": {'alias': 'key', 'domain_of': ['KeyVal']} }) + value: Optional[Any] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'value', 'domain_of': ['SlotDerivation', 'KeyVal']} }) class CopyDirective(ConfiguredBaseModel): """ Instructs a Schema Mapper in how to map to a target schema. Not used for data transformation. - This is the process to process a directive: - 1. If `copy_all`, add all sub-elements to the list of sub-elements to be copied. - 2. If `exclude`, remove the specified sub-elements from the above list. - 3. If `exclude_all`, clean-up the above list. Effectively making previous steps useless. - 4. If `include`, add the specified sub-elements from the list result of previous steps. - Implementations might decide to somehow report (error, warning,...) meaningless combinations - (like specifying `copy_all` and `exclude_all`). - Validation on the correctness of the resulting derived schema might be done optionally by the implementation. - For example, removing a slot but keeping a class that requires it would invalidate the derived-schema. - It is always possible to validate the schema with the LinkML linter after derivation. - What are the considered sub-elements depends on the calls of Element to be transformed. - For example, for a class they are `slots` and `attributes`. + This is the process to process a directive: 1. If `copy_all`, add all sub-elements to the list of sub-elements to be copied. 2. If `exclude`, remove the specified sub-elements from the above list. 3. If `exclude_all`, clean-up the above list. Effectively making previous steps useless. 4. If `include`, add the specified sub-elements from the list result of previous steps. + Implementations might decide to somehow report (error, warning,...) meaningless combinations (like specifying `copy_all` and `exclude_all`). + Validation on the correctness of the resulting derived schema might be done optionally by the implementation. For example, removing a slot but keeping a class that requires it would invalidate the derived-schema. It is always possible to validate the schema with the LinkML linter after derivation. + What are the considered sub-elements depends on the calls of Element to be transformed. For example, for a class they are `slots` and `attributes`. """ - - linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta( - {"from_schema": "https://w3id.org/linkml/transformer", "status": "testing"} - ) - - element_name: str = Field( - ..., - json_schema_extra={ - "linkml_meta": {"alias": "element_name", "domain_of": ["CopyDirective"]} - }, - ) - copy_all: Optional[bool] = Field( - None, - description="""Copy all sub-elements of the Element being derived.""", - json_schema_extra={"linkml_meta": {"alias": "copy_all", "domain_of": ["CopyDirective"]}}, - ) - exclude_all: Optional[bool] = Field( - None, - description="""Do not copy any of the sub-elements of the Element being derived.""", - json_schema_extra={"linkml_meta": {"alias": "exclude_all", "domain_of": ["CopyDirective"]}}, - ) - exclude: Optional[Any] = Field( - None, - description="""Remove certain sub-elements from the list of sub-elements to be copied. -As of now there it is under-specified, how to specify the sub-elements to exclude. One possible implementation would be a list where all element types can be mixed, since there might not be name conflicts across element types.""", - json_schema_extra={"linkml_meta": {"alias": "exclude", "domain_of": ["CopyDirective"]}}, - ) - include: Optional[Any] = Field( - None, - description="""Add certain sub-elements to the list of sub-elements to be copied. -As of now there it is under-specified, how to specify the sub-elements to include. One possible implementation would be a list where all element types can be mixed, since there might not be name conflicts across element types.""", - json_schema_extra={"linkml_meta": {"alias": "include", "domain_of": ["CopyDirective"]}}, - ) - add: Optional[Any] = Field( - None, json_schema_extra={"linkml_meta": {"alias": "add", "domain_of": ["CopyDirective"]}} - ) - + linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({'from_schema': 'https://w3id.org/linkml/transformer', 'status': 'testing'}) + + element_name: str = Field(default=..., json_schema_extra = { "linkml_meta": {'alias': 'element_name', 'domain_of': ['CopyDirective']} }) + copy_all: Optional[bool] = Field(default=None, description="""Copy all sub-elements of the Element being derived.""", json_schema_extra = { "linkml_meta": {'alias': 'copy_all', 'domain_of': ['CopyDirective']} }) + exclude_all: Optional[bool] = Field(default=None, description="""Do not copy any of the sub-elements of the Element being derived.""", json_schema_extra = { "linkml_meta": {'alias': 'exclude_all', 'domain_of': ['CopyDirective']} }) + exclude: Optional[Any] = Field(default=None, description="""Remove certain sub-elements from the list of sub-elements to be copied. +As of now there it is under-specified, how to specify the sub-elements to exclude. One possible implementation would be a list where all element types can be mixed, since there might not be name conflicts across element types.""", json_schema_extra = { "linkml_meta": {'alias': 'exclude', 'domain_of': ['CopyDirective']} }) + include: Optional[Any] = Field(default=None, description="""Add certain sub-elements to the list of sub-elements to be copied. +As of now there it is under-specified, how to specify the sub-elements to include. One possible implementation would be a list where all element types can be mixed, since there might not be name conflicts across element types.""", json_schema_extra = { "linkml_meta": {'alias': 'include', 'domain_of': ['CopyDirective']} }) + add: Optional[Any] = Field(default=None, json_schema_extra = { "linkml_meta": {'alias': 'add', 'domain_of': ['CopyDirective']} }) + + +# Helper methods for safe dictionary access +def _ensure_dict_field(obj, field_name): + """Ensure a dictionary field is initialized as empty dict if None""" + current_value = getattr(obj, field_name, None) + if current_value is None: + setattr(obj, field_name, {}) + return getattr(obj, field_name) + return current_value + +# Add methods to handle None dictionary fields safely +def ensure_class_derivations(self): + """Ensure class_derivations is initialized as empty dict if None""" + return _ensure_dict_field(self, 'class_derivations') + +def ensure_enum_derivations(self): + """Ensure enum_derivations is initialized as empty dict if None""" + return _ensure_dict_field(self, 'enum_derivations') + +def ensure_slot_derivations(self): + """Ensure slot_derivations is initialized as empty dict if None""" + return _ensure_dict_field(self, 'slot_derivations') + +def ensure_permissible_value_derivations(self): + """Ensure permissible_value_derivations is initialized as empty dict if None""" + return _ensure_dict_field(self, 'permissible_value_derivations') + +# Monkey patch the methods onto the classes +TransformationSpecification.ensure_class_derivations = ensure_class_derivations +TransformationSpecification.ensure_enum_derivations = ensure_enum_derivations +TransformationSpecification.ensure_slot_derivations = ensure_slot_derivations +ClassDerivation.ensure_slot_derivations = ensure_slot_derivations +EnumDerivation.ensure_permissible_value_derivations = ensure_permissible_value_derivations # Model rebuild # see https://pydantic-docs.helpmanual.io/usage/models/#rebuilding-a-model @@ -1624,6 +665,7 @@ class CopyDirective(ConfiguredBaseModel): TransformationSpecification.model_rebuild() ElementDerivation.model_rebuild() ClassDerivation.model_rebuild() +ObjectDerivation.model_rebuild() AliasedClass.model_rebuild() SlotDerivation.model_rebuild() EnumDerivation.model_rebuild() @@ -1638,3 +680,4 @@ class CopyDirective(ConfiguredBaseModel): PivotOperation.model_rebuild() KeyVal.model_rebuild() CopyDirective.model_rebuild() + diff --git a/src/linkml_map/datamodel/transformer_model.yaml b/src/linkml_map/datamodel/transformer_model.yaml index a950d11..7ea7af8 100644 --- a/src/linkml_map/datamodel/transformer_model.yaml +++ b/src/linkml_map/datamodel/transformer_model.yaml @@ -269,6 +269,8 @@ classes: range: StringificationConfiguration aggregation_operation: range: AggregationOperation + value: + range: Any EnumDerivation: is_a: ElementDerivation diff --git a/src/linkml_map/inference/inference.py b/src/linkml_map/inference/inference.py index f269fce..9e3b49c 100644 --- a/src/linkml_map/inference/inference.py +++ b/src/linkml_map/inference/inference.py @@ -21,6 +21,8 @@ def induce_missing_values( if not cd.populated_from: cd.populated_from = cd.name for cd in specification.class_derivations.values(): + if cd.slot_derivations is None: + continue for sd in cd.slot_derivations.values(): if sd.object_derivations: #skip inference for object derivations, inferencese come from class derivation later diff --git a/src/linkml_map/inference/inverter.py b/src/linkml_map/inference/inverter.py index e256ee7..59b6bdb 100644 --- a/src/linkml_map/inference/inverter.py +++ b/src/linkml_map/inference/inverter.py @@ -51,12 +51,14 @@ def invert(self, spec: TransformationSpecification) -> TransformationSpecificati """ logger.info("Inverting specification") inverted_spec = TransformationSpecification() - for cd in spec.class_derivations.values(): - inverted_cd = self.invert_class_derivation(cd, spec) - inverted_spec.class_derivations[inverted_cd.name] = inverted_cd - for ed in spec.enum_derivations.values(): - inverted_ed = self.invert_enum_derivation(ed, spec) - inverted_spec.enum_derivations[inverted_ed.name] = inverted_ed + if spec.class_derivations: + for cd in spec.class_derivations.values(): + inverted_cd = self.invert_class_derivation(cd, spec) + inverted_spec.ensure_class_derivations()[inverted_cd.name] = inverted_cd + if spec.enum_derivations: + for ed in spec.enum_derivations.values(): + inverted_ed = self.invert_enum_derivation(ed, spec) + inverted_spec.ensure_enum_derivations()[inverted_ed.name] = inverted_ed return inverted_spec def invert_class_derivation( @@ -72,13 +74,14 @@ def invert_class_derivation( inverted_cd = ClassDerivation( name=cd.populated_from if cd.populated_from else cd.name, populated_from=cd.name ) - for sd in cd.slot_derivations.values(): - inverted_sd = self.invert_slot_derivation(sd, cd, spec) - if inverted_sd: - inverted_cd.slot_derivations[inverted_sd.name] = inverted_sd - elif self.strict: - msg = f"Cannot invert slot derivation: {sd.name}" - raise NonInvertibleSpecificationError(msg) + if cd.slot_derivations: + for sd in cd.slot_derivations.values(): + inverted_sd = self.invert_slot_derivation(sd, cd, spec) + if inverted_sd: + inverted_cd.ensure_slot_derivations()[inverted_sd.name] = inverted_sd + elif self.strict: + msg = f"Cannot invert slot derivation: {sd.name}" + raise NonInvertibleSpecificationError(msg) return inverted_cd def invert_enum_derivation( @@ -97,12 +100,13 @@ def invert_enum_derivation( if inverted_ed.expr: msg = "TODO: invert enum derivation with expression" raise NonInvertibleSpecificationError(msg) - for pv_deriv in ed.permissible_value_derivations.values(): - inverted_pv_deriv = PermissibleValueDerivation( - name=pv_deriv.populated_from if pv_deriv.populated_from else pv_deriv.name, - populated_from=pv_deriv.name, - ) - inverted_ed.permissible_value_derivations[inverted_pv_deriv.name] = inverted_pv_deriv + if ed.permissible_value_derivations: + for pv_deriv in ed.permissible_value_derivations.values(): + inverted_pv_deriv = PermissibleValueDerivation( + name=pv_deriv.populated_from if pv_deriv.populated_from else pv_deriv.name, + populated_from=pv_deriv.name, + ) + inverted_ed.ensure_permissible_value_derivations()[inverted_pv_deriv.name] = inverted_pv_deriv return inverted_ed def invert_slot_derivation( diff --git a/src/linkml_map/inference/schema_mapper.py b/src/linkml_map/inference/schema_mapper.py index eddddb9..a311efa 100644 --- a/src/linkml_map/inference/schema_mapper.py +++ b/src/linkml_map/inference/schema_mapper.py @@ -100,6 +100,8 @@ def _copy_schema( source: SchemaDefinition, target: SchemaDefinition, ) -> SchemaDefinition: + if copy_directives is None: + return target if type(copy_directives) is dict: copy_directives_list = copy_directives.values() else: @@ -120,6 +122,8 @@ def _copy_class( source: ClassDefinition, target: ClassDefinition, ) -> ClassDefinition: + if copy_directives is None: + return target if type(copy_directives) is dict: copy_directives_list = copy_directives.values() else: @@ -170,12 +174,14 @@ def derive_schema( target_schema.imports.append(im) for prefix in source_schema.prefixes.values(): target_schema.prefixes[prefix.prefix_prefix] = prefix - for class_derivation in specification.class_derivations.values(): - class_definition = self._derive_class(class_derivation) - target_schema.classes[class_definition.name] = class_definition - for enum_derivation in specification.enum_derivations.values(): - enum_definition = self._derive_enum(enum_derivation) - target_schema.enums[enum_definition.name] = enum_definition + if specification.class_derivations: + for class_derivation in specification.class_derivations.values(): + class_definition = self._derive_class(class_derivation) + target_schema.classes[class_definition.name] = class_definition + if specification.enum_derivations: + for enum_derivation in specification.enum_derivations.values(): + enum_definition = self._derive_enum(enum_derivation) + target_schema.enums[enum_definition.name] = enum_definition target_schema.default_range = source_schema.default_range for cd in target_schema.classes.values(): self._rewire_class(cd) @@ -211,9 +217,10 @@ def _derive_class(self, class_derivation: ClassDerivation) -> ClassDefinition: source_class, target_class, ) - for slot_derivation in class_derivation.slot_derivations.values(): - slot_definition = self._derive_slot(slot_derivation) - target_class.attributes[slot_definition.name] = slot_definition + if class_derivation.slot_derivations is not None: + for slot_derivation in class_derivation.slot_derivations.values(): + slot_definition = self._derive_slot(slot_derivation) + target_class.attributes[slot_definition.name] = slot_definition if class_derivation.is_a: target_class.is_a = class_derivation.is_a if class_derivation.mixins: @@ -255,17 +262,18 @@ def _derive_enum(self, enum_derivation: EnumDerivation) -> EnumDefinition: target_enum.slots = [] target_enum.attributes = {} target_enum.slot_usage = {} - for pv_derivation in enum_derivation.permissible_value_derivations.values(): - if pv_derivation.populated_from: - pv = PermissibleValue(text=pv_derivation.populated_from) - target_enum.permissible_values[pv.text] = pv - elif pv_derivation.sources: - for source in pv_derivation.sources: - pv = PermissibleValue(text=source) + if enum_derivation.permissible_value_derivations: + for pv_derivation in enum_derivation.permissible_value_derivations.values(): + if pv_derivation.populated_from: + pv = PermissibleValue(text=pv_derivation.populated_from) target_enum.permissible_values[pv.text] = pv - else: - msg = f"Missing populated_from or sources for {pv_derivation}" - raise ValueError(msg) + elif pv_derivation.sources: + for source in pv_derivation.sources: + pv = PermissibleValue(text=source) + target_enum.permissible_values[pv.text] = pv + else: + msg = f"Missing populated_from or sources for {pv_derivation}" + raise ValueError(msg) if enum_derivation.mirror_source: for pv in source_enum.permissible_values.values(): if pv.text not in target_enum.permissible_values: diff --git a/src/linkml_map/transformer/object_transformer.py b/src/linkml_map/transformer/object_transformer.py index 3a08bd1..a694c32 100644 --- a/src/linkml_map/transformer/object_transformer.py +++ b/src/linkml_map/transformer/object_transformer.py @@ -203,138 +203,139 @@ def map_object( tgt_attrs = {} bindings = None # map each slot assignment in source_obj, if there is a slot_derivation - for slot_derivation in class_deriv.slot_derivations.values(): - v = None - source_class_slot = None - if slot_derivation.value is not None: - v = slot_derivation.value - if slot_derivation.range is None: - slot_derivation.range = "string" - elif slot_derivation.unit_conversion: - v = self._perform_unit_conversion(slot_derivation, source_obj, sv, source_type) - elif slot_derivation.expr: - if bindings is None: - bindings = Bindings( - self, - source_obj=source_obj, - source_obj_typed=source_obj_typed, - source_type=source_type, - sv=sv, - bindings={"NULL": None}, - ) - - try: - v = eval_expr_with_mapping(slot_derivation.expr, bindings) - except Exception as err: - if not self.unrestricted_eval: - msg = f"Expression not in safe subset: {slot_derivation.expr}" - raise RuntimeError(msg) from err - ctxt_obj, _ = bindings.get_ctxt_obj_and_dict() - aeval = Interpreter(usersyms={"src": ctxt_obj, "target": None}) - aeval(slot_derivation.expr) - v = aeval.symtable["target"] - elif slot_derivation.populated_from: - v = source_obj.get(slot_derivation.populated_from, None) - if slot_derivation.value_mappings and v is not None: - mapped = slot_derivation.value_mappings.get(str(v), None) - v = mapped.value if mapped is not None else None - source_class_slot = sv.induced_slot(slot_derivation.populated_from, source_type) - logger.debug( - f"Pop slot {slot_derivation.name} => {v} using {slot_derivation.populated_from} // {source_obj}" - ) - elif slot_derivation.sources: - vmap = {s: source_obj.get(s, None) for s in slot_derivation.sources} - vmap = {k: v for k, v in vmap.items() if v is not None} - if len(vmap.keys()) > 1: - msg = f"Multiple sources for {slot_derivation.name}: {vmap}" - raise ValueError(msg) - if len(vmap.keys()) == 1: - v = next(iter(vmap.values())) - source_class_slot_name = next(iter(vmap.keys())) - source_class_slot = sv.induced_slot(source_class_slot_name, source_type) - else: - v = None - source_class_slot = None - - logger.debug( - f"Pop slot {slot_derivation.name} => {v} using {slot_derivation.populated_from} // {source_obj}" - ) - elif slot_derivation.object_derivations: - # We'll collect all derived objects here - derived_objs = [] - - for obj_derivation in slot_derivation.object_derivations: - for target_cls, cls_derivation in obj_derivation.class_derivations.items(): - # Determine the correct source object to use - source_sub_obj = source_obj # You may refine this if needed - - # Recursively map the sub-object - nested_result = self.map_object( - source_sub_obj, - source_type=cls_derivation.populated_from, - target_type=target_cls, - class_derivation=cls_derivation, + if class_deriv.slot_derivations: + for slot_derivation in class_deriv.slot_derivations.values(): + v = None + source_class_slot = None + if slot_derivation.value is not None: + v = slot_derivation.value + if slot_derivation.range is None: + slot_derivation.range = "string" + elif slot_derivation.unit_conversion: + v = self._perform_unit_conversion(slot_derivation, source_obj, sv, source_type) + elif slot_derivation.expr: + if bindings is None: + bindings = Bindings( + self, + source_obj=source_obj, + source_obj_typed=source_obj_typed, + source_type=source_type, + sv=sv, + bindings={"NULL": None}, ) - derived_objs.append(nested_result) - # If the slot is multivalued, we assign the whole list - # Otherwise, just assign the first (for now; error/warning later if >1) - target_class_slot = self.target_schemaview.induced_slot(slot_derivation.name, target_type) - if target_class_slot.multivalued: - v = derived_objs - else: - v = derived_objs[0] if derived_objs else None - else: - source_class_slot = sv.induced_slot(slot_derivation.name, source_type) - v = source_obj.get(slot_derivation.name, None) - if source_class_slot and v is not None: - # slot is mapped and there is a value in the assignment - target_range = slot_derivation.range - source_class_slot_range = source_class_slot.range - if source_class_slot.multivalued: - if isinstance(v, list): - v = [self.map_object(v1, source_class_slot_range, target_range) for v1 in v] - elif isinstance(v, dict): - v = { - k1: self.map_object(v1, source_class_slot_range, target_range) - for k1, v1 in v.items() - } + try: + v = eval_expr_with_mapping(slot_derivation.expr, bindings) + except Exception as err: + if not self.unrestricted_eval: + msg = f"Expression not in safe subset: {slot_derivation.expr}" + raise RuntimeError(msg) from err + ctxt_obj, _ = bindings.get_ctxt_obj_and_dict() + aeval = Interpreter(usersyms={"src": ctxt_obj, "target": None}) + aeval(slot_derivation.expr) + v = aeval.symtable["target"] + elif slot_derivation.populated_from: + v = source_obj.get(slot_derivation.populated_from, None) + if slot_derivation.value_mappings and v is not None: + mapped = slot_derivation.value_mappings.get(str(v), None) + v = mapped.value if mapped is not None else None + source_class_slot = sv.induced_slot(slot_derivation.populated_from, source_type) + logger.debug( + f"Pop slot {slot_derivation.name} => {v} using {slot_derivation.populated_from} // {source_obj}" + ) + elif slot_derivation.sources: + vmap = {s: source_obj.get(s, None) for s in slot_derivation.sources} + vmap = {k: v for k, v in vmap.items() if v is not None} + if len(vmap.keys()) > 1: + msg = f"Multiple sources for {slot_derivation.name}: {vmap}" + raise ValueError(msg) + if len(vmap.keys()) == 1: + v = next(iter(vmap.values())) + source_class_slot_name = next(iter(vmap.keys())) + source_class_slot = sv.induced_slot(source_class_slot_name, source_type) else: - v = [self.map_object(v, source_class_slot_range, target_range)] - else: - v = self.map_object(v, source_class_slot_range, target_range) - if ( - self._is_coerce_to_multivalued(slot_derivation, class_deriv) - and v is not None - and not isinstance(v, list) - ): - v = self._singlevalued_to_multivalued(v, slot_derivation) - if self._is_coerce_to_singlevalued(slot_derivation, class_deriv) and isinstance( - v, list - ): - v = self._multivalued_to_singlevalued(v, slot_derivation) - v = self._coerce_datatype(v, target_range) - if slot_derivation.dictionary_key and isinstance(v, list): - # List to CompactDict - v = {v1[slot_derivation.dictionary_key]: v1 for v1 in v} - for v1 in v.values(): - del v1[slot_derivation.dictionary_key] - elif ( - slot_derivation.cast_collection_as - and slot_derivation.cast_collection_as == CollectionType.MultiValuedList - and isinstance(v, dict) - ): - # CompactDict to List - src_rng = source_class_slot.range - src_rng_id_slot = self.source_schemaview.get_identifier_slot( - src_rng, use_key=True + v = None + source_class_slot = None + + logger.debug( + f"Pop slot {slot_derivation.name} => {v} using {slot_derivation.populated_from} // {source_obj}" ) - if src_rng_id_slot: - v = [{**v1, src_rng_id_slot.name: k} for k, v1 in v.items()] + elif slot_derivation.object_derivations: + # We'll collect all derived objects here + derived_objs = [] + + for obj_derivation in slot_derivation.object_derivations: + for target_cls, cls_derivation in obj_derivation.class_derivations.items(): + # Determine the correct source object to use + source_sub_obj = source_obj # You may refine this if needed + + # Recursively map the sub-object + nested_result = self.map_object( + source_sub_obj, + source_type=cls_derivation.populated_from, + target_type=target_cls, + class_derivation=cls_derivation, + ) + derived_objs.append(nested_result) + + # If the slot is multivalued, we assign the whole list + # Otherwise, just assign the first (for now; error/warning later if >1) + target_class_slot = self.target_schemaview.induced_slot(slot_derivation.name, target_type) + if target_class_slot.multivalued: + v = derived_objs else: - v = list(v.values()) - tgt_attrs[str(slot_derivation.name)] = v - return tgt_attrs + v = derived_objs[0] if derived_objs else None + else: + source_class_slot = sv.induced_slot(slot_derivation.name, source_type) + v = source_obj.get(slot_derivation.name, None) + if source_class_slot and v is not None: + # slot is mapped and there is a value in the assignment + target_range = slot_derivation.range + source_class_slot_range = source_class_slot.range + if source_class_slot.multivalued: + if isinstance(v, list): + v = [self.map_object(v1, source_class_slot_range, target_range) for v1 in v] + elif isinstance(v, dict): + v = { + k1: self.map_object(v1, source_class_slot_range, target_range) + for k1, v1 in v.items() + } + else: + v = [self.map_object(v, source_class_slot_range, target_range)] + else: + v = self.map_object(v, source_class_slot_range, target_range) + if ( + self._is_coerce_to_multivalued(slot_derivation, class_deriv) + and v is not None + and not isinstance(v, list) + ): + v = self._singlevalued_to_multivalued(v, slot_derivation) + if self._is_coerce_to_singlevalued(slot_derivation, class_deriv) and isinstance( + v, list + ): + v = self._multivalued_to_singlevalued(v, slot_derivation) + v = self._coerce_datatype(v, target_range) + if slot_derivation.dictionary_key and isinstance(v, list): + # List to CompactDict + v = {v1[slot_derivation.dictionary_key]: v1 for v1 in v} + for v1 in v.values(): + del v1[slot_derivation.dictionary_key] + elif ( + slot_derivation.cast_collection_as + and slot_derivation.cast_collection_as == CollectionType.MultiValuedList + and isinstance(v, dict) + ): + # CompactDict to List + src_rng = source_class_slot.range + src_rng_id_slot = self.source_schemaview.get_identifier_slot( + src_rng, use_key=True + ) + if src_rng_id_slot: + v = [{**v1, src_rng_id_slot.name: k} for k, v1 in v.items()] + else: + v = list(v.values()) + tgt_attrs[str(slot_derivation.name)] = v + return tgt_attrs def _perform_unit_conversion( self, @@ -523,7 +524,7 @@ def transform_enum(self, source_value: str, enum_name: str, source_obj: Any) -> for pv_deriv in enum_deriv.permissible_value_derivations.values(): if source_value == pv_deriv.populated_from: return pv_deriv.name - if source_value in pv_deriv.sources: + if pv_deriv.sources and source_value in pv_deriv.sources: return pv_deriv.name if enum_deriv.mirror_source: return str(source_value) diff --git a/src/linkml_map/transformer/transformer.py b/src/linkml_map/transformer/transformer.py index 14ff730..b11f3c4 100644 --- a/src/linkml_map/transformer/transformer.py +++ b/src/linkml_map/transformer/transformer.py @@ -198,7 +198,8 @@ def _class_derivation_ancestors(self, cd: ClassDerivation) -> dict[str, ClassDer """ spec = self.specification ancestors = {} - parents = cd.mixins + ([cd.is_a] if cd.is_a else []) + mixins = cd.mixins or [] + parents = mixins + ([cd.is_a] if cd.is_a else []) for parent in parents: ancestors[parent] = spec.class_derivations[parent] ancestors.update(self._class_derivation_ancestors(spec.class_derivations[parent])) diff --git a/tests/test_schema_mapper/test_schema_mapper.py b/tests/test_schema_mapper/test_schema_mapper.py index 6366753..1df8c0d 100644 --- a/tests/test_schema_mapper/test_schema_mapper.py +++ b/tests/test_schema_mapper/test_schema_mapper.py @@ -139,7 +139,7 @@ def test_derive_partial(mapper: SchemaMapper) -> None: ClassDerivation(name="Agent", populated_from="Person"), ] for derivation in derivations: - specification.class_derivations[derivation.name] = derivation + specification.ensure_class_derivations()[derivation.name] = derivation target_schema = mapper.derive_schema(specification) print(yaml_dumper.dumps(target_schema)) assert list(target_schema.classes.keys()) == ["Agent"] @@ -215,7 +215,7 @@ def test_partial_copy_specification(mapper: SchemaMapper) -> None: ClassDerivation(name="Agent", populated_from="Person"), ] for derivation in derivations: - specification.class_derivations[derivation.name] = derivation + specification.ensure_class_derivations()[derivation.name] = derivation target_schema = mapper.derive_schema(specification) # classes must be the same with addition for schema_class in source_schema.classes: @@ -236,7 +236,7 @@ def test_full_copy_class(mapper: SchemaMapper) -> None: ClassDerivation(name="Agent", populated_from="Person", copy_directives=copy_all_directive), ] for derivation in derivations: - specification.class_derivations[derivation.name] = derivation + specification.ensure_class_derivations()[derivation.name] = derivation target_schema = mapper.derive_schema(specification) # classes must be the same with addition for schema_class in source_schema.classes: @@ -264,7 +264,7 @@ def test_copy_blacklisting(mapper: SchemaMapper) -> None: ClassDerivation(name="Agent", populated_from="Person"), ] for derivation in derivations: - specification.class_derivations[derivation.name] = derivation + specification.ensure_class_derivations()[derivation.name] = derivation target_schema = mapper.derive_schema(specification) # classes must be the same with addition for schema_class in source_schema.classes: @@ -298,7 +298,7 @@ def test_copy_whitelisting(mapper: SchemaMapper) -> None: ClassDerivation(name="Agent", populated_from="Person"), ] for derivation in derivations: - specification.class_derivations[derivation.name] = derivation + specification.ensure_class_derivations()[derivation.name] = derivation target_schema = mapper.derive_schema(specification) # classes, slots and enums must have only what explicitly included for schema_class in source_schema.classes: diff --git a/tests/test_transformer/test_biolink_subsetting.py b/tests/test_transformer/test_biolink_subsetting.py index 7a2eee8..9253feb 100644 --- a/tests/test_transformer/test_biolink_subsetting.py +++ b/tests/test_transformer/test_biolink_subsetting.py @@ -37,7 +37,7 @@ def get_biolink_class_derivations(sv: SchemaView, subset_classes: list) -> dict: induced_slots = sv.class_induced_slots(class_name) for slot in induced_slots: slot_derivation = SlotDerivation(populated_from=slot.name, name=underscore(slot.name)) - class_derivation.slot_derivations[underscore(slot.name)] = slot_derivation + class_derivation.ensure_slot_derivations()[underscore(slot.name)] = slot_derivation class_derivations[camelcase(class_name)] = class_derivation return class_derivations diff --git a/tests/test_transformer/test_object_transformer.py b/tests/test_transformer/test_object_transformer.py index 75c3f64..94b4f77 100644 --- a/tests/test_transformer/test_object_transformer.py +++ b/tests/test_transformer/test_object_transformer.py @@ -555,8 +555,8 @@ def mk(mv: bool, ex: bool = False) -> SchemaDefinition: sd.cast_collection_as = ( CollectionType.MultiValued if target_multivalued else CollectionType.SingleValued ) - specification.class_derivations[class_name] = cd - cd.slot_derivations[att_name] = sd + specification.ensure_class_derivations()[class_name] = cd + cd.ensure_slot_derivations()[att_name] = sd source_instance = {att_name: [val] if source_multivalued else val} tr = ObjectTransformer( specification=specification,