Skip to content

Commit

Permalink
experimental: first pass at unified model transformations
Browse files Browse the repository at this point in the history
  • Loading branch information
cmungall committed May 5, 2023
1 parent db3f98a commit c0e4fbe
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 4 deletions.
31 changes: 31 additions & 0 deletions linkml/transformers/model_transformer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from abc import abstractmethod
from dataclasses import dataclass
from typing import Any

from linkml_runtime import SchemaView
from linkml_runtime.linkml_model import SlotDefinition, ClassDefinitionName


@dataclass
class ModelTransformer:
"""
Base class for all model transformers
"""
schemaview: SchemaView = None

@abstractmethod
def transform(
self, tgt_schema_name: str = None, top_class: ClassDefinitionName = None
) -> Any:
raise NotImplementedError

def unfold_slot_range(self, slot: SlotDefinition):
union_ranges = []
for x in slot.any_of + slot.exactly_one_of:

Check warning on line 24 in linkml/transformers/model_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/model_transformer.py#L24

Added line #L24 was not covered by tests
if x.range:
union_ranges.append(x.range)
if not union_ranges:

Check warning on line 27 in linkml/transformers/model_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/model_transformer.py#L27

Added line #L27 was not covered by tests
union_ranges.append(slot.range)

Check warning on line 29 in linkml/transformers/model_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/model_transformer.py#L29

Added line #L29 was not covered by tests


95 changes: 95 additions & 0 deletions linkml/transformers/oomodel_transformer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from abc import ABC
from dataclasses import dataclass
from typing import Optional, List, Union

Check warning on line 3 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L1-L3

Added lines #L1 - L3 were not covered by tests

from pydantic import BaseModel

Check warning on line 5 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L5

Added line #L5 was not covered by tests

from linkml.transformers.model_transformer import ModelTransformer

Check warning on line 7 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L7

Added line #L7 was not covered by tests


Check warning on line 9 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L9

Added line #L9 was not covered by tests
NAME = str


Check warning on line 12 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L12

Added line #L12 was not covered by tests
class TargetLanguageProperties(BaseModel):
"""
Properties for a target language
"""
multiple_inheritance: Optional[bool] = None
ranges_as_unions: Optional[bool] = None
element_name_regex: Optional[str] = None
reserved_words: Optional[List[str]] = None

Check warning on line 20 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L17-L20

Added lines #L17 - L20 were not covered by tests


class ProgramElement(BaseModel, ABC):

Check warning on line 23 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L23

Added line #L23 was not covered by tests
"""
A base element in the object-oriented program model.
Each element must have a name. This should uniquely
identify within the context of the element type, and
in the scope of a module
"""
name: NAME
doc: Optional[str] = None

Check warning on line 33 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L32-L33

Added lines #L32 - L33 were not covered by tests

class ProgramPackage(ProgramElement):
pass

Check warning on line 37 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L36-L37

Added lines #L36 - L37 were not covered by tests

class ProgramModule(ProgramElement):
pass

Check warning on line 41 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L40-L41

Added lines #L40 - L41 were not covered by tests

RANGE = Union["DisjunctiveRangeExpression", "AtomicRangeExpression"]

Check warning on line 44 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L44

Added line #L44 was not covered by tests
class RangeExpression(BaseModel, ABC):
"""
A range expression

Check warning on line 47 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L47

Added line #L47 was not covered by tests
"""
optional: Optional[bool] = None


class DisjunctiveRangeExpression(RangeExpression):

Check warning on line 52 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L52

Added line #L52 was not covered by tests
"""
A disjunctive range expression
"""

Check warning on line 55 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L55

Added line #L55 was not covered by tests
ranges: List[RANGE]


class AtomicRangeExpression(RangeExpression):
"""

Check warning on line 60 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L60

Added line #L60 was not covered by tests
An atomic range expression
"""
range: NAME

Check warning on line 63 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L63

Added line #L63 was not covered by tests
package: Optional[NAME] = None


class ProgramField(ProgramElement):
"""
A field (attribute, slot) in a class.

Check warning on line 69 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L68-L69

Added lines #L68 - L69 were not covered by tests
"""
allowed_values: Optional[RANGE] = None
default_expression: Optional[str] = None

Check warning on line 72 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L72

Added line #L72 was not covered by tests



class ProgramClass(ProgramElement):
"""
A class in the object-oriented program model.

Check warning on line 78 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L77-L78

Added lines #L77 - L78 were not covered by tests
"""
is_a: Optional[NAME] = None
mixins: Optional[List[NAME]] = None

Check warning on line 81 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L81

Added line #L81 was not covered by tests
class_attributes: Optional[List[ProgramField]] = None
fields: Optional[List[ProgramField]] = None



class ProgramEnum(ProgramElement):
pass

Check warning on line 89 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L86-L89

Added lines #L86 - L89 were not covered by tests

@dataclass
class ObjectOrientedModelTransformer(ModelTransformer):
"""

Check warning on line 93 in linkml/transformers/oomodel_transformer.py

View check run for this annotation

Codecov / codecov/patch

linkml/transformers/oomodel_transformer.py#L92-L93

Added lines #L92 - L93 were not covered by tests
Transforms the source schema into an object-oriented model
"""
5 changes: 3 additions & 2 deletions linkml/transformers/relmodel_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from linkml_runtime.utils.schemaview import SchemaView, SlotDefinitionName
from sqlalchemy import *

from linkml.transformers.model_transformer import ModelTransformer


class RelationalAnnotations(Enum):
PRIMARY_KEY = "primary_key"
Expand Down Expand Up @@ -137,12 +139,11 @@ class TransformationResult:


@dataclass
class RelationalModelTransformer:
class RelationalModelTransformer(ModelTransformer):
"""
Transforms the source schema into a relational schema
"""

schemaview: SchemaView = None
# dialect: str = field(default_factory=lambda : 'sqlite')
skip_tree_root: bool = field(default_factory=lambda: False)
skip_abstract: bool = field(default_factory=lambda: True)
Expand Down
11 changes: 9 additions & 2 deletions linkml/transformers/schema_renamer.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,17 @@ def _rename(self, element: Any, parent_key: ElementName = None) -> Any:

@click.command()
@click.option("-o", "--output", help="path to output schema")
@click.option("-C", "--class-names", help="function for class names")
@click.option("-S", "--slot-names", help="function for slot names")
@click.option("-C", "--class-names", default="camel", show_default=True, help="function for class names")
@click.option("-S", "--slot-names", default="snake", show_default=True, help="function for slot names")
@click.argument("schema")
def main(schema, output, class_names, slot_names):
"""
Transforms a schema, renaming all elements to follow canonical casing conventions.
Example:
schema_renamer.py -C camelcase -S snakecase my_schema.yaml > my_schema_renamed.yaml
"""
sv = SchemaView(schema)

def n2f(n: str) -> Callable:
Expand Down

0 comments on commit c0e4fbe

Please sign in to comment.