Skip to content

Commit

Permalink
Add pycodestyle and pydocstyle linting and needed changes
Browse files Browse the repository at this point in the history
  • Loading branch information
laracroft37 committed Sep 10, 2024
1 parent 6b263ea commit 34f89a0
Show file tree
Hide file tree
Showing 31 changed files with 247 additions and 188 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install mypy types-setuptools black
pip install mypy types-setuptools black pycodestyle pydocstyle
- name: Run linters
run: |
mypy avocado_i2n
black --check --diff --color avocado_i2n
# only excluded checks are conflicts with black and within pycodestyle
# (in addition E402 is not something we intend to follow)
pycodestyle --ignore=E203,E402,E501,W503 avocado_i2n
pydocstyle avocado_i2n
1 change: 1 addition & 0 deletions avocado_i2n/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Package with the complete Avocado I2N modules and functionality."""
2 changes: 2 additions & 0 deletions avocado_i2n/cartgraph/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Package for the complete Cartesian graph structure."""

from .object import TestObject, NetObject, VMObject, ImageObject
from .worker import TestEnvironment, TestSwarm, TestWorker
from .node import PrefixTreeNode, PrefixTree, EdgeRegister, TestNode
Expand Down
29 changes: 17 additions & 12 deletions avocado_i2n/cartgraph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@
# along with avocado-i2n. If not, see <http://www.gnu.org/licenses/>.

"""
Main test suite data structure.
SUMMARY
------------------------------------------------------
Main test suite data structure containing tests as nodes in a bidirected graph
with edges to their dependencies (parents) and dependables (children) but also
with a separate edge for each stateful object.
Copyright: Intra2net AG
Data structure containing tests as nodes in a bidirected graph with edges to their
dependencies (parents) and dependables (children) but also with a separate edge
for each stateful object.
Copyright: Intra2net AG
INTERFACE
------------------------------------------------------
Expand Down Expand Up @@ -105,6 +106,7 @@ def __init__(self) -> None:
self.runner = None

def __repr__(self) -> str:
"""Provide a representation of the object."""
dump = "[cartgraph] objects='%s' nodes='%s'" % (
len(self.objects),
len(self.nodes),
Expand Down Expand Up @@ -188,8 +190,9 @@ def save_setup_list(self, dump_dir: str, filename: str = "setup_list") -> None:

def report_progress(self) -> None:
"""
Report the total test run progress as the number and percentage
of tests that are fully finished (will not be run again).
Report the total test run progress.
The number and percentage of tests that are fully finished will not be run again.
The estimation includes setup tests which might be reused and therefore
provides worst case scenario for the number of remaining tests. It also
Expand All @@ -211,8 +214,7 @@ def report_progress(self) -> None:

def visualize(self, dump_dir: str, tag: str = "0") -> None:
"""
Dump a visual description of the Cartesian graph at
a given parsing/traversal step.
Dump a visual description of the Cartesian graph at a given parsing/traversal step.
:param dump_dir: directory for the dump image
:param tag: tag of the dump, e.g. parsing/traversal step and slot
Expand Down Expand Up @@ -1280,8 +1282,10 @@ def parse_composite_nodes(
unique: bool = False,
) -> list[TestNode] | TestNode:
"""
Parse all user defined tests (leaf nodes) using the nodes restriction string
and possibly restricting to a single test object for the singleton tests.
Parse all user defined tests (leaf nodes).
Use the nodes restriction string and possibly restricting to a single test object
for the singleton tests.
:param restriction: single or multi-line restriction to use
:param test_object: possibly flat test object to compose the node on top of, typically a test net
Expand Down Expand Up @@ -2045,8 +2049,9 @@ async def traverse_object_trees(
self, worker: TestWorker, params: Params = None
) -> None:
"""
Run all user and system defined tests optimizing the setup reuse and
minimizing the repetition of demanded tests.
Run all user and system defined tests.
Optimize the setup reuse and minimize the repetition of demanded tests.
:param worker: worker traversing the graph
:param params: runtime parameters used for extra customization
Expand Down
45 changes: 32 additions & 13 deletions avocado_i2n/cartgraph/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@
# along with avocado-i2n. If not, see <http://www.gnu.org/licenses/>.

"""
Utility for the main test suite substructures like test nodes.
SUMMARY
------------------------------------------------------
Utility for the main test suite substructures like test nodes.
Copyright: Intra2net AG
INTERFACE
------------------------------------------------------
Expand All @@ -48,35 +47,47 @@


class PrefixTreeNode(object):
"""A node of a prefix tree."""

def __init__(self, variant: str = None, parent: str = None) -> None:
"""Construct a PrefixTree Node(test) for any test objects (vms)."""
self.variant = variant
self.parent = parent
self.end_test_node = None
self.children = {}

def check_child(self, variant: str) -> bool:
"""Check child prefix tree node."""
return variant in self.children

