def test_get_model(): metamodel = metamodel_from_str(grammar) model = metamodel.model_from_str(model_str) t = model.a[0].y assert get_model(t) is model
def get_parser(model_obj): """ Args: model_obj: the model object of interest Returns: the parser associated with the element """ the_model = get_model(model_obj) return the_model._tx_parser
def check_raw_type_is_defined_for_language(rawtype): if "generate_cpp" in self.options.keys( ) and self.options["generate_cpp"]: if rawtype.genericType == "custom" and not rawtype.cpptype: raise Exception( "C++ type is required to generate C++ code for {} in {}" .format(rawtype.name, get_model(rawtype)._tx_filename)) if "generate_python" in self.options.keys( ) and self.options["generate_python"]: if rawtype.genericType == "custom" and not rawtype.pythontype: raise Exception( "python type is required to generate python code for {} in {}" .format(rawtype.name, get_model(rawtype)._tx_filename)) if "generate_python_construct" in self.options.keys( ) and self.options["generate_python_construct"]: if not rawtype.pythonconstructtype: raise Exception( "python-construct type is required to generate python code for {} in {}" .format(rawtype.name, get_model(rawtype)._tx_filename))
def needs_to_be_resolved(parent_obj, attr_name): """ This function determines, if a reference (CrossReference) needs to be resolved or not (while creating the model, while resolving references). Args: parent_obj: the object containing the attribute to be resolved. attr_name: the attribute identification object. Returns: True if the attribute needs to be resolved. Else False. In case of lists of references, this function return true if any of the references in the list needs to be resolved. Note: outside the model building process (from_file or from_str) this function always returns False. """ if hasattr(get_model(parent_obj), "_tx_reference_resolver"): return get_model(parent_obj)._tx_reference_resolver. \ has_unresolved_crossrefs(parent_obj, attr_name) else: return False
def person_definer_scope(knows, attr, attr_ref): m = get_model(knows) # get the model of the currently processed element name = attr_ref.obj_name # the name of currently looked up element found_persons = list(filter(lambda p: p.name == name, m.persons)) if len(found_persons) > 0: return found_persons[0] # if a person exists, return it else: mm = get_metamodel(m) # else, create it and store it in the model person = mm['Person']() person.name = name person.parent = m m.persons.append(person) return person
def apply(self, obj, lookup_list, matched_path, first_element): """ Args: obj: model object lookup_list: non-empty name list Returns: The object indicated by the navigation object, Postponed, None, or a list (if a list has to be processed). """ from textx.scoping.tools import needs_to_be_resolved from textx.scoping import Postponed if first_element: from textx import get_model obj = get_model(obj) if len(lookup_list) == 0 and self.consume_name: return None, lookup_list, matched_path if needs_to_be_resolved(obj, self.name): return Postponed(), lookup_list, matched_path if hasattr(obj, self.name): target = getattr(obj, self.name) if not self.consume_name and self.fixed_name is None: return target, lookup_list, matched_path # return list else: if not isinstance(target, list): target = [target] if self.fixed_name is not None: lst = list( filter( lambda x: hasattr(x, "name") and getattr( x, "name") == self.fixed_name, target)) if len(lst) > 0: return lst[0], lookup_list, matched_path + [ lst[0] ] # return obj else: return None, lookup_list, matched_path # return None else: lst = list( filter( lambda x: hasattr(x, "name") and getattr( x, "name") == lookup_list[0], target)) if len(lst) > 0: return lst[0], lookup_list[1:], matched_path + [ lst[0] ] # return obj else: return None, lookup_list, matched_path # return None else: return None, lookup_list, matched_path
def get_location(model_obj): """ Args: model_obj: the model object of interest Returns: the line, col and filename of the model element. The filename may be None. This function may be used to fill exceptions """ the_model = get_model(model_obj) line, col = the_model._tx_parser.pos_to_linecol( model_obj._tx_position) return {"line": line, "col": col, "filename": the_model._tx_filename}
def test_issue89_get_obj_pos_in_text(): mm = textx.metamodel_from_str(''' Model: objs+=Obj; Obj: 'obj' name=ID; ''') m = mm.model_from_str('''obj A obj B obj C obj D ''') assert (1, 1) == textx.get_model(m.objs[0])._tx_parser.pos_to_linecol( m.objs[0]._tx_position) assert (2, 1) == m._tx_parser.pos_to_linecol(m.objs[1]._tx_position) assert (3, 2) == m._tx_parser.pos_to_linecol(m.objs[2]._tx_position) assert (4, 10) == m._tx_parser.pos_to_linecol(m.objs[3]._tx_position)
def json_scope_provider(obj, attr, attr_ref): if not obj.pyobj: from textx.scoping import Postponed return Postponed() if not hasattr(obj.pyobj, "data"): import json obj.pyobj.data = json.load( open( os.path.join( os.path.abspath( os.path.dirname(get_model(obj)._tx_filename)), obj.pyobj.filename))) if attr_ref.obj_name in obj.pyobj.data: return obj.pyobj.data[attr_ref.obj_name] else: raise TextXSemanticError("{} not found".format(attr_ref.obj_name))
def __call__(self, obj, attr, obj_ref): from textx.scoping.tools import get_referenced_object from textx.scoping import Postponed from textx import get_model try: res = get_referenced_object( None, obj, self.path_to_container_object + "." + obj_ref.obj_name, obj_ref.cls) if type(res) is Postponed: self.postponed_counter += 1 return res except TypeError as e: from textx.scoping.tools import get_parser line, col = get_parser(obj).pos_to_linecol(obj_ref.position) raise TextXSemanticError('{}'.format(str(e)), line=line, col=col, filename=get_model(obj)._tx_filename)
def check_array_attribute(array_attribute): """ check if array size depends only on attributes defined before it in the struct :param array_attribute: :return: None throws on error """ from itemlang.itemc.metamodel_formula import ScalarRef dependencies = map( lambda x: x.ref0, reduce( lambda l1, l2: l1 + l2, map(lambda node: get_children_of_type(ScalarRef, node), array_attribute.array_dimensions), [])) struct = array_attribute.parent index_of_array = struct.attributes.index(array_attribute) available_infos_until_this_array = struct.attributes[0:index_of_array] for d in dependencies: if not (d in available_infos_until_this_array): raise Exception( "array {}.{} depends on {}.{} not defined before it in {}.". format(struct.name, array_attribute.name, struct.name, d.name, get_model(struct)._tx_filename))
def __call__(self, obj, attr, obj_ref): from textx.model import ObjCrossRef, get_model assert type(obj_ref) is ObjCrossRef, type(obj_ref) # cls, obj_name = obj_ref.cls, obj_ref.obj_name # 1) lookup URIs... (first, before looking locally - to detect file # not founds and distant model errors...) # TODO: raise error if lookup is not unique model = get_model(obj) model_repository = model._tx_model_repository # 1) try to find object locally ret = self.scope_provider(obj, attr, obj_ref) if ret: return ret # 2) do we have loaded models? for m in model_repository.local_models.filename_to_model.values(): ret = self.scope_provider(m, attr, obj_ref) if ret: return ret return None
def get_from_zero_or_more(obj, lookup_list, first_element=False): assert self.start_locally() or self.start_at_root() # or, not xor if not allowed(obj, lookup_list, self): # also adjusts visited objs return # recursion stopper if first_element: if self.start_locally(): yield obj, lookup_list if self.start_at_root(): from textx import get_model yield get_model(obj), lookup_list else: yield obj, lookup_list assert isinstance(self.path_element.seq, RRELSequence) for iobj, ilookup_list in self.path_element.seq.get_next_matches( obj, lookup_list, allowed, first_element=first_element): if isinstance(iobj, Postponed): yield iobj, ilookup_list # found postponed return # yield from for iiobj, iilookup_list in get_from_zero_or_more( iobj, ilookup_list): yield iiobj, iilookup_list
def myassert(ref): if not ref.default_value: raise Exception("{}: {}.{} needs to have a default value".format( get_model(ref)._tx_filename, ref.parent.name, ref.name))
def __call__(self, obj, attr, obj_ref): """ the default scope provider Args: obj: unused (used for multi_metamodel_support) attr: unused obj_ref: the cross reference to be resolved Returns: the resolved reference or None """ from textx.const import RULE_COMMON, RULE_ABSTRACT from textx.model import ObjCrossRef from textx.scoping.tools import get_parser if obj_ref is None: return None # an error! (see model.py: resolve_refs (TODO check) assert type(obj_ref) is ObjCrossRef, type(obj_ref) if get_parser(obj).debug: get_parser(obj).dprint("Resolving obj crossref: {}:{}" .format(obj_ref.cls, obj_ref.obj_name)) def _inner_resolve_link_rule_ref(cls, obj_name): """ Depth-first resolving of link rule reference. """ if cls._tx_type is RULE_ABSTRACT: for inherited in cls._tx_inh_by: result = _inner_resolve_link_rule_ref(inherited, obj_name) if result: return result elif cls._tx_type == RULE_COMMON: # TODO make this code exchangable # allow to know the current attribute (model location for # namespace) and to navigate through the whole model... # OR (with another scope provider) to make custom lookups in # the model # # Scopeprovider # - needs: .current reference (in the model) # .the model (?) # - provides: the resolved object or None if id(cls) in get_parser(obj)._instances: objs = get_parser(obj)._instances[id(cls)] return objs.get(obj_name) if self.multi_metamodel_support: from textx import get_model, get_children from textx import textx_isinstance result_lst = get_children( lambda x: _hasattr(x, "name") and _getattr(x, "name") == obj_ref.obj_name and textx_isinstance(x, obj_ref.cls), get_model(obj)) if len(result_lst) == 1: result = result_lst[0] elif len(result_lst) > 1: line, col = get_parser(obj).pos_to_linecol(obj_ref.position) raise TextXSemanticError( "name {} is not unique.".format(obj_ref.obj_name), line=line, col=col, filename=get_model(obj)._tx_filename) else: result = None else: result = _inner_resolve_link_rule_ref(obj_ref.cls, obj_ref.obj_name) if result: return result return None # error handled outside
def basename(self): exercise = self.parent fn = get_model(exercise)._tx_filename.\ replace(sep, "_").\ replace(".", "_") return "uml_{}_{}".format(fn, exercise.content.index(self))
def __call__(self, obj, attr, obj_ref): """ the default scope provider Args: obj: unused (used for multi_metamodel_support) attr: unused obj_ref: the cross reference to be resolved Returns: the resolved reference or None """ from textx.const import RULE_COMMON, RULE_ABSTRACT from textx.model import ObjCrossRef from textx.scoping.tools import get_parser if obj_ref is None: return None # an error! (see model.py: resolve_refs (TODO check) assert type(obj_ref) is ObjCrossRef, type(obj_ref) if get_parser(obj).debug: get_parser(obj).dprint("Resolving obj crossref: {}:{}" .format(obj_ref.cls, obj_ref.obj_name)) def _inner_resolve_link_rule_ref(cls, obj_name): """ Depth-first resolving of link rule reference. """ if cls._tx_type is RULE_ABSTRACT: for inherited in cls._tx_inh_by: result = _inner_resolve_link_rule_ref(inherited, obj_name) if result: return result elif cls._tx_type == RULE_COMMON: # TODO make this code exchangable # allow to know the current attribute (model location for # namespace) and to navigate through the whole model... # OR (with another scope provider) to make custom lookups in # the model # # Scopeprovider # - needs: .current reference (in the model) # .the model (?) # - provides: the resolved object or None if id(cls) in get_parser(obj)._instances: objs = get_parser(obj)._instances[id(cls)] return objs.get(obj_name) if self.multi_metamodel_support: from textx import get_model, get_children from textx import textx_isinstance result_lst = get_children( lambda x: hasattr(x, "name") and x.name == obj_ref.obj_name and textx_isinstance(x, obj_ref.cls), get_model(obj)) if len(result_lst) == 1: result = result_lst[0] elif len(result_lst) > 1: line, col = get_parser(obj).pos_to_linecol(obj_ref.position) raise TextXSemanticError( "name {} is not unique.".format(obj_ref.obj_name), line=line, col=col, filename=get_model(obj)._tx_filename) else: result = None else: result = _inner_resolve_link_rule_ref(obj_ref.cls, obj_ref.obj_name) if result: return result return None # error handled outside
def apply(self, obj, lookup_list, matched_path, first_element): """ Args: obj: model object lookup_list: non-empty name list Returns: The object indicated by the navigation object, Postponed, None, or a list (if a list has to be processed). """ assert self.rrel_expression is not None from textx.scoping.tools import needs_to_be_resolved from textx.scoping import Postponed if first_element: from textx import get_model obj = get_model(obj) start = [obj] if not hasattr(obj, "parent"): # am I a root model node? if self.rrel_expression.importURI: if hasattr(obj, "_tx_model_repository"): for m in obj._tx_model_repository.local_models: start.append(m) if obj._tx_metamodel.builtin_models: for m in obj._tx_metamodel.builtin_models: start.append(m) if len(lookup_list) == 0 and self.consume_name: return None, lookup_list, matched_path def lookup(obj): if needs_to_be_resolved(obj, self.name): return Postponed(), lookup_list, matched_path if hasattr(obj, self.name): target = getattr(obj, self.name) if not self.consume_name and self.fixed_name is None: return target, lookup_list, matched_path # return list else: if not isinstance(target, list): target = [target] if self.fixed_name is not None: lst = list( filter( lambda x: hasattr(x, "name") and getattr( x, "name") == self.fixed_name, target)) if len(lst) > 0: return lst[0], lookup_list, matched_path + [ lst[0] ] # return obj else: return None, lookup_list, matched_path # return None else: lst = list( filter( lambda x: hasattr(x, "name") and getattr( x, "name") == lookup_list[0], target)) if len(lst) > 0: return lst[0], lookup_list[1:], matched_path + [ lst[0] ] # return obj else: return None, lookup_list, matched_path # return None else: return None, lookup_list, matched_path for start_obj in start: res, res_lookup_list, res_lookup_path = lookup(start_obj) if (res): return res, res_lookup_list, res_lookup_path return None, lookup_list, matched_path
def get_filename(self): return join(abspath(dirname(get_model(self)._tx_filename)), self.file)
def obj_is_newer_than_file(obj, filename): if not exists(filename): return True date = getmtime(filename) return obj_is_newer_than_date(get_model(obj), date)
def basename(self, relative_to): n = relpath( get_model(self)._tx_filename, dirname(get_model(relative_to)._tx_filename)) return n.replace(".exercise", "").replace(sep, ".")
def check_raw_type_has_defined_bits(rawtype): if rawtype.genericType != "custom" and not rawtype.genericBits: raise Exception("Bits need to be specified for {} in {}".format( rawtype.name, get_model(rawtype)._tx_filename))
def get_name(self): return basename(get_model(self)._tx_filename).replace(".exam", "")
def test_rrel_basic_lookup(): """ This is a basic test for the find function: we use a model with some structure and query this structure with RREL expressions. """ ################################# # META MODEL DEF ################################# my_metamodel = metamodel_from_str(metamodel_str) ################################# # MODEL PARSING ################################# my_model = my_metamodel.model_from_str(modeltext) ################################# # TEST ################################# P2 = find(my_model, "P2", "packages") assert P2.name == "P2" Part2 = find(my_model, "P2.Part2", "packages.classes") assert Part2.name == "Part2" rec = find(my_model, "P2.Part2.rec", "packages.classes.attributes") rec_with_fixed_name = find(my_model, "P2.rec", "packages.'Part2'~classes.attributes") assert rec_with_fixed_name is rec assert rec.name == "rec" assert rec.parent == Part2 P2 = find(my_model, "P2", "(packages)") assert P2.name == "P2" from textx import get_model assert get_model(my_model) is my_model P2 = find(my_model, "P2", "packages*") assert P2.name == "P2" Part2 = find(my_model, "P2.Part2", "packages*.classes") assert Part2.name == "Part2" rec = find(my_model, "P2.Part2.rec", "packages*.classes.attributes") assert rec.name == "rec" assert rec.parent == Part2 Part2_tst = find(rec, "", "..") assert Part2_tst is Part2 P2_from_inner_node = find(rec, "P2", "(packages)") assert P2_from_inner_node is P2 P2_tst = find(rec, "", "parent(Package)") assert P2_tst is P2 P2_tst = find(rec, "", "...") assert P2_tst is P2 P2_tst = find(rec, "", ".(..).(..)") assert P2_tst is P2 P2_tst = find(rec, "", "(..).(..)") assert P2_tst is P2 P2_tst = find(rec, "", "...(.).(.)") assert P2_tst is P2 P2_tst = find(rec, "", "..(.).(..)") assert P2_tst is P2 P2_tst = find(rec, "", "..((.)*)*.(..)") assert P2_tst is P2 none = find(my_model, "", "..") assert none is None m = find(my_model, "", ".") # '.' references the current element assert m is my_model inner = find(my_model, "inner", "~packages.~packages.~classes.attributes") assert inner.name == "inner" package_Inner = find(inner, "Inner", "parent(OBJECT)*.packages") assert textx_isinstance(package_Inner, my_metamodel["Package"]) assert not textx_isinstance(package_Inner, my_metamodel["Class"]) assert None is find(inner, "P2", "parent(Class)*.packages") # expensive version of a "Plain Name" scope provider: inner = find(my_model, "inner", "~packages*.~classes.attributes") assert inner.name == "inner" rec2 = find(my_model, "P2.Part2.rec", "other1,other2,packages*.classes.attributes") assert rec2 is rec rec2 = find(my_model, "P2.Part2.rec", "other1,packages*.classes.attributes,other2") assert rec2 is rec rec2 = find(my_model, "P2::Part2::rec", "other1,packages*.classes.attributes,other2", split_string="::") assert rec2 is rec rec2 = find(my_model, "P2.Part2.rec", "other1,other2,other3") assert rec2 is None rec2 = find(my_model, "P2.Part2.rec", "(packages,classes,attributes)*") assert rec2 is rec rec2 = find(my_model, "P2.Part2.rec", "(packages,(classes,attributes)*)*.attributes") assert rec2 is rec rec2 = find(my_model, "rec", "(~packages,~classes,attributes,classes)*") assert rec2.name == "rec" rec2 = find(my_model, "rec", "(~packages,~classes,attributes,classes)*", my_metamodel["OBJECT"]) assert rec2.name == "rec" rec2 = find(my_model, "rec", "(~packages,~classes,attributes,classes)*", my_metamodel["Attribute"]) assert rec2 is rec rec2 = find(my_model, "rec", "(~packages,~classes,attributes,classes)*", my_metamodel["Package"]) assert rec2 is None rec2 = find(my_model, "rec", "(~packages,classes,attributes,~classes)*", my_metamodel["Class"]) assert rec2.name == "rec" assert rec2 is not rec # it is the class... rec2 = find(my_model, "rec", "(~packages,~classes,attributes,classes)*", my_metamodel["Class"]) assert rec2.name == "rec" assert rec2 is not rec # it is the class... t = find(my_model, "", ".") assert t is my_model t = find(my_model, "", "(.)") assert t is my_model t = find(my_model, "", "(.)*") assert t is my_model t = find(my_model, "", "(.)*.no_existent") # inifite recursion stopper assert t is None rec2 = find(my_model, "rec", "(.)*.(~packages,~classes,attributes,classes)*", my_metamodel["Class"]) assert rec2.name == "rec" assert rec2 is not rec # it is the class... # Here, we test the start_from_root/start_locally logic: P2t = find(rec, "P2", "(.)*.packages") assert P2t is None P2t = find(rec, "P2", "(.,not_existent_but_root)*.packages") assert P2t is P2 rect = find(rec, "rec", "(~packages)*.(..).attributes") assert rect is None rect = find(rec, "rec", "(.,~packages)*.(..).attributes") assert rect is rec