Skip to content
Snippets Groups Projects
Commit 7eb8aee6 authored by Henrik tom Wörden's avatar Henrik tom Wörden
Browse files

test

parent 529838a1
Branches
Tags
2 merge requests!22Release 0.3,!14F fix list
Pipeline #10431 failed
...@@ -21,6 +21,7 @@ import sys ...@@ -21,6 +21,7 @@ import sys
import caosdb as db import caosdb as db
import yaml import yaml
from caosdb.common.datatype import is_reference
from .data_model import DataModel from .data_model import DataModel
...@@ -43,8 +44,23 @@ KEYWORDS_IGNORED = [ ...@@ -43,8 +44,23 @@ KEYWORDS_IGNORED = [
] ]
def _get_listdatatype(dtype):
"""matches a string to check whehter the type definition is a list
returns the type within the list or None, if it cannot be matched with a
list definition
"""
match = re.match(r"^LIST[(](?P<dt>.*)[)]$", dtype)
if match is None:
return None
else:
return match.group("dt")
# Taken from https://stackoverflow.com/a/53647080, CC-BY-SA, 2018 by # Taken from https://stackoverflow.com/a/53647080, CC-BY-SA, 2018 by
# https://stackoverflow.com/users/2572431/augurar # https://stackoverflow.com/users/2572431/augurar
class SafeLineLoader(yaml.SafeLoader): class SafeLineLoader(yaml.SafeLoader):
"""Load a line and keep meta-information. """Load a line and keep meta-information.
...@@ -56,6 +72,7 @@ class SafeLineLoader(yaml.SafeLoader): ...@@ -56,6 +72,7 @@ class SafeLineLoader(yaml.SafeLoader):
mapping = super().construct_mapping(node, deep=deep) mapping = super().construct_mapping(node, deep=deep)
# Add 1 so line numbering starts at 1 # Add 1 so line numbering starts at 1
mapping['__line__'] = node.start_mark.line + 1 mapping['__line__'] = node.start_mark.line + 1
return mapping return mapping
# End of https://stackoverflow.com/a/53647080 # End of https://stackoverflow.com/a/53647080
...@@ -76,12 +93,14 @@ class YamlDefinitionError(RuntimeError): ...@@ -76,12 +93,14 @@ class YamlDefinitionError(RuntimeError):
def parse_model_from_yaml(filename): def parse_model_from_yaml(filename):
"""Shortcut if the Parser object is not needed.""" """Shortcut if the Parser object is not needed."""
parser = Parser() parser = Parser()
return parser.parse_model_from_yaml(filename) return parser.parse_model_from_yaml(filename)
def parse_model_from_string(string): def parse_model_from_string(string):
"""Shortcut if the Parser object is not needed.""" """Shortcut if the Parser object is not needed."""
parser = Parser() parser = Parser()
return parser.parse_model_from_string(string) return parser.parse_model_from_string(string)
...@@ -105,6 +124,7 @@ class Parser(object): ...@@ -105,6 +124,7 @@ class Parser(object):
""" """
with open(filename, 'r') as outfile: with open(filename, 'r') as outfile:
ymlmodel = yaml.load(outfile, Loader=SafeLineLoader) ymlmodel = yaml.load(outfile, Loader=SafeLineLoader)
return self._create_model_from_dict(ymlmodel) return self._create_model_from_dict(ymlmodel)
def parse_model_from_string(self, string): def parse_model_from_string(self, string):
...@@ -121,6 +141,7 @@ class Parser(object): ...@@ -121,6 +141,7 @@ class Parser(object):
The created DataModel The created DataModel
""" """
ymlmodel = yaml.load(string, Loader=SafeLineLoader) ymlmodel = yaml.load(string, Loader=SafeLineLoader)
return self._create_model_from_dict(ymlmodel) return self._create_model_from_dict(ymlmodel)
def _create_model_from_dict(self, ymlmodel): def _create_model_from_dict(self, ymlmodel):
...@@ -148,6 +169,7 @@ class Parser(object): ...@@ -148,6 +169,7 @@ class Parser(object):
# a record type with the name of the element. # a record type with the name of the element.
# The retrieved entity will be added to the model. # The retrieved entity will be added to the model.
# If no entity with that name is found an exception is raised. # If no entity with that name is found an exception is raised.
if "extern" not in ymlmodel: if "extern" not in ymlmodel:
ymlmodel["extern"] = [] ymlmodel["extern"] = []
...@@ -196,11 +218,14 @@ class Parser(object): ...@@ -196,11 +218,14 @@ class Parser(object):
out : str out : str
If `name` was a string, return it. Else return str(`name`). If `name` was a string, return it. Else return str(`name`).
""" """
if name is None: if name is None:
print("WARNING: Name of this context is None: {}".format(context), print("WARNING: Name of this context is None: {}".format(context),
file=sys.stderr) file=sys.stderr)
if not isinstance(name, str): if not isinstance(name, str):
name = str(name) name = str(name)
return name return name
def _add_entity_to_model(self, name, definition): def _add_entity_to_model(self, name, definition):
...@@ -208,9 +233,11 @@ class Parser(object): ...@@ -208,9 +233,11 @@ class Parser(object):
Properties are also initialized. Properties are also initialized.
""" """
if name == "__line__": if name == "__line__":
return return
name = self._stringify(name) name = self._stringify(name)
if name not in self.model: if name not in self.model:
self.model[name] = None self.model[name] = None
...@@ -222,7 +249,7 @@ class Parser(object): ...@@ -222,7 +249,7 @@ class Parser(object):
# is it a property # is it a property
and "datatype" in definition and "datatype" in definition
# but not a list # but not a list
and not definition["datatype"].startswith("LIST")): and not is_reference(db.Property(datatype=definition["datatype"]))):
# and create the new property # and create the new property
self.model[name] = db.Property(name=name, self.model[name] = db.Property(name=name,
...@@ -235,6 +262,7 @@ class Parser(object): ...@@ -235,6 +262,7 @@ class Parser(object):
if prop_type in definition: if prop_type in definition:
# Empty property mapping should be allowed. # Empty property mapping should be allowed.
if definition[prop_type] is None: if definition[prop_type] is None:
definition[prop_type] = {} definition[prop_type] = {}
try: try:
...@@ -245,6 +273,7 @@ class Parser(object): ...@@ -245,6 +273,7 @@ class Parser(object):
except AttributeError as ate: except AttributeError as ate:
if ate.args[0].endswith("'items'"): if ate.args[0].endswith("'items'"):
line = definition["__line__"] line = definition["__line__"]
if isinstance(definition[prop_type], list): if isinstance(definition[prop_type], list):
line = definition[prop_type][0]["__line__"] line = definition[prop_type][0]["__line__"]
raise YamlDefinitionError(line) from None raise YamlDefinitionError(line) from None
...@@ -252,26 +281,24 @@ class Parser(object): ...@@ -252,26 +281,24 @@ class Parser(object):
def _add_to_recordtype(self, ent_name, props, importance): def _add_to_recordtype(self, ent_name, props, importance):
"""Add properties to a RecordType.""" """Add properties to a RecordType."""
for n, e in props.items(): for n, e in props.items():
if n in KEYWORDS: if n in KEYWORDS:
if n in KEYWORDS_IGNORED: if n in KEYWORDS_IGNORED:
continue continue
raise YamlDefinitionError("Unexpected keyword in line {}: {}".format( raise YamlDefinitionError("Unexpected keyword in line {}: {}".format(
props["__line__"], n)) props["__line__"], n))
if n == "__line__": if n == "__line__":
continue continue
n = self._stringify(n) n = self._stringify(n)
if isinstance(e, dict) and "datatype" in e and e["datatype"].startswith("LIST"): if (isinstance(e, dict) and "datatype" in e
match = re.match(r"LIST[(](.*)[)]", e["datatype"]) and (_get_listdatatype(e["datatype"]) is not None)):
self.model[ent_name].add_property(
if match is None: name=n,
raise ValueError("List datatype definition is wrong")
dt = db.LIST(match.group(1))
self.model[ent_name].add_property(name=n,
importance=importance, importance=importance,
datatype=dt datatype=_get_listdatatype(e["datatype"]))
)
else: else:
self.model[ent_name].add_property(name=n, self.model[ent_name].add_property(name=n,
importance=importance) importance=importance)
...@@ -288,6 +315,7 @@ class Parser(object): ...@@ -288,6 +315,7 @@ class Parser(object):
def _treat_entity(self, name, definition, line=None): def _treat_entity(self, name, definition, line=None):
"""Parse the definition and the information to the entity.""" """Parse the definition and the information to the entity."""
if name == "__line__": if name == "__line__":
return return
name = self._stringify(name) name = self._stringify(name)
...@@ -366,7 +394,11 @@ class Parser(object): ...@@ -366,7 +394,11 @@ class Parser(object):
else: else:
# get the datatype # get the datatype
try: try:
if _get_listdatatype(value.datatype) is None:
value.datatype = db.__getattribute__(value.datatype) value.datatype = db.__getattribute__(value.datatype)
else:
value.datatype = db.__getattribute__(
_get_listdatatype(value.datatype))
except AttributeError: except AttributeError:
raise ValueError("Unknown Datatype.") raise ValueError("Unknown Datatype.")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment