Skip to content

Commit

Permalink
Issue/747 entity origin (#752)
Browse files Browse the repository at this point in the history
* Track all locations where an instance has been created. (fixes #747)
  • Loading branch information
wouterdb authored and bartv committed Oct 16, 2018
1 parent fc4d0a6 commit 559fc82
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ docs/moduleguides
.mypy
.mypy_cache
mypy
types
types
2 changes: 1 addition & 1 deletion src/inmanta/ast/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ def get_instance(self,
Return an instance of the class defined in this entity
"""
out = Instance(self, resolver, queue)
out.location = location
out.set_location(location)
for k, v in attributes.items():
out.set_attribute(k, v, location)

Expand Down
2 changes: 1 addition & 1 deletion src/inmanta/ast/statements/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def copy_location(self, statement: Locatable) -> None:
"""
Copy the location of this statement in the given statement
"""
statement.location = self.location
statement.set_location(self.location)

def get_namespace(self) -> "Namespace":
return self.namespace
Expand Down
3 changes: 1 addition & 2 deletions src/inmanta/ast/statements/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,12 @@ def execute(self, requires: Dict[object, ResultVariable], resolver: Resolver, qu
raise Exception("Inconsistent indexes detected!")

object_instance = first
self.copy_location(object_instance)
for k, v in attributes.items():
object_instance.set_attribute(k, v, self.location)

else:
# create the instance
object_instance = type_class.get_instance(attributes, resolver, queue, self.location)
self.copy_location(object_instance)

# deferred execution for indirect attributes
for attributename, valueexpression in self._indirect_attributes.items():
Expand Down
13 changes: 11 additions & 2 deletions src/inmanta/execute/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from inmanta.ast import RuntimeException, NotFoundException, DoubleSetException, OptionalValueException, AttributeException, \
Locatable, Location
from inmanta.ast.type import Type
from typing import Dict, Any
from typing import List, Dict, Any


class ResultCollector(object):
Expand Down Expand Up @@ -636,6 +636,8 @@ def __init__(self, mytype, resolver, queue):
# see inmanta.ast.execute.scheduler.QueueScheduler
self.trackers = []

self.locations = []

def get_type(self):
return self.type

Expand All @@ -657,7 +659,7 @@ def __repr__(self):
return "%s %02x" % (self.type, self.sid)

def __str__(self):
return "%s (instantiated at %s)" % (self.type, self.location)
return "%s (instantiated at %s)" % (self.type, ",".join([str(l) for l in self.get_locations()]))

def add_implementation(self, impl):
if impl in self.implemenations:
Expand Down Expand Up @@ -709,5 +711,12 @@ def verify_done(self):
return False
return True

def set_location(self, location: Location):
Locatable.set_location(self, location)
self.locations.append(location)

def get_location(self) -> Location:
return self.location

def get_locations(self) -> List[Location]:
return self.locations
24 changes: 24 additions & 0 deletions tests/test_compilation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2682,6 +2682,30 @@ def test_lazy_attibutes3(snippetcompiler):
assert "5" == root.lookup("a").get_value().lookup("value").get_value().lookup("value").get_value()


def test_747_entity_multi_location(snippetcompiler):
snippetcompiler.setup_for_snippet("""
entity Alpha:
string name
end
implementation none for Alpha:
end
implement Alpha using none
index Alpha(name)
a= Alpha(name="A")
b= Alpha(name="A")
c= Alpha(name="A")
""", autostd=False)
(_, scopes) = compiler.do_compile()

root = scopes.get_child("__config__")
a = root.lookup("a").get_value()
assert len(a.get_locations()) == 3
assert sorted([l.lnr for l in a.get_locations()]) == [12, 13, 14]


def test_749_is_unknown(snippetcompiler):
snippetcompiler.setup_for_snippet("""
import tests
Expand Down
60 changes: 60 additions & 0 deletions tests/test_compiler_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,3 +440,63 @@ def test_672_missing_type(snippetcompiler):
""",
"could not find type Testt in namespace __config__"
" (reported in Implementation(test) ({dir}/main.cf:5))")


def test_747_index_collisions(snippetcompiler):
snippetcompiler.setup_for_error(
"""
entity Test:
string name
string value
end
implementation none for Test:
end
implement Test using none
index Test(name)
Test(name="A", value="a")
Test(name="A", value="b")
""",
"""Could not set attribute `value` on instance `__config__::Test (instantiated at {dir}/main.cf:13,{dir}/main.cf:14)` (reported in Construct(Test) ({dir}/main.cf:14))
caused by:
value set twice:
\told value: a
\t\tset at {dir}/main.cf:13
\tnew value: b
\t\tset at {dir}/main.cf:14
(reported in Construct(Test) ({dir}/main.cf:14))""" # nopep8
)


def test_747_index_collisions_invisible(snippetcompiler):
snippetcompiler.setup_for_error(
"""
entity Test:
string name
string value
end
implementation none for Test:
end
implement Test using none
index Test(name)
for v in ["a","b"]:
Test(name="A", value=v)
end
""",
"""Could not set attribute `value` on instance `__config__::Test (instantiated at {dir}/main.cf:15,{dir}/main.cf:15)` (reported in Construct(Test) ({dir}/main.cf:15))
caused by:
value set twice:
\told value: a
\t\tset at {dir}/main.cf:15:34
\tnew value: b
\t\tset at {dir}/main.cf:15:34
(reported in Construct(Test) ({dir}/main.cf:15))""" # nopep8
)

0 comments on commit 559fc82

Please sign in to comment.