Skip to content

Commit

Permalink
topotato: add TopotatoItem.cls_node
Browse files Browse the repository at this point in the history
Replace a bunch of `.getparent(TopotatoClass)` calls, each of those
needs an assert for mypy to be happy...

Signed-off-by: David Lamparter <[email protected]>
  • Loading branch information
eqvinox committed Sep 16, 2024
1 parent 53e8c40 commit 7c27fe9
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 43 deletions.
66 changes: 28 additions & 38 deletions topotato/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,6 @@ class TopotatoItem(nodes.Item):
to pytest to do its thing.
"""

parent: "TopotatoClass"
"""
Part of pytest, but in general nodes may have `None` as a parent. This
causes false errors in mypy, so this is here to state that `parent` is
never `None` (and always a `TopotatoClass`)
"""

_codeloc: Optional[inspect.FrameInfo]
"""
Test source code location that resulted in the creation of this item.
Expand All @@ -208,6 +201,10 @@ class TopotatoItem(nodes.Item):
instance of WhateverTestClass defined in test_something.py
"""

cls_node: "TopotatoClass"
"""
The pytest node created for the :py:class:`TestBase` subclass.
"""
instance: "TopotatoNetwork"
"""
Running network instance this item belongs to.
Expand Down Expand Up @@ -236,9 +233,10 @@ def __init__(self, *, name: str, parent: nodes.Node, codeloc=None, **kw):
self.skipchecks = []
self._codeloc = codeloc

tparent = self.getparent(TopotatoClass)
assert tparent is not None
self._obj = tparent.obj
self.cls_node = cast(TopotatoClass, self.getparent(TopotatoClass))
if self.cls_node is None:
raise RuntimeError("TopotatoItem without parent TopotatoClass?!")
self._obj = self.cls_node.obj

@classmethod
def from_parent(
Expand Down Expand Up @@ -336,8 +334,8 @@ def setup(self):
# pylint: disable=attribute-defined-outside-init
fn.started_ts = time.time()

with _SkipMgr(self) as tcls:
self.instance = tcls.netinst
with _SkipMgr(self):
self.instance = self.cls_node.netinst
self.timeline = self.instance.timeline

# pylint: disable=unused-argument
Expand Down Expand Up @@ -367,9 +365,7 @@ def sleep(self, step=None, until=None):
abs_delay = time.time() + (step or float("inf"))
deadline = min(abs_until, abs_delay)

tinst = self.getparent(TopotatoClass)
assert tinst is not None
tinst.netinst.timeline.sleep(deadline - time.time())
self.timeline.sleep(deadline - time.time())

def reportinfo(self): # -> Tuple[Union[py.path.local, str], int, str]:
"""
Expand Down Expand Up @@ -488,21 +484,17 @@ class _SkipMgr:
"""

_item: TopotatoItem
_cls: "TopotatoClass"

def __init__(self, item: TopotatoItem):
tcls = item.getparent(TopotatoClass)
assert tcls is not None

self._item = item
self._cls = tcls

def __enter__(self) -> "TopotatoClass":
def __enter__(self) -> None:
if self._item.cascade_failures == SkipMode.DontSkip:
return self._cls
if self._cls.skipall:
raise TopotatoEarlierFailSkip(self._cls.skipall_node) from self._cls.skipall
return self._cls
return
if self._item.cls_node.skipall:
raise TopotatoEarlierFailSkip(
self._item.cls_node.skipall_node
) from self._item.cls_node.skipall

def __exit__(
self,
Expand All @@ -518,8 +510,8 @@ def __exit__(
return

if self._item.cascade_failures == SkipMode.SkipThisAndLater:
self._cls.skipall_node = self._item
self._cls.skipall = exc_value
self._item.cls_node.skipall_node = self._item
self._item.cls_node.skipall = exc_value


# false warning on get_closest_marker()
Expand All @@ -539,24 +531,24 @@ def __init__(self, **kwargs):
super().__init__(name="startup", **kwargs)

def reportinfo(self):
tcls = self.getparent(TopotatoClass)
assert tcls is not None
fspath, _, _ = tcls.reportinfo()
fspath, _, _ = self.cls_node.reportinfo()
return fspath, float("-inf"), "startup"

def setup(self):
# this needs to happen before TopotatoItem.setup, since that accesses
# tcls.netinst
with _SkipMgr(self) as tcls:
# cls_node.netinst
with _SkipMgr(self):
# pylint: disable=protected-access
tcls.netinst = tcls.obj._setup(self.session, tcls.nodeid).prepare()
self.cls_node.netinst = self.cls_node.obj._setup(
self.session, self.cls_node.nodeid
).prepare()
super().setup()

@endtrace
@skiptrace
def runtest(self):
with _SkipMgr(self):
self.parent.do_start()
self.cls_node.do_start()


# false warning on get_closest_marker()
Expand All @@ -576,13 +568,11 @@ def __init__(self, **kwargs):
super().__init__(name="shutdown", **kwargs)

def reportinfo(self):
tcls = self.getparent(TopotatoClass)
assert tcls is not None
fspath, _, _ = tcls.reportinfo()
fspath, _, _ = self.cls_node.reportinfo()
return fspath, float("inf"), "shutdown"

def __call__(self):
self.parent.do_stop(self)
self.cls_node.do_stop(self)


class TestBase:
Expand Down
2 changes: 1 addition & 1 deletion topotato/interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def pytest_collection(session: pytest.Session):
session.items = []
for item in allitems:
if isinstance(item, TopotatoItem) and item.name == "startup":
sys.stdout.write(f" {item.parent.nodeid}\n")
sys.stdout.write(f" {item.cls_node.nodeid}\n")
session.items.append(item)

sys.stdout.write("\n")
Expand Down
2 changes: 1 addition & 1 deletion topotato/pretty.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ class PrettyStartup(PrettyTopotato, matches=base.InstanceStartup):
def when_call(self, call, result):
super().when_call(call, result)

self.instance.ts_rel = self.item.parent.starting_ts
self.instance.ts_rel = self.item.cls_node.starting_ts

def files(self):
dot = self.instance.network.dot()
Expand Down
6 changes: 3 additions & 3 deletions topotato/pytestintegration.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def topologies():

# TODO: refactor for FRRNetworkInstance removal / FRRConfigs rework
for item in topologies():
name = item.parent.nodeid
name = item.cls_node.nodeid

cfgsetup = item._obj.instancefn.configs
cfgs = cfgsetup.cfgclass(cfgsetup.net, session.frr)
Expand All @@ -165,7 +165,7 @@ def topologies():

# TODO: refactor for FRRNetworkInstance removal / FRRConfigs rework
for item in topologies():
name = item.parent.nodeid
name = item.cls_node.nodeid
if path[0] != name:
continue

Expand Down Expand Up @@ -193,7 +193,7 @@ def topologies():
which = session.config.getoption("--show-topology")

for item in topologies():
name = item.parent.nodeid
name = item.cls_node.nodeid
if name != which:
continue

Expand Down

0 comments on commit 7c27fe9

Please sign in to comment.