def get_child(self, variant: str) -> str:
"""Get child prefix tree node."""
return self.children[variant]

def set_child(self, variant: str, child: str) -> None:
"""Set child prefix tree node."""
self.children[variant] = child

def unset_child(self, variant: str) -> None:
"""Unset child prefix tree node."""
del self.children[variant]

def traverse(self) -> Generator[None, None, None]:
"""Traverse the current node."""
yield self
for child in self.children.values():
yield from child.traverse()


class PrefixTree(object):
"""A node of a prefix tree."""

def __init__(self) -> None:
"""Construct a Prefix Tree (test) for any test objects (vms)."""
self.variant_nodes = {}

def __contains__(self, name: str) -> bool:
"""Check whether the prefix tree contains a given name."""
variants = name.split(".")
if variants[0] not in self.variant_nodes:
return False
Expand All @@ -90,6 +101,7 @@ def __contains__(self, name: str) -> bool:
return False

def insert(self, test_node: "TestNode") -> None:
"""Trie structure used for faster prefix lookup."""
variants = test_node.params["name"].split(".")
if variants[0] not in self.variant_nodes.keys():
self.variant_nodes[variants[0]] = [PrefixTreeNode(variants[0])]
Expand All @@ -105,6 +117,7 @@ def insert(self, test_node: "TestNode") -> None:
current.end_test_node = test_node

def get(self, name: str) -> list["TestNode"]:
"""Get all the names of the prefix tree."""
variants = name.split(".")
if variants[0] not in self.variant_nodes:
return []
Expand All @@ -122,11 +135,14 @@ def get(self, name: str) -> list["TestNode"]:


class EdgeRegister:
"""A register for the Cartesian graph edges allowing counter and worker stats extraction."""

def __init__(self) -> None:
"""Construct an EdgeRegister (test) for any test objects (vms)."""
self._registry = {}

def __repr__(self) -> str:
"""Provide a representation of the object."""
return f"[edge] registry='{self._registry}'"

def get_workers(self, node: "TestNode" = None) -> set[str]:
Expand Down Expand Up @@ -176,11 +192,15 @@ def register(self, node: "TestNode", worker: TestWorker) -> None:

class TestNode(Runnable):
"""
A wrapper for all test relevant parts like parameters, parser, used
objects and dependencies to/from other test nodes (setup/cleanup).
A wrapper for all test relevant parts.
Such test relevant unclude like parameters, parser, used objects and
dependencies to/from other test nodes (setup/cleanup).
"""

class ReadOnlyDict(dict[str, str]):
"""Custom implementation of a read-only attribute of dictionary type."""

def _readonly(self, *args: tuple[type, ...], **kwargs: dict[str, type]) -> None:
raise RuntimeError("Cannot modify read-only dictionary")

Expand Down Expand Up @@ -343,12 +363,12 @@ def long_prefix(self) -> Params:

@property.get
def id(self) -> Params:
"""Unique ID to identify a test node."""
"""Use unique ID to identify a test node."""
return self.prefix + "-" + self.params["name"]

@property.get
def id_test(self) -> Params:
"""Unique test ID to identify a test node."""
"""Use a unique test ID to identify a test node."""
return TestID(self.prefix, self.params["name"])

def __init__(self, prefix: str, recipe: param.Reparsable) -> None:
Expand Down Expand Up @@ -386,6 +406,7 @@ def __init__(self, prefix: str, recipe: param.Reparsable) -> None:
self._dropped_cleanup_nodes = EdgeRegister()

def __repr__(self) -> str:
"""Provide a representation of the object."""
shortname = self.params.get("shortname", "<unknown>")
return f"[node] longprefix='{self.long_prefix}', shortname='{shortname}'"

Expand Down Expand Up @@ -495,7 +516,7 @@ def is_cleanup_ready(self, worker: TestWorker) -> bool:

def is_started(self, worker: TestWorker = None, threshold: int = 1) -> bool:
"""
The test is currently traversed by at least N (-1 for all) workers of all or some scopes.
Test is currently traversed by at least N (-1 for all) workers of all or some scopes.
:param worker: evaluate with respect to an optional worker ID scope or globally if none given
:param threshold: how eagerly the node is considered started in terms of number of
Expand Down Expand Up @@ -537,7 +558,7 @@ def is_started(self, worker: TestWorker = None, threshold: int = 1) -> bool:

def is_finished(self, worker: TestWorker = None, threshold: int = 1) -> bool:
"""
The test was ever traversed by at least N (-1 for all) workers of all or some scopes.
Test was ever traversed by at least N (-1 for all) workers of all or some scopes.
:param worker: evaluate with respect to an optional worker ID scope or globally if none given
:param threshold: how eagerly the node is considered started in terms of number of
Expand Down Expand Up @@ -770,7 +791,7 @@ def should_rerun(self, worker: TestWorker = None) -> bool:

def default_run_decision(self, worker: TestWorker) -> bool:
"""
Default decision policy on whether a test node should be run or skipped.
Set default decision policy on whether a test node should be run or skipped.
:param worker: worker which makes the run decision
:returns: whether the worker should run the test node
Expand Down Expand Up @@ -805,7 +826,7 @@ def default_run_decision(self, worker: TestWorker) -> bool:

def default_clean_decision(self, worker: TestWorker) -> bool:
"""
Default decision policy on whether a test node should be cleaned or skipped.
Set default decision policy on whether a test node should be cleaned or skipped.
:param worker: worker which makes the clean decision
:returns: whether the worker should clean the test node
Expand Down Expand Up @@ -1164,9 +1185,7 @@ def regenerate_params(self, verbose: bool = False) -> None:
self.regenerate_vt_parameters()

def regenerate_vt_parameters(self) -> None:
"""
Regenerate the parameters provided to the VT runner.
"""
"""Regenerate the parameters provided to the VT runner."""
uri = self.params.get("name")
vt_params = self.params.copy()
# Flatten the vt_params, discarding the attributes that are not
Expand Down
14 changes: 9 additions & 5 deletions avocado_i2n/cartgraph/object.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@
# along with avocado-i2n. If not, see <http://www.gnu.org/licenses/>.

"""
Utility for the main test suite substructures like test objects.
SUMMARY
------------------------------------------------------
Utility for the main test suite substructures like test objects.
Copyright: Intra2net AG
INTERFACE
------------------------------------------------------
Expand All @@ -46,6 +45,7 @@ def params(self) -> Params:

@property.get
def component_form(self) -> Params:
"""Component form of the test object name."""
return self.params["name"].replace(self.key + ".", "")

@property.get
Expand All @@ -55,7 +55,7 @@ def long_suffix(self) -> str:

@property.get
def id(self) -> str:
"""Unique ID to identify a test object."""
"""Use unique ID to identify a test object."""
return self.long_suffix + "-" + self.params["name"]

def __init__(self, suffix: str, recipe: param.Reparsable) -> None:
Expand All @@ -82,6 +82,7 @@ def __init__(self, suffix: str, recipe: param.Reparsable) -> None:
self.key = "objects"

def __repr__(self) -> str:
"""Provide a representation of the object."""
shortname = self.params.get("shortname", "<unknown>")
return f"[object] longsuffix='{self.long_suffix}', shortname='{shortname}'"

Expand All @@ -91,8 +92,9 @@ def is_flat(self) -> bool:

def is_permanent(self) -> bool:
"""
If the test object is permanent, it can only be created manually
(possibly through the use of manual setup steps).
If the test object is permanent, it can only be created manually.
Thus possibly through the use of manual setup steps.
On states on permanent test object are treated differently than
on states on normal test object since they are preserved through
Expand Down Expand Up @@ -147,6 +149,7 @@ class NetObject(TestObject):
"""A Net wrapper for a test object used in one or more test nodes."""

def component_form(self) -> str:
"""Component form of the test object name."""
# TODO: an unexpected order of joining in the Cartesian config requires us to override base property
return self.params["name"]

Expand Down Expand Up @@ -188,6 +191,7 @@ def id(self) -> str:
id = property(fget=id)

def component_form(self) -> str:
"""Component form of the test object name."""
return self.composites[0].component_form

component_form = property(fget=component_form)
Expand Down
6 changes: 4 additions & 2 deletions avocado_i2n/cartgraph/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@
# along with avocado-i2n. If not, see <http://www.gnu.org/licenses/>.

"""
Utility for the main test suite substructures like test objects.
SUMMARY
------------------------------------------------------
Utility for the main test suite substructures like test objects.
Copyright: Intra2net AG
INTERFACE
------------------------------------------------------
Expand All @@ -41,6 +40,7 @@


class TestEnvironment(object):
"""Generic environment isolating a given test."""

def __init__(self, id: str) -> None:
"""
Expand All @@ -66,6 +66,7 @@ def __init__(self, id: str, workers: str = None) -> None:
self.workers = workers or []

def __repr__(self) -> str:
"""Provide a representation of the object."""
dump = f"[swarm] id='{self.id}', workers='{len(self.workers)}'"
for worker in self.workers:
dump = f"{dump}\n\t{worker}"
Expand Down Expand Up @@ -101,6 +102,7 @@ def __init__(self, id_net: NetObject) -> None:
self.spawner = None

def __repr__(self) -> str:
"""Provide a representation of the object."""
return f"[worker] id='{self.id}', spawner='{self.params['nets_spawner']}'"

def overwrite_with_slot(self, slot: str) -> None:
Expand Down
Loading

0 comments on commit 34f89a0

Please sign in to comment.