Skip to content

feat(extract): Route+HANDLES for Django REST Framework @action methods#746

Merged
DeusData merged 1 commit into
mainfrom
distill/647-drf-viewset-actions
Jul 1, 2026
Merged

feat(extract): Route+HANDLES for Django REST Framework @action methods#746
DeusData merged 1 commit into
mainfrom
distill/647-drf-viewset-actions

Conversation

@DeusData

@DeusData DeusData commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Distilled from #647 (thanks @muskiteer for the DRF ViewSet extractor).

What

Django REST Framework ViewSets expose extra endpoints through @action-decorated methods:

class CustomerTaskViewSet(ViewSet):
    @action(detail=True, methods=["post"], url_path="approve")
    def approve_draft_with_charge(self, request, pk=None): ...

On main these methods carried no route_path, so Phase 2a created no Route node and no HANDLES edge for them — the endpoint was invisible in the graph (#603).

Fix

try_drf_action_decorator (internal/cbm/extract_defs.c): when a method's decorator identifier is action, read the methods / url_path / detail kwargs and set *out_path/*out_method. The existing decorator-route pipeline (ensure_one_decorator_route, Phase 2a) then creates the Route + handler→Route HANDLES edge in the established direction. Fallbacks: method name for url_path, "GET" for methods; detail=True/{pk}/<seg>, else /<seg>.

Reproduce-first

handles_drf_action_python (edge_types_probe suite): a DRF @action method must produce ≥1 HANDLES edge. RED (0 edges) on main without the extractor, GREEN with it. Full suite green.

Scope note (why a distillation, not a merge of #647)

#647 bundled this extractor with an unrelated project-wide reversal of the HANDLES edge direction (handler→RouteRoute→handler) across every framework. That reversal was (a) unnecessary — the test counts HANDLES direction-agnostically and the extractor alone closes #603 — and (b) a latent regression: pass_cross_repo.c's find_route_handler resolves a route's handler with WHERE e.target_id = <route> AND e.type='HANDLES' (assumes handler→Route) and was not updated, so cross-repo route→handler resolution would silently return 0. This PR keeps only the extractor and preserves the documented convention.

Known limitation

Multi-method actions (methods=["get","post"]) capture only the first method → a single Route. Left as a follow-up.

Closes #603

Co-authored with @muskiteer.

…thods

Django REST Framework ViewSets expose extra endpoints through @action-decorated
methods, e.g. @action(detail=True, methods=["post"], url_path="approve"). On
main these methods carried no route_path, so Phase 2a created no Route node and
no HANDLES edge for them -- the endpoint was invisible in the graph (#603).

Add try_drf_action_decorator (internal/cbm/extract_defs.c): when a method's
decorator identifier is "action", read the methods / url_path / detail kwargs
and set *out_path/*out_method. The existing decorator-route pipeline
(ensure_one_decorator_route, Phase 2a) then creates the Route + handler->Route
HANDLES edge in the established direction. Fallbacks: method name for url_path,
"GET" for methods; detail=True -> /{pk}/<seg>, else /<seg>.

Reproduce-first guard: handles_drf_action_python in the edge_types_probe suite
-- a DRF @action method must produce >=1 HANDLES edge (RED with 0 edges before
the extractor, GREEN after).

Known limitation: multi-method actions (methods=["get","post"]) capture only the
first method -> a single Route.

Distilled from #647 (thanks @muskiteer). Drops that PR's unrelated project-wide
HANDLES edge-direction reversal, which was unnecessary for the fix and broke the
handler->Route convention relied on by pass_cross_repo.c's find_route_handler.

Closes #603

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Co-Authored-By: muskiteer <agarwal.vansh3110@gmail.com>
@DeusData DeusData merged commit f42c066 into main Jul 1, 2026
15 checks passed
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.

Django REST Framework ViewSet routes miss HANDLES mappings

1 participant