def test_get_children(): metamodel = metamodel_from_str(grammar) model = metamodel.model_from_str(model_str) seconds_thirds = get_children( lambda x: x.__class__.__name__ in ['Second', 'Third'], model) assert len(seconds_thirds) == 8 # 3 seconds and 5 thirds assert seconds_thirds[0].x == [23, 45, 56] assert seconds_thirds[1].x == 'one' assert seconds_thirds[-1].x == 'third' # Children first seconds_thirds = get_children( lambda x: x.__class__.__name__ in ['Second', 'Third'], model, children_first=True) assert len(seconds_thirds) == 8 # 3 seconds and 5 thirds assert seconds_thirds[0].x == 'one' assert seconds_thirds[1].x == [23, 45, 56] assert seconds_thirds[-1].x == 'third' # Do not traverse seconds seconds_thirds = get_children( lambda x: x.__class__.__name__ in ['Second', 'Third'], model, should_follow=lambda x: x.__class__.__name__ != 'Second') assert len(seconds_thirds) == 3 # Only 3 thirds at the top of the model assert seconds_thirds[0].x == 'first' assert seconds_thirds[-1].x == 'third'
def test_model_with_circular_imports(): """ Basic test for FQNImportURI + circular imports """ ################################# # META MODEL DEF ################################# my_meta_model = metamodel_from_file( join(abspath(dirname(__file__)), 'interface_model1', 'Interface.tx')) my_meta_model.register_scope_providers( {"*.*": scoping_providers.FQNImportURI()}) ################################# # MODEL PARSING ################################# my_model = my_meta_model.model_from_file( join(abspath(dirname(__file__)), "interface_model1", "model_c", "A.if")) ################################# # TEST MODEL ################################# imports = get_children_of_type("Import", my_model) assert len(imports) > 0 for i in imports: assert 1 == len(i._tx_loaded_models) # one file / load import assert i.importURI in i._tx_loaded_models[0]._tx_filename check_unique_named_object_has_class(my_model, "A", "Interface") a = get_unique_named_object(my_model, "A") a_self = get_children(lambda x: hasattr(x, 'name') and x.name == "self", a) assert len(a_self) == 1 a_self = a_self[0] a_other = get_children( lambda x: hasattr(x, 'name') and x.name == "other", a) assert len(a_other) == 1 a_other = a_other[0] a_other_self = get_children( lambda x: hasattr(x, 'name') and x.name == "self", a_other.ref) assert len(a_other_self) == 1 a_other_self = a_other_self[0] a_other_other = get_children( lambda x: hasattr(x, 'name') and x.name == "other", a_other.ref) assert len(a_other_other) == 1 a_other_other = a_other_other[0] assert a_self.ref == a_other_other.ref assert a_self.ref != a_other.ref assert a_other.ref == a_other_self.ref assert a_other.ref != a_other_other.ref
def test_model_with_circular_imports(): """ Basic test for FQNImportURI + circular imports """ ################################# # META MODEL DEF ################################# my_meta_model = metamodel_from_file( join(abspath(dirname(__file__)), 'interface_model1', 'Interface.tx')) my_meta_model.register_scope_providers( {"*.*": scoping_providers.FQNImportURI()}) ################################# # MODEL PARSING ################################# my_model = my_meta_model.model_from_file( join(abspath(dirname(__file__)), "interface_model1", "model_c", "A.if")) ################################# # TEST MODEL ################################# imports = get_children_of_type("Import", my_model) assert len(imports) > 0 for i in imports: assert 1 == len(i._tx_loaded_models) # one file / load import assert i.importURI in i._tx_loaded_models[0]._tx_filename check_unique_named_object_has_class(my_model, "A", "Interface") a = get_unique_named_object(my_model, "A") a_self = get_children(lambda x: hasattr(x, 'name') and x.name == "self", a) assert len(a_self) == 1 a_self = a_self[0] a_other = get_children(lambda x: hasattr(x, 'name') and x.name == "other", a) assert len(a_other) == 1 a_other = a_other[0] a_other_self = get_children( lambda x: hasattr(x, 'name') and x.name == "self", a_other.ref) assert len(a_other_self) == 1 a_other_self = a_other_self[0] a_other_other = get_children( lambda x: hasattr(x, 'name') and x.name == "other", a_other.ref) assert len(a_other_other) == 1 a_other_other = a_other_other[0] assert a_self.ref == a_other_other.ref assert a_self.ref != a_other.ref assert a_other.ref == a_other_self.ref assert a_other.ref != a_other_other.ref
def get_unique_named_object_in_all_models(root, name): """ retrieves a unique named object (no fully qualified name) Args: root: start of search (if root is a model all known models are searched as well) name: name of object Returns: the object (if not unique, raises an error) """ if hasattr(root, '_tx_model_repository'): src = list( root._tx_model_repository.local_models.filename_to_model.values()) if root not in src: src.append(root) else: src = [root] a = [] for m in src: # print("analyzing {}".format(m._tx_filename)) a = a + get_children( lambda x: hasattr(x, 'name') and x.name == name, m) assert len(a) == 1 return a[0]
def test_children(): """ This test checks the get_children function """ ################################# # META MODEL DEF ################################# my_metamodel = metamodel_from_str(metamodel_str) my_metamodel.register_scope_providers({"*.*": scoping_providers.FQN()}) ################################# # MODEL PARSING ################################# my_model = my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class Part2 { attr C2 rec; } class C2 { attr P1.Part1 p1; attr Part2 p2a; attr P2.Part2 p2b; } } ''') ################################# # TEST ################################# res = get_children_of_type("Class", my_model) res.sort(key=lambda x: x.name) assert len(res) == 3 assert all(map(eq, map(lambda x: x.name, res), ["C2", "Part1", "Part2"])) assert not all(map(eq, map(lambda x: x.name, res), ["Part1", "Part2", "C2"])) for x in res: assert x.__class__.__name__ == "Class" res = get_children_of_type("Attribute", my_model) res.sort(key=lambda x: x.name) assert len(res) == 4 assert all(map(eq, map(lambda x: x.name, res), ["p1", "p2a", "p2b", "rec"])) for x in res: assert x.__class__.__name__ == "Attribute" res = get_children(lambda x: hasattr(x, "name") and re.match( ".*2.*", x.name), my_model) res.sort(key=lambda x: x.name) assert len(res) == 5 assert all(map(eq, map(lambda x: x.name, res), ["C2", "P2", "Part2", "p2a", "p2b"]))
def get_unique_named_object_in_all_models(root, name): """ retrieves a unique named object (no fully qualified name) Args: root: start of search (if root is a model all known models are searched as well) name: name of object Returns: the object (if not unique, raises an error) """ if hasattr(root, '_tx_model_repository'): src = list( root._tx_model_repository.local_models.filename_to_model.values()) if root not in src: src.append(root) else: src = [root] a = [] for m in src: print("analyzing {}".format(m._tx_filename)) a = a + get_children( lambda x: hasattr(x, 'name') and x.name == name, m) assert len(a) == 1 return a[0]
def _load_referenced_models(self, model, encoding='utf-8'): from textx.model import get_children visited = [] for obj in get_children( lambda x: hasattr(x, "importURI") and x not in visited, model): visited.append(obj) if self.search_path is not None: # search_path based i/o: my_search_path = \ [dirname(model._tx_filename)] + self.search_path loaded_model = \ model._tx_model_repository.load_model_using_search_path( obj.importURI, model=model, search_path=my_search_path) obj._tx_loaded_models = [loaded_model] else: # globing based i/o: basedir = dirname(model._tx_filename) if len(basedir) > 0: basedir += "/" filename_pattern = abspath(basedir + obj.importURI) obj._tx_loaded_models = \ model._tx_model_repository.load_models_using_filepattern( filename_pattern, model=model, glob_args=self.glob_args, encoding=encoding)
def test_model_with_circular_imports(): ################################# # META MODEL DEF ################################# my_meta_model = metamodel_from_file( abspath(dirname(__file__)) + '/interface_model1/Interface.tx') my_meta_model.register_scope_providers( {"*.*": scoping_providers.FQNImportURI()}) ################################# # MODEL PARSING ################################# my_model = my_meta_model.model_from_file( abspath(dirname(__file__)) + "/interface_model1/model_c/A.if") ################################# # TEST MODEL ################################# check_unique_named_object_has_class(my_model, "A", "Interface") a = get_unique_named_object(my_model, "A") a_self = get_children(lambda x: hasattr(x, 'name') and x.name == "self", a) assert len(a_self) == 1 a_self = a_self[0] a_other = get_children(lambda x: hasattr(x, 'name') and x.name == "other", a) assert len(a_other) == 1 a_other = a_other[0] a_other_self = get_children( lambda x: hasattr(x, 'name') and x.name == "self", a_other.ref) assert len(a_other_self) == 1 a_other_self = a_other_self[0] a_other_other = get_children( lambda x: hasattr(x, 'name') and x.name == "other", a_other.ref) assert len(a_other_other) == 1 a_other_other = a_other_other[0] assert a_self.ref == a_other_other.ref assert a_self.ref != a_other.ref assert a_other.ref == a_other_self.ref assert a_other.ref != a_other_other.ref
def test_fully_qualified_name_ref(): ################################# # META MODEL DEF ################################# my_metamodel = metamodel_from_str(metamodel_str) my_metamodel.register_scope_providers({"*.*": scoping_providers.FQN()}) ################################# # MODEL PARSING ################################# my_model = my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class Part2 { attr C2 rec; } class C2 { attr P1.Part1 p1; attr Part2 p2a; attr P2.Part2 p2b; } } ''') ################################# # TEST ################################# res = get_children_of_type("Class", my_model) res.sort(key=lambda x: x.name) assert len(res) == 3 assert all(map(eq, map(lambda x: x.name, res), ["C2", "Part1", "Part2"])) assert not all( map(eq, map(lambda x: x.name, res), ["Part1", "Part2", "C2"])) for x in res: assert x.__class__.__name__ == "Class" res = get_children_of_type("Attribute", my_model) res.sort(key=lambda x: x.name) assert len(res) == 4 assert all(map(eq, map(lambda x: x.name, res), ["p1", "p2a", "p2b", "rec"])) for x in res: assert x.__class__.__name__ == "Attribute" res = get_children( lambda x: hasattr(x, "name") and re.match(".*2.*", x.name), my_model) res.sort(key=lambda x: x.name) assert len(res) == 5 assert all( map(eq, map(lambda x: x.name, res), ["C2", "P2", "Part2", "p2a", "p2b"]))
def _export_subgraph(m): from textx import get_children f.write('subgraph "cluster_{}" {{\n'.format(m._tx_filename)) f.write(''' penwidth=2.0 color=darkorange4; label = "{}"; '''.format(m._tx_filename)) for obj in get_children(lambda _: True, m): f.write('{};\n'.format(id(obj))) f.write('\n}\n')
def test_fully_qualified_name_ref_with_splitstring(): """ This is a basic test for the FQN (positive and negative test). """ ################################# # META MODEL DEF ################################# my_metamodel = metamodel_from_str(r''' Model: packages*=Package; Package: 'package' name=ID '{' classes*=Class '}'; Class: 'class' name=ID '{'attributes*=Attribute'}'; Attribute: 'attr' ref=[Class|FQN] name=ID ';'; Comment: /#.*/; FQN[split='/']: ID('/'ID)*; ''') my_metamodel.register_scope_providers( {"Attribute.ref": "^packages*.classes"}) ################################# # MODEL PARSING ################################# my_model = my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class Part2 { attr C2 rec; } class C2 { attr P1/Part1 p1; attr Part2 p2a; attr P2/Part2 p2b; } } ''') ################################# # TEST MODEL ################################# a = get_children(lambda x: hasattr(x, 'name') and x.name == "rec", my_model) assert len(a) == 1 assert a[0].name == "rec" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "C2"
def get_unique_named_object(root, name): """ retrieves a unique named object (no fully qualified name) Args: root: start of search name: name of object Returns: the object (if not unique, raises an error) """ a = get_children(lambda x: hasattr(x, 'name') and x.name == name, root) assert len(a) == 1 return a[0]
def _load_referenced_models(self, model): from textx.model import get_children visited = [] for obj in get_children( lambda x: hasattr(x, "importURI") and x not in visited, model): visited.append(obj) # TODO add multiple lookup rules for file search basedir = dirname(model._tx_filename) if len(basedir) > 0: basedir += "/" filename_pattern = abspath(basedir + obj.importURI) obj._tx_loaded_models = \ model._tx_model_repository.load_models_using_filepattern( filename_pattern, model=model, glob_args=self.glob_args)
def _load_referenced_models(self, model, encoding): from textx.model import get_children visited = [] for obj in get_children( lambda x: hasattr(x, "importURI") and x not in visited, model): add_to_local_models = True if self.importURI_to_scope_name is not None: obj.name = self.importURI_to_scope_name(obj) # print("setting name to {}".format(obj.name)) if hasattr(obj, "name"): if obj.name is not None and obj.name != "": add_to_local_models = not self.importAs visited.append(obj) if self.search_path is not None: # search_path based i/o: my_search_path = \ [dirname(model._tx_filename)] + self.search_path loaded_model = \ model._tx_model_repository.load_model_using_search_path( self.importURI_converter(obj.importURI), model=model, search_path=my_search_path, encoding=encoding, add_to_local_models=add_to_local_models, model_params=model._tx_model_params) obj._tx_loaded_models = [loaded_model] else: # globing based i/o: basedir = dirname(model._tx_filename) filename_pattern = abspath( join(basedir, self.importURI_converter(obj.importURI))) obj._tx_loaded_models = \ model._tx_model_repository.load_models_using_filepattern( filename_pattern, model=model, glob_args=self.glob_args, encoding=encoding, add_to_local_models=add_to_local_models, model_params=model._tx_model_params)
def _load_referenced_models(self, model, encoding): from textx.model import get_children visited = [] for obj in get_children( lambda x: hasattr(x, "importURI") and x not in visited, model): add_to_local_models = True if self.importURI_to_scope_name is not None: obj.name = self.importURI_to_scope_name(obj) print("setting name to {}".format(obj.name)) if hasattr(obj, "name"): if obj.name is not None and obj.name != "": add_to_local_models = not self.importAs visited.append(obj) if self.search_path is not None: # search_path based i/o: my_search_path = \ [dirname(model._tx_filename)] + self.search_path loaded_model = \ model._tx_model_repository.load_model_using_search_path( self.importURI_converter(obj.importURI), model=model, search_path=my_search_path, encoding=encoding, add_to_local_models=add_to_local_models) obj._tx_loaded_models = [loaded_model] else: # globing based i/o: basedir = dirname(model._tx_filename) filename_pattern = abspath( join(basedir, self.importURI_converter(obj.importURI))) obj._tx_loaded_models = \ model._tx_model_repository.load_models_using_filepattern( filename_pattern, model=model, glob_args=self.glob_args, encoding=encoding, add_to_local_models=add_to_local_models)
def test_plain_name_ref(): """ Basic test for PlainName (good case and bad case) """ ################################# # META MODEL DEF ################################# my_metamodel = metamodel_from_str(metamodel_str) my_metamodel.register_scope_providers( {"*.*": scoping_providers.PlainName(multi_metamodel_support=False)}) ################################# # MODEL PARSING ################################# my_model = my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class Part2 { attr C2 rec; } class C2 { attr Part1 p1; attr Part2 p2a; attr Part2 p2b; } } ''') ################################# # TEST MODEL ################################# a = get_children(lambda x: hasattr(x, 'name') and x.name == "rec", my_model) assert len(a) == 1 assert a[0].name == "rec" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "C2" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p1", my_model) assert len(a) == 1 assert a[0].name == "p1" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part1" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p2a", my_model) assert len(a) == 1 assert a[0].name == "p2a" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part2" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p2b", my_model) assert len(a) == 1 assert a[0].name == "p2b" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part2" ########################### # MODEL WITH ERROR (no entry found) ############################ with raises(textx.exceptions.TextXSemanticError, match=r'.*Unknown object.*Part0.*'): my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class C2 { attr Part0 p1; } } ''') ########################### # MODEL WITH NO ERROR (double entries not checked) ############################ my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class Part1 { } class C2 { attr Part1 p1; } } ''')
def test_plain_name_ref_with_muli_metamodel_support(): """ Basic test for PlainName with multi metamodel support. It is also checked that the referred objects must have a unique name. """ ################################# # META MODEL DEF ################################# my_metamodel = metamodel_from_str(metamodel_str) my_metamodel.register_scope_providers( {"*.*": scoping_providers.PlainName(multi_metamodel_support=True)}) ################################# # MODEL PARSING ################################# my_model = my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class Part2 { attr C2 rec; } class C2 { attr Part1 p1; attr Part2 p2a; attr Part2 p2b; } } ''') ################################# # TEST MODEL ################################# a = get_children(lambda x: hasattr(x, 'name') and x.name == "rec", my_model) assert len(a) == 1 assert a[0].name == "rec" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "C2" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p1", my_model) assert len(a) == 1 assert a[0].name == "p1" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part1" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p2a", my_model) assert len(a) == 1 assert a[0].name == "p2a" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part2" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p2b", my_model) assert len(a) == 1 assert a[0].name == "p2b" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part2" ########################### # MODEL WITH ERROR (no entry found) ############################ with raises(textx.exceptions.TextXSemanticError, match=r'.*Unknown object.*Part0.*'): my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class C2 { attr Part0 p1; } } ''') ########################### # MODEL WITH ERROR (double entries) ############################ with raises(textx.exceptions.TextXSemanticError, match=r'.*None:10:\d+: error: name Part1 is not unique.*'): my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class Part1 { } class C2 { attr Part1 p1; } } ''')
def test_fully_qualified_name_ref(): """ This is a basic test for the FQN (positive and negative test). """ ################################# # META MODEL DEF ################################# my_metamodel = metamodel_from_str(metamodel_str) my_metamodel.register_scope_providers({"*.*": scoping_providers.FQN()}) ################################# # MODEL PARSING ################################# my_model = my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class Part2 { attr C2 rec; } class C2 { attr P1.Part1 p1; attr Part2 p2a; attr P2.Part2 p2b; } } ''') ################################# # TEST MODEL ################################# a = get_children(lambda x: hasattr(x, 'name') and x.name == "rec", my_model) assert len(a) == 1 assert a[0].name == "rec" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "C2" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p1", my_model) assert len(a) == 1 assert a[0].name == "p1" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part1" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p2a", my_model) assert len(a) == 1 assert a[0].name == "p2a" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part2" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p2b", my_model) assert len(a) == 1 assert a[0].name == "p2b" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part2" ########################### # MODEL WITH ERROR ############################ with raises(textx.exceptions.TextXSemanticError, match=r'None:8:.*: Unknown object.*Part1.*'): my_metamodel.model_from_str(''' #1 package P1 { #2 class Part1 { #3 } #4 } #5 package P2 { #6 class C2 { #7 attr Part1 p1; #8 } } ''') with raises(textx.exceptions.TextXSemanticError, match=r'.*test_fully_qualified_name_test_error.model:8:\d+:' ' Unknown object.*Part1.*'): my_metamodel.model_from_file( join(dirname(__file__), "misc", "test_fully_qualified_name_test_error.model"))
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 test_fully_qualified_name_ref(): ################################# # META MODEL DEF ################################# my_metamodel = metamodel_from_str(metamodel_str) my_metamodel.register_scope_providers({"*.*": scoping_providers.FQN()}) ################################# # MODEL PARSING ################################# my_model = my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class Part2 { attr C2 rec; } class C2 { attr P1.Part1 p1; attr Part2 p2a; attr P2.Part2 p2b; } } ''') ################################# # TEST MODEL ################################# a = get_children(lambda x: hasattr(x, 'name') and x.name == "rec", my_model) assert len(a) == 1 assert a[0].name == "rec" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "C2" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p1", my_model) assert len(a) == 1 assert a[0].name == "p1" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part1" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p2a", my_model) assert len(a) == 1 assert a[0].name == "p2a" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part2" a = get_children(lambda x: hasattr(x, 'name') and x.name == "p2b", my_model) assert len(a) == 1 assert a[0].name == "p2b" assert a[0].ref.__class__.__name__ == "Class" assert a[0].ref.name == "Part2" ########################### # MODEL WITH ERROR ############################ with raises(textx.exceptions.TextXSemanticError, match=r'.*Unknown object.*Part1.*'): my_model2 = my_metamodel.model_from_str(''' package P1 { class Part1 { } } package P2 { class C2 { attr Part1 p1; } } ''')
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