Source code for linkml.generators.protogen
import os
from dataclasses import dataclass
from typing import Optional
import click
from linkml_runtime.linkml_model.meta import ClassDefinition, SlotDefinition
from linkml_runtime.utils.formatutils import camelcase, lcamelcase
from linkml._version import __version__
from linkml.utils.generator import Generator, shared_arguments
[docs]@dataclass
class ProtoGenerator(Generator):
"""
A `Generator` for creating Protobuf schemas from a linkml schema.
"""
# ClassVars
generatorname = os.path.basename(__file__)
generatorversion = "0.1.1"
valid_formats = ["proto"]
visit_all_class_slots = True
uses_schemaloader = True
# ObjectVars
relative_slot_num: int = 0
def visit_schema(self, **kwargs) -> Optional[str]:
return self.generate_header()
def generate_header(self) -> str:
items = []
items.append(' syntax="proto3";')
items.append(" package")
items.append(f"// metamodel_version: {self.schema.metamodel_version}")
if self.schema.version:
items.append(f"// version: {self.schema.version}")
out = "\n".join(items) + "\n"
return out
def visit_class(self, cls: ClassDefinition) -> Optional[str]:
if cls.mixin or cls.abstract or not cls.slots:
return None
items = []
if cls.description:
for dline in cls.description.split("\n"):
items.append(f"// {dline}")
items.append(f"message {camelcase(cls.name)}")
items.append(" {")
out = "\n".join(items)
self.relative_slot_num = 0
return out
def end_class(self, cls: ClassDefinition) -> str:
return "\n }\n"
def visit_class_slot(self, cls: ClassDefinition, aliased_slot_name: str, slot: SlotDefinition) -> str:
qual = "repeated " if slot.multivalued else ""
slotname = lcamelcase(aliased_slot_name)
slot_range = camelcase(slot.range)
if slot.rank is None:
# numbering of slots is important in the proto implementation
# and should be determined by the rank param.
slot.rank = 0
return f"\n {qual} {lcamelcase(slot_range)} {(slotname)} = {slot.rank}"
@shared_arguments(ProtoGenerator)
@click.version_option(__version__, "-V", "--version")
@click.command()
def cli(yamlfile, **args):
"""Generate proto representation of LinkML model"""
print(ProtoGenerator(yamlfile, **args).serialize(**args))
if __name__ == "__main__":
cli()