Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions camera/blur_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def _run_and_verify(opts):
b_t = iron.zeros(16 * 16, dtype=np.int32, device="npu")
out_t = iron.zeros(tensor_size, dtype=np.int8, device="npu")

edge_detect(in_t, b_t, out_t, **_compile_kwargs(opts))
blur(in_t, b_t, out_t, **_compile_kwargs(opts))

in_uint8 = in_np.view(np.uint8)
expected_uint8 = _edge_detect_ref(in_uint8, opts.height, opts.width)
Expand All @@ -339,7 +339,7 @@ def _run_and_verify(opts):
def main():
opts = _make_argparser().parse_args()
run_design_cli(
edge_detect,
blur,
opts,
compile_kwargs=_compile_kwargs,
run_and_verify=_run_and_verify,
Expand Down
68 changes: 68 additions & 0 deletions camera/test_blur_pipeline_cli_symbol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Regression guard for the blur_pipeline CLI / self-verify design symbol.
#
# blur_pipeline.py was adapted from AMD's `edge_detect` IRON example. The design
# it actually defines is `blur` (see `def blur(...)` and
# `from blur_pipeline import blur` in npu_camera_daemon.py / test_blur.py), but
# `_run_and_verify()` and `main()` still called the old name `edge_detect`,
# which is never defined or imported in this module. Because the module imports
# `aie.iron` at the top, a host without the NPU toolchain fails at that import
# first (so CI's import-boundary check stays green) -- but on a real NPU box
# `python blur_pipeline.py` reaches main() and dies with
# `NameError: name 'edge_detect' is not defined` instead of running the design.
#
# This test is pure-AST (no aie/NPU toolchain, no numpy) so it runs anywhere,
# and it asserts the design symbol the CLI hands to the NPU is one the module
# actually defines.
import ast
import builtins
import os

HERE = os.path.dirname(os.path.abspath(__file__))
SRC = os.path.join(HERE, "blur_pipeline.py")


def _module_bound_names(tree):
names = set()
for node in tree.body:
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
names.add(node.name)
elif isinstance(node, (ast.Import, ast.ImportFrom)):
for alias in node.names:
names.add(alias.asname or alias.name.split(".")[0])
elif isinstance(node, ast.Assign):
for tgt in node.targets:
if isinstance(tgt, ast.Name):
names.add(tgt.id)
return names


def _cli_referenced_names(tree):
"""Bare names called (or handed to run_design_cli) inside the CLI paths."""
refs = set()
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef) and node.name in ("_run_and_verify", "main"):
for sub in ast.walk(node):
if isinstance(sub, ast.Call) and isinstance(sub.func, ast.Name):
refs.add(sub.func.id)
# run_design_cli(<design>, ...) -> first positional arg is the design fn
if sub.func.id == "run_design_cli" and sub.args and isinstance(sub.args[0], ast.Name):
refs.add(sub.args[0].id)
return refs


def test_cli_design_symbol_is_defined():
tree = ast.parse(open(SRC, encoding="utf-8").read())
bound = _module_bound_names(tree)
assert "blur" in bound, "expected the design function `blur` to be defined"
refs = _cli_referenced_names(tree)
assert "edge_detect" not in refs, (
"blur_pipeline.py references undefined `edge_detect` (leftover from the "
"AMD edge_detect example) in its CLI/self-verify path; it should call `blur`"
)
undefined = {r for r in refs if r not in bound and not hasattr(builtins, r)}
assert not undefined, f"CLI/self-verify references undefined names: {sorted(undefined)}"


if __name__ == "__main__":
test_cli_design_symbol_is_defined()
print("OK: blur_pipeline CLI design symbol is defined")