Skip to content

Feat/add registry import failure test#1142

Merged
muddlebee merged 9 commits intoTracer-Cloud:mainfrom
Aaryan-549:feat/add-registry-import-failure-test
Apr 30, 2026
Merged

Feat/add registry import failure test#1142
muddlebee merged 9 commits intoTracer-Cloud:mainfrom
Aaryan-549:feat/add-registry-import-failure-test

Conversation

@Aaryan-549
Copy link
Copy Markdown
Contributor

Fixes #1115

Describe the changes you have made in this PR -

Added regression test to verify the tool registry properly handles modules that fail to import. The test checks that when a module raises
an exception during import, the registry skips it gracefully and continues loading valid tools from other modules.

The test creates a mock scenario with a broken module and a valid module, then verifies:

  • Valid tools still get registered despite the broken module
  • Import failures are logged as warnings
  • The tool map remains functional and can access valid tools

Demo/Screenshot for feature changes and bug fixes -

Test passes with current code:
tests/tools/test_registry.py::test_registry_regression_import_failures PASSED

Test catches the regression when continue statement is removed from exception handler:
UnboundLocalError: cannot access local variable 'module' where it is not associated with a value

This proves the test correctly detects when import error handling is broken.


Code Understanding and AI Usage

Did you use AI assistance (ChatGPT, Claude, Copilot, etc.) to write any part of this code?

  • Yes, I used AI assistance (continue below)

If you used AI assistance:

  • I have reviewed every single line of the AI-generated code
  • I can explain the purpose and logic of each function/component I added
  • I have tested edge cases and understand how the code handles them
  • I have modified the AI output to follow this project's coding standards and conventions

Explain your implementation approach:

The test mirrors the pattern from the duplicate tool names regression test. It uses monkeypatch to mock the module import process, creates
a scenario where one module fails with RuntimeError while another succeeds, then verifies the registry recovers gracefully.

Key parts:

  • mock_import() function simulates import failures for "broken_module"
  • Valid tool is still created and registered in a separate module
  • Test asserts that valid tools are found despite the failure
  • caplog captures and verifies the warning is logged

The implementation catches a real bug: if the continue statement after exception handling is removed, the code tries to use an
uninitialized module variable, causing UnboundLocalError.


Checklist before requesting a review

  • I have added proper PR title and linked to the issue
  • I have performed a self-review of my code
  • I can explain the purpose of every function, class, and logic block I added
  • I understand why my changes work and have tested them thoroughly
  • I have considered potential edge cases and how my code handles them
  • If it is a core feature, I have added thorough tests
  • My code follows the project's style guidelines and conventions

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 30, 2026

Greptile Summary

This PR adds two regression tests to tests/tools/test_registry.py: one verifying the registry gracefully skips modules that raise an exception during import, and one verifying duplicate tool names across modules are deduplicated (keeping the first registration). Both tests correctly monkeypatch _iter_tool_module_names and _import_tool_module, rely on the autouse cache-reset fixture, and exercise real code paths in registry.py.

Confidence Score: 5/5

Safe to merge — only test code is added, no production logic is changed, and all findings are minor P2 style points.

Both new tests are structurally sound and follow established patterns in the file. The only actionable items are P2 style suggestions (stale # pragma: no cover in the production file and a redundant length assertion), neither of which blocks correctness or CI.

No files require special attention; consider a follow-up to remove # pragma: no cover from the except Exception block in app/tools/registry.py.

Important Files Changed

Filename Overview
tests/tools/test_registry.py Adds two regression tests: one for graceful skipping of import-failing modules and one for duplicate tool names across modules. Both correctly use monkeypatch + autouse cache-reset fixture. Two minor P2 style points: the except Exception pragma in registry.py is now stale, and assert len(tools) >= 1 is redundant.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[_load_registry_snapshot] --> B[iter module names]
    B --> C{_import_tool_module}
    C -->|ModuleNotFoundError| D[log warning & continue]
    C -->|RuntimeError / Exception| E[log warning & continue\n← NEW TEST covers this path]
    C -->|success| F[_collect_registered_tools_from_module]
    F --> G{duplicate tool name\nacross modules?}
    G -->|yes| H[log warning & skip\n← NEW TEST covers this path]
    G -->|no| I[add to tools_by_name]
    D --> B
    E --> B
    H --> B
    I --> B
    B -->|done| J[return sorted tuple]
Loading

Reviews (1): Last reviewed commit: "Add registry regression test for import ..." | Re-trigger Greptile

Comment on lines +352 to +398
)


