Skip to content

Discovery miner: Python API routes (FastAPI, Flask, Django) #129

@Dimwiddle

Description

@Dimwiddle

Summary

Extract HTTP route definitions from Python web framework files using tree-sitter. Supports FastAPI, Flask, and Django.

Depends on: #124, #125, #126

New file

src/specleft/discovery/miners/python/routes.py

import uuid
from specleft.discovery.models import SupportedLanguage, MinerResult, DiscoveredItem, ItemKind, ApiRouteMeta
from specleft.discovery.context import MinerContext

class PythonRouteMiner:
    miner_id = uuid.UUID("007ab65e-e4e8-4b7e-9c33-163635168071")
    name = "python_api_routes"
    languages = frozenset({SupportedLanguage.PYTHON})

    def mine(self, ctx: MinerContext) -> MinerResult: ...

Framework detection

Read from ctx.frameworks[SupportedLanguage.PYTHON] to determine which framework detection strategy to apply. Do NOT re-parse pyproject.toml or scan imports — the FrameworkDetector has already resolved this.

If ctx.frameworks includes "fastapi", scan for FastAPI patterns. If "flask", scan Flask patterns. If "django", scan Django patterns. Multiple frameworks may be present — scan for all.

File targeting

Use ctx.file_index.files_by_language(SupportedLanguage.PYTHON) to get all Python files. Scan all of them for route patterns (not just test files).

Detection strategies per framework

FastAPI / APIRouter:
Tree-sitter query: decorated function where decorator is an attribute access on app or router, method name is get|post|put|patch|delete|options|head. First string argument is the path.

Flask:
@app.route("/path", methods=["GET"]) or @blueprint.route(...). Parse methods keyword argument; default to ["GET"] if absent.

Django:
urlpatterns = [path("...", view_func, name="..."), re_path(...)]. Parse list elements.

Typed metadata

Each item's metadata dict must conform to ApiRouteMeta:

ApiRouteMeta(
    http_method    = "GET",
    path           = "/users/{id}",
    framework      = "fastapi",
    handler_name   = "get_user",
    has_docstring  = True,
    docstring      = "Retrieve a user by ID",
    response_model = "UserResponse",
)

name: "{METHOD} {path}" (e.g. "GET /users/{id}")
language: SupportedLanguage.PYTHON

Acceptance criteria

  • FastAPI fixture with 3 routes (GET, POST, PATCH) returns 3 items with correct methods and paths
  • All items have language=SupportedLanguage.PYTHON
  • Each item's metadata validates against ApiRouteMeta
  • Flask blueprint route @bp.route("/items", methods=["GET", "POST"])http_method=["GET", "POST"]
  • Django urlpatterns with path() and re_path() both produce items
  • Missing methods kwarg on Flask route defaults to ["GET"]
  • response_model captured for FastAPI routes
  • Uses ctx.file_index and ctx.frameworks — no direct filesystem or manifest parsing
  • Tests in tests/discovery/miners/test_python_routes.py
  • Update scenarios and tests in features/feature-spec-discovery.md to cover the functionality introduced by this issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    apiAPI route miningminerDiscovery miner implementationnew featureIssues or PRs for a new feature that doesn't currently existpythonPython language specific

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions