"""Tests for muse/plugins/code/_framework.py. Coverage -------- ImplicitEntryEdge - Immutable dataclass (frozen=True). - Equality comparison uses all fields. FrameworkPlugin protocol - All three built-in plugins satisfy the Protocol at runtime. - _CustomPatternPlugin satisfies the Protocol at runtime. _FastAPIPlugin.detect_entry_points - @router.get / .post / .put / .delete / .patch recognised. - @router.head / .options / .trace recognised. - Path extracted from first positional argument. - Method stored in UPPER CASE. - No-path decorator still produces an edge (path=""). - Non-HTTP attribute (@router.dependency) ignored. - Non-Python source → empty list. - Syntax error → empty list. - Symbol not in sym_tree → no edge emitted. - Class method decorated with @router.get → edge with qualified address. _FlaskPlugin.detect_entry_points - @app.route → kind "http-route", methods from kwarg. - @app.route with no methods kwarg → defaults to ["GET"]. - @app.before_request (bare) → kind "lifecycle-hook". - @app.before_request() (called) → kind "lifecycle-hook". - @app.errorhandler(404) → kind "error-handler". - Non-Flask attribute ignored. _CeleryPlugin.detect_entry_points - @shared_task (bare Name) → kind "task". - @shared_task() (called Name) → kind "task". - @app.task (bare Attribute) → kind "task". - @app.task() (called Attribute) → kind "task". - @app.periodic_task() → kind "periodic-task". - Unrelated decorator ignored. _CustomPatternPlugin.detect_entry_points - Custom decorator name → edge with provided kind. - Non-matching decorator → no edge. - Only Python rules applied. build_implicit_edge_graph - Empty manifest → empty graph. - Single file with FastAPI handler → address in graph. - Multiple files, multiple plugins → all edges collected. - Non-Python files ignored. - Syntax error in file → skipped gracefully. - auto_detect=False → empty graph. - disabled_plugins excludes matching plugin. - Custom rule via FrameworkConfig applied. load_framework_config - Missing file → FrameworkConfig defaults. - Valid TOML section → fields parsed. - Malformed TOML → defaults returned (no crash). - Missing [framework_detection] section → defaults. - disabled_plugins stored as frozenset. - custom_entry_points parsed into _CustomEntryPointRule. Integration - FastAPI handler excluded from dead-code analysis. - Celery task excluded from dead-code analysis. """ from __future__ import annotations import dataclasses import hashlib import pathlib import textwrap import pytest from muse.core.object_store import write_object from muse.core.types import Manifest, blob_id from muse.plugins.code.ast_parser import SymbolTree, parse_symbols from muse.core.paths import muse_dir from muse.plugins.code._framework import ( BUILTIN_PLUGINS, FrameworkConfig, FrameworkPlugin, ImplicitEntryEdge, _CeleryPlugin, _CustomEntryPointRule, _CustomPatternPlugin, _FastAPIPlugin, _FlaskPlugin, build_implicit_edge_graph, load_framework_config, ) # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- type _SourceMap = dict[str, str] def _write_snapshot(tmp_path: pathlib.Path, files: _SourceMap) -> Manifest: """Write source files into the object store and return a manifest.""" manifest: Manifest = {} for rel_path, source in files.items(): blob = source.encode() oid = blob_id(blob) write_object(tmp_path, oid, blob) manifest[rel_path] = oid return manifest def _sym_tree(source: str, file_path: str) -> SymbolTree: """Parse a source string into a SymbolTree.""" return parse_symbols(source.encode(), file_path) # --------------------------------------------------------------------------- # ImplicitEntryEdge # --------------------------------------------------------------------------- class TestImplicitEntryEdge: def test_is_frozen(self) -> None: edge = ImplicitEntryEdge( framework_id="fastapi", symbol_address="app/routes.py::create_item", kind="http-route", metadata={"method": "POST", "path": "/items"}, ) with pytest.raises((AttributeError, TypeError, dataclasses.FrozenInstanceError)): setattr(edge, "framework_id", "other") def test_equality_uses_all_fields(self) -> None: e1 = ImplicitEntryEdge("fastapi", "f.py::fn", "http-route", {"method": "GET"}) e2 = ImplicitEntryEdge("fastapi", "f.py::fn", "http-route", {"method": "GET"}) e3 = ImplicitEntryEdge("fastapi", "f.py::fn", "http-route", {"method": "POST"}) assert e1 == e2 assert e1 != e3 def test_default_metadata_is_empty_dict(self) -> None: edge = ImplicitEntryEdge( framework_id="celery", symbol_address="tasks.py::send_email", kind="task", ) assert edge.metadata == {} # --------------------------------------------------------------------------- # FrameworkPlugin protocol — runtime-checkable # --------------------------------------------------------------------------- class TestFrameworkPluginProtocol: def test_builtin_plugins_satisfy_protocol(self) -> None: for plugin in BUILTIN_PLUGINS: assert isinstance(plugin, FrameworkPlugin), ( f"{type(plugin).__name__} does not satisfy FrameworkPlugin protocol" ) def test_custom_pattern_plugin_satisfies_protocol(self) -> None: plugin = _CustomPatternPlugin([]) assert isinstance(plugin, FrameworkPlugin) # --------------------------------------------------------------------------- # _FastAPIPlugin # --------------------------------------------------------------------------- class TestFastAPIPlugin: plugin = _FastAPIPlugin() def _edges(self, source: str, file_path: str = "app/routes.py") -> list[ImplicitEntryEdge]: sym_tree = _sym_tree(source, file_path) return self.plugin.detect_entry_points(file_path, sym_tree, source.encode()) def test_get_route(self) -> None: src = textwrap.dedent("""\ @router.get("/items") async def list_items(): return [] """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].kind == "http-route" assert edges[0].metadata["method"] == "GET" assert edges[0].metadata["path"] == "/items" assert edges[0].framework_id == "fastapi" def test_post_route(self) -> None: src = textwrap.dedent("""\ @router.post("/items") def create_item(): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].metadata["method"] == "POST" def test_put_delete_patch_routes(self) -> None: src = textwrap.dedent("""\ @router.put("/items/{id}") def update_item(): pass @router.delete("/items/{id}") def delete_item(): pass @router.patch("/items/{id}") def patch_item(): pass """) edges = self._edges(src) methods = {e.metadata["method"] for e in edges} assert methods == {"PUT", "DELETE", "PATCH"} def test_head_options_trace(self) -> None: src = textwrap.dedent("""\ @router.head("/ping") def ping_head(): pass @router.options("/ping") def ping_options(): pass @router.trace("/ping") def ping_trace(): pass """) edges = self._edges(src) methods = {e.metadata["method"] for e in edges} assert "HEAD" in methods assert "OPTIONS" in methods assert "TRACE" in methods def test_path_extracted_from_first_arg(self) -> None: src = textwrap.dedent("""\ @api_router.get("/api/v1/users", tags=["users"]) def get_users(): pass """) edges = self._edges(src) assert edges[0].metadata["path"] == "/api/v1/users" def test_no_path_arg_gives_empty_string(self) -> None: src = textwrap.dedent("""\ @router.get() def no_path(): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].metadata["path"] == "" def test_non_http_attribute_ignored(self) -> None: src = textwrap.dedent("""\ @router.dependency def get_db(): pass """) edges = self._edges(src) assert edges == [] def test_bare_decorator_not_a_call_ignored(self) -> None: # @router.get without parens — not a Call node in AST src = textwrap.dedent("""\ @router.get def index(): pass """) edges = self._edges(src) assert edges == [] def test_syntax_error_returns_empty(self) -> None: src = "def broken(:\n pass\n" edges = self.plugin.detect_entry_points("f.py", {}, src.encode()) assert edges == [] def test_symbol_not_in_tree_returns_no_edge(self) -> None: # Provide an empty sym_tree — _resolve_address will return None. src = textwrap.dedent("""\ @router.get("/items") def list_items(): pass """) edges = self.plugin.detect_entry_points("app/routes.py", {}, src.encode()) assert edges == [] def test_multiple_routes_in_one_file(self) -> None: src = textwrap.dedent("""\ @router.get("/a") def get_a(): pass @router.post("/b") def post_b(): pass """) edges = self._edges(src) assert len(edges) == 2 def test_method_stored_uppercase(self) -> None: src = textwrap.dedent("""\ @router.get("/x") def get_x(): pass """) edges = self._edges(src) assert edges[0].metadata["method"] == "GET" def test_address_uses_file_path(self) -> None: src = textwrap.dedent("""\ @router.get("/runs") async def list_runs(): pass """) edges = self._edges(src, file_path="server/app/routers/runs.py") assert edges[0].symbol_address.startswith("server/app/routers/runs.py::") # --------------------------------------------------------------------------- # _FlaskPlugin # --------------------------------------------------------------------------- class TestFlaskPlugin: plugin = _FlaskPlugin() def _edges(self, source: str, file_path: str = "app/views.py") -> list[ImplicitEntryEdge]: sym_tree = _sym_tree(source, file_path) return self.plugin.detect_entry_points(file_path, sym_tree, source.encode()) def test_route_with_methods_kwarg(self) -> None: src = textwrap.dedent("""\ @app.route("/users", methods=["GET", "POST"]) def users(): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].kind == "http-route" assert "GET" in edges[0].metadata["method"] assert "POST" in edges[0].metadata["method"] def test_route_no_methods_defaults_to_get(self) -> None: src = textwrap.dedent("""\ @app.route("/index") def index(): pass """) edges = self._edges(src) assert len(edges) == 1 assert "GET" in edges[0].metadata["method"] def test_route_path_extracted(self) -> None: src = textwrap.dedent("""\ @bp.route("/dashboard") def dashboard(): pass """) edges = self._edges(src) assert edges[0].metadata["path"] == "/dashboard" def test_before_request_bare(self) -> None: src = textwrap.dedent("""\ @app.before_request def setup(): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].kind == "lifecycle-hook" assert edges[0].metadata.get("hook") == "before_request" def test_before_request_called(self) -> None: src = textwrap.dedent("""\ @app.before_request() def setup(): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].kind == "lifecycle-hook" def test_after_request(self) -> None: src = textwrap.dedent("""\ @app.after_request def add_headers(response): pass """) edges = self._edges(src) assert any(e.kind == "lifecycle-hook" for e in edges) def test_errorhandler(self) -> None: src = textwrap.dedent("""\ @app.errorhandler(404) def not_found(e): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].kind == "error-handler" def test_non_flask_attribute_ignored(self) -> None: src = textwrap.dedent("""\ @app.middleware def mw(): pass """) edges = self._edges(src) assert edges == [] def test_syntax_error_returns_empty(self) -> None: src = "def bad(:\n pass\n" edges = self.plugin.detect_entry_points("v.py", {}, src.encode()) assert edges == [] def test_framework_id_is_flask(self) -> None: src = textwrap.dedent("""\ @app.route("/") def root(): pass """) edges = self._edges(src) assert edges[0].framework_id == "flask" # --------------------------------------------------------------------------- # _CeleryPlugin # --------------------------------------------------------------------------- class TestCeleryPlugin: plugin = _CeleryPlugin() def _edges(self, source: str, file_path: str = "tasks/email.py") -> list[ImplicitEntryEdge]: sym_tree = _sym_tree(source, file_path) return self.plugin.detect_entry_points(file_path, sym_tree, source.encode()) def test_shared_task_bare_name(self) -> None: src = textwrap.dedent("""\ @shared_task def send_email(): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].kind == "task" assert edges[0].framework_id == "celery" def test_shared_task_called(self) -> None: src = textwrap.dedent("""\ @shared_task(bind=True) def send_email(self): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].kind == "task" def test_app_task_bare_attribute(self) -> None: src = textwrap.dedent("""\ @celery.task def process(): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].kind == "task" def test_app_task_called_attribute(self) -> None: src = textwrap.dedent("""\ @app.task(queue="high") def urgent(): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].kind == "task" def test_periodic_task_called(self) -> None: src = textwrap.dedent("""\ @app.periodic_task(run_every=60) def heartbeat(): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].kind == "periodic-task" def test_periodic_task_bare(self) -> None: src = textwrap.dedent("""\ @app.periodic_task def tick(): pass """) edges = self._edges(src) assert len(edges) == 1 assert edges[0].kind == "periodic-task" def test_unrelated_decorator_ignored(self) -> None: src = textwrap.dedent("""\ @login_required def secure(): pass """) edges = self._edges(src) assert edges == [] def test_syntax_error_returns_empty(self) -> None: edges = self.plugin.detect_entry_points("t.py", {}, b"def broken(:\n pass\n") assert edges == [] def test_framework_id_is_celery(self) -> None: src = textwrap.dedent("""\ @shared_task def work(): pass """) edges = self._edges(src) assert edges[0].framework_id == "celery" # --------------------------------------------------------------------------- # _CustomPatternPlugin # --------------------------------------------------------------------------- class TestCustomPatternPlugin: def _make_plugin(self, rules: list[_CustomEntryPointRule]) -> _CustomPatternPlugin: return _CustomPatternPlugin(rules) def test_custom_decorator_produces_edge(self) -> None: rule = _CustomEntryPointRule( language="Python", kind="rpc-handler", decorator_names=["rpc_handler"], ) plugin = self._make_plugin([rule]) src = textwrap.dedent("""\ @rpc_handler def handle_request(): pass """) sym_tree = _sym_tree(src, "svc/rpc.py") edges = plugin.detect_entry_points("svc/rpc.py", sym_tree, src.encode()) assert len(edges) == 1 assert edges[0].kind == "rpc-handler" assert edges[0].framework_id == "custom" def test_called_form_also_recognised(self) -> None: rule = _CustomEntryPointRule( language="Python", kind="webhook", decorator_names=["webhook_handler"], ) plugin = self._make_plugin([rule]) src = textwrap.dedent("""\ @webhook_handler(event="push") def on_push(): pass """) sym_tree = _sym_tree(src, "hooks.py") edges = plugin.detect_entry_points("hooks.py", sym_tree, src.encode()) assert len(edges) == 1 assert edges[0].kind == "webhook" def test_non_matching_decorator_ignored(self) -> None: rule = _CustomEntryPointRule( language="Python", kind="grpc", decorator_names=["grpc_handler"], ) plugin = self._make_plugin([rule]) src = textwrap.dedent("""\ @login_required def view(): pass """) sym_tree = _sym_tree(src, "views.py") edges = plugin.detect_entry_points("views.py", sym_tree, src.encode()) assert edges == [] def test_non_python_rules_excluded(self) -> None: rule = _CustomEntryPointRule( language="TypeScript", kind="ts-handler", decorator_names=["Handler"], ) plugin = self._make_plugin([rule]) # Plugin should have no Python rules, so no edges. src = textwrap.dedent("""\ @Handler def fn(): pass """) sym_tree = _sym_tree(src, "f.py") edges = plugin.detect_entry_points("f.py", sym_tree, src.encode()) assert edges == [] def test_empty_rules_returns_empty(self) -> None: plugin = self._make_plugin([]) src = textwrap.dedent("""\ @anything def fn(): pass """) sym_tree = _sym_tree(src, "f.py") edges = plugin.detect_entry_points("f.py", sym_tree, src.encode()) assert edges == [] def test_metadata_includes_decorator_name(self) -> None: rule = _CustomEntryPointRule( language="Python", kind="job", decorator_names=["schedule_job"], ) plugin = self._make_plugin([rule]) src = textwrap.dedent("""\ @schedule_job def nightly(): pass """) sym_tree = _sym_tree(src, "jobs.py") edges = plugin.detect_entry_points("jobs.py", sym_tree, src.encode()) assert edges[0].metadata.get("decorator") == "schedule_job" # --------------------------------------------------------------------------- # build_implicit_edge_graph # --------------------------------------------------------------------------- class TestBuildImplicitEdgeGraph: def test_empty_manifest_returns_empty(self, tmp_path: pathlib.Path) -> None: config = FrameworkConfig() result = build_implicit_edge_graph(tmp_path, {}, config=config) assert result == {} def test_fastapi_handler_detected(self, tmp_path: pathlib.Path) -> None: src = textwrap.dedent("""\ @router.get("/runs") async def list_runs(): pass """) manifest = _write_snapshot(tmp_path, {"server/routers/runs.py": src}) config = FrameworkConfig() result = build_implicit_edge_graph(tmp_path, manifest, config=config) assert any("list_runs" in addr for addr in result) def test_celery_task_detected(self, tmp_path: pathlib.Path) -> None: src = textwrap.dedent("""\ @shared_task def send_notification(): pass """) manifest = _write_snapshot(tmp_path, {"tasks/notify.py": src}) config = FrameworkConfig() result = build_implicit_edge_graph(tmp_path, manifest, config=config) assert any("send_notification" in addr for addr in result) def test_flask_handler_detected(self, tmp_path: pathlib.Path) -> None: src = textwrap.dedent("""\ @app.route("/dashboard") def dashboard(): pass """) manifest = _write_snapshot(tmp_path, {"web/views.py": src}) config = FrameworkConfig() result = build_implicit_edge_graph(tmp_path, manifest, config=config) assert any("dashboard" in addr for addr in result) def test_non_python_file_ignored(self, tmp_path: pathlib.Path) -> None: go_src = "func handler() {}\n" manifest = _write_snapshot(tmp_path, {"main.go": go_src}) config = FrameworkConfig() result = build_implicit_edge_graph(tmp_path, manifest, config=config) assert result == {} def test_syntax_error_file_skipped_gracefully(self, tmp_path: pathlib.Path) -> None: bad_src = "def broken(:\n pass\n" manifest = _write_snapshot(tmp_path, {"bad.py": bad_src}) config = FrameworkConfig() # Must not raise. result = build_implicit_edge_graph(tmp_path, manifest, config=config) assert isinstance(result, dict) def test_auto_detect_false_returns_empty(self, tmp_path: pathlib.Path) -> None: src = textwrap.dedent("""\ @router.get("/x") def get_x(): pass """) manifest = _write_snapshot(tmp_path, {"routes.py": src}) config = FrameworkConfig(auto_detect=False) result = build_implicit_edge_graph(tmp_path, manifest, config=config) assert result == {} def test_disabled_plugins_excluded(self, tmp_path: pathlib.Path) -> None: src = textwrap.dedent("""\ @router.get("/items") async def list_items(): pass """) manifest = _write_snapshot(tmp_path, {"routes.py": src}) # Disable FastAPI; FlaskPlugin and CeleryPlugin won't match this source. config = FrameworkConfig(disabled_plugins=frozenset({"fastapi"})) result = build_implicit_edge_graph(tmp_path, manifest, config=config) # No edge should appear since fastapi is the only matching plugin. assert not any("list_items" in addr for addr in result) def test_multiple_files_multiple_plugins(self, tmp_path: pathlib.Path) -> None: fastapi_src = textwrap.dedent("""\ @router.post("/orders") def create_order(): pass """) celery_src = textwrap.dedent("""\ @shared_task def process_order(): pass """) manifest = _write_snapshot(tmp_path, { "api/routes.py": fastapi_src, "workers/tasks.py": celery_src, }) config = FrameworkConfig() result = build_implicit_edge_graph(tmp_path, manifest, config=config) addrs = set(result.keys()) assert any("create_order" in a for a in addrs) assert any("process_order" in a for a in addrs) def test_custom_rule_in_config(self, tmp_path: pathlib.Path) -> None: src = textwrap.dedent("""\ @grpc_handler def serve_request(): pass """) manifest = _write_snapshot(tmp_path, {"svc/grpc.py": src}) rule = _CustomEntryPointRule( language="Python", kind="grpc", decorator_names=["grpc_handler"] ) config = FrameworkConfig(custom_entry_points=[rule]) result = build_implicit_edge_graph(tmp_path, manifest, config=config) assert any("serve_request" in addr for addr in result) # Kind should be grpc edges = [e for edges in result.values() for e in edges] assert any(e.kind == "grpc" for e in edges) def test_all_disabled_returns_empty(self, tmp_path: pathlib.Path) -> None: src = textwrap.dedent("""\ @router.get("/x") async def get_x(): pass """) manifest = _write_snapshot(tmp_path, {"r.py": src}) config = FrameworkConfig(disabled_plugins=frozenset({"fastapi", "flask", "celery"})) result = build_implicit_edge_graph(tmp_path, manifest, config=config) assert result == {} def test_graph_maps_address_to_edges(self, tmp_path: pathlib.Path) -> None: src = textwrap.dedent("""\ @router.get("/x") async def get_x(): pass """) manifest = _write_snapshot(tmp_path, {"routes.py": src}) config = FrameworkConfig() result = build_implicit_edge_graph(tmp_path, manifest, config=config) for addr, edges in result.items(): assert isinstance(addr, str) assert isinstance(edges, list) for e in edges: assert isinstance(e, ImplicitEntryEdge) # --------------------------------------------------------------------------- # load_framework_config # --------------------------------------------------------------------------- class TestLoadFrameworkConfig: def test_missing_file_returns_defaults(self, tmp_path: pathlib.Path) -> None: config = load_framework_config(tmp_path) assert config.auto_detect is True assert config.disabled_plugins == frozenset() assert config.custom_entry_points == [] def test_valid_toml_parsed(self, tmp_path: pathlib.Path) -> None: dot_muse = muse_dir(tmp_path) dot_muse.mkdir() toml_content = textwrap.dedent("""\ [framework_detection] auto_detect = true disabled_plugins = ["celery"] [[framework_detection.custom_entry_points]] language = "Python" kind = "grpc" decorator_names = ["grpc_method"] """) (dot_muse / "code_config.toml").write_text(toml_content) config = load_framework_config(tmp_path) assert config.auto_detect is True assert "celery" in config.disabled_plugins assert len(config.custom_entry_points) == 1 assert config.custom_entry_points[0].kind == "grpc" assert "grpc_method" in config.custom_entry_points[0].decorator_names def test_auto_detect_false_parsed(self, tmp_path: pathlib.Path) -> None: dot_muse = muse_dir(tmp_path) dot_muse.mkdir() (dot_muse / "code_config.toml").write_text( "[framework_detection]\nauto_detect = false\n" ) config = load_framework_config(tmp_path) assert config.auto_detect is False def test_missing_section_returns_defaults(self, tmp_path: pathlib.Path) -> None: dot_muse = muse_dir(tmp_path) dot_muse.mkdir() (dot_muse / "code_config.toml").write_text("[other_section]\nkey = 1\n") config = load_framework_config(tmp_path) assert config.auto_detect is True assert config.disabled_plugins == frozenset() def test_malformed_toml_returns_defaults(self, tmp_path: pathlib.Path) -> None: dot_muse = muse_dir(tmp_path) dot_muse.mkdir() (dot_muse / "code_config.toml").write_bytes(b"\xff\xfe invalid toml !!!") # Must not raise — returns defaults. config = load_framework_config(tmp_path) assert isinstance(config, FrameworkConfig) def test_disabled_plugins_stored_as_frozenset(self, tmp_path: pathlib.Path) -> None: dot_muse = muse_dir(tmp_path) dot_muse.mkdir() (dot_muse / "code_config.toml").write_text( '[framework_detection]\ndisabled_plugins = ["flask", "celery"]\n' ) config = load_framework_config(tmp_path) assert isinstance(config.disabled_plugins, frozenset) assert "flask" in config.disabled_plugins assert "celery" in config.disabled_plugins def test_multiple_custom_rules(self, tmp_path: pathlib.Path) -> None: dot_muse = muse_dir(tmp_path) dot_muse.mkdir() toml = textwrap.dedent("""\ [framework_detection] [[framework_detection.custom_entry_points]] language = "Python" kind = "grpc" decorator_names = ["grpc_method"] [[framework_detection.custom_entry_points]] language = "Python" kind = "webhook" decorator_names = ["webhook_handler", "on_event"] """) (dot_muse / "code_config.toml").write_text(toml) config = load_framework_config(tmp_path) assert len(config.custom_entry_points) == 2 kinds = {r.kind for r in config.custom_entry_points} assert kinds == {"grpc", "webhook"} # --------------------------------------------------------------------------- # Integration — dead-code analysis excludes entry points # --------------------------------------------------------------------------- class TestDeadCodeIntegration: """Verify that framework-wired symbols are not reported as dead code.""" def test_fastapi_handler_excluded_from_dead(self, tmp_path: pathlib.Path) -> None: """A FastAPI route handler with no explicit callers is not dead code.""" from muse.plugins.code._framework import build_implicit_edge_graph src = textwrap.dedent("""\ @router.get("/items") async def list_items(): pass """) manifest = _write_snapshot(tmp_path, {"api/routes.py": src}) implicit = build_implicit_edge_graph(tmp_path, manifest) entry_point_addresses = frozenset(implicit.keys()) # The handler must be recognised as an entry point. assert any("list_items" in addr for addr in entry_point_addresses) def test_celery_task_excluded_from_dead(self, tmp_path: pathlib.Path) -> None: from muse.plugins.code._framework import build_implicit_edge_graph src = textwrap.dedent("""\ @shared_task def send_report(): pass """) manifest = _write_snapshot(tmp_path, {"tasks/report.py": src}) implicit = build_implicit_edge_graph(tmp_path, manifest) entry_point_addresses = frozenset(implicit.keys()) assert any("send_report" in addr for addr in entry_point_addresses) def test_plain_function_not_mistaken_for_entry_point( self, tmp_path: pathlib.Path ) -> None: from muse.plugins.code._framework import build_implicit_edge_graph src = textwrap.dedent("""\ def compute_total(items): pass """) manifest = _write_snapshot(tmp_path, {"billing.py": src}) implicit = build_implicit_edge_graph(tmp_path, manifest) entry_point_addresses = frozenset(implicit.keys()) assert not any("compute_total" in addr for addr in entry_point_addresses)