def test_registry_regression_import_failures(
monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture
) -> None:
"""Test that registry gracefully skips modules with import failures."""
module: Any = ModuleType("app.tools.valid_tool")

@tool(
name="valid_tool",
description="A valid tool.",
source="knowledge",
)
def valid_tool() -> dict[str, str]:
return {"status": "ok"}

valid_tool.__module__ = module.__name__
module.valid_tool = valid_tool

def mock_import(name: str) -> ModuleType:
if name == "broken_module":
raise RuntimeError("Module initialization failed")
return module

monkeypatch.setattr(
registry_module,
"_iter_tool_module_names",
lambda: ["broken_module", "valid_tool"],
)
monkeypatch.setattr(
registry_module,
"_import_tool_module",
mock_import,
)

with caplog.at_level(logging.WARNING, logger="app.tools.registry"):
tools = registry_module.get_registered_tools()

tool_names = [t.name for t in tools]

assert "valid_tool" in tool_names
assert len(tools) >= 1
assert registry_module.get_registered_tool_map()["valid_tool"].run() == {
"status": "ok"
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 # pragma: no cover now stale in production code

The RuntimeError raised by mock_import is caught by the general except Exception as exc block in registry.py (line 131), which carries the comment # pragma: no cover - defensive logging path. That annotation was added precisely because no test exercised this path — but this test now does. The pragma will continue to tell the coverage tool to ignore the branch, so coverage reports will still show it as uncovered even though it is exercised. Consider removing # pragma: no cover from registry.py's except Exception handler alongside this PR (or in a follow-up), otherwise the coverage signal remains misleading.

Comment on lines +388 to +389
with caplog.at_level(logging.WARNING, logger="app.tools.registry"):
tools = registry_module.get_registered_tools()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Redundant len assertion

assert len(tools) >= 1 is fully implied by the assert "valid_tool" in tool_names assertion directly above it. Removing this line tightens the test and avoids the impression that an empty list with a false-positive in check could ever pass.

Suggested change
with caplog.at_level(logging.WARNING, logger="app.tools.registry"):
tools = registry_module.get_registered_tools()
assert "valid_tool" in tool_names
assert registry_module.get_registered_tool_map()["valid_tool"].run() == {

@Aaryan-549 Aaryan-549 force-pushed the feat/add-registry-import-failure-test branch from c98329d to 491f285 Compare April 30, 2026 12:38
Comment thread tests/tools/test_registry.py Fixed
@muddlebee
Copy link
Copy Markdown
Collaborator

@Aaryan-549 pls fix the CI and review points :)

@Aaryan-549
Copy link
Copy Markdown
Contributor Author

@muddlebee Yes yes forgot to put a text here that I am still working on it. My bad.

@Aaryan-549
Copy link
Copy Markdown
Contributor Author

Hey @muddlebee Have a look now!

@muddlebee muddlebee merged commit 039d1a5 into Tracer-Cloud:main Apr 30, 2026
10 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🌮 @Aaryan-549's PR: showed up unannounced, improved everything, left zero bugs. Just like a perfect taco. 🌮


👋 Join us on Discord - OpenSRE : hang out, contribute, or hunt for features and issues. Everyone's welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add registry regression test for import failures

3 participants