226 lines
7.3 KiB
Markdown
226 lines
7.3 KiB
Markdown
---
|
|
adapter:
|
|
language: python
|
|
display_name: "Python"
|
|
version: "1.0"
|
|
|
|
detection:
|
|
files: [pyproject.toml, setup.py, requirements.txt, Pipfile]
|
|
content_patterns:
|
|
- file: "pyproject.toml"
|
|
pattern: '\\[project\\]|\\[tool\\.poetry\\]'
|
|
confidence: 0.90
|
|
|
|
commands:
|
|
build: null # Python typically doesn't need a build step
|
|
test: "pytest"
|
|
lint: "ruff check ."
|
|
lint_arch: "python scripts/lint_deps.py src/"
|
|
format: "ruff format ."
|
|
start: null # Inferred from framework
|
|
dev: null
|
|
|
|
package_manager:
|
|
detection:
|
|
- lockfile: "poetry.lock"
|
|
manager: "poetry"
|
|
- lockfile: "uv.lock"
|
|
manager: "uv"
|
|
- lockfile: "Pipfile.lock"
|
|
manager: "pipenv"
|
|
- lockfile: "pdm.lock"
|
|
manager: "pdm"
|
|
default: "pip"
|
|
install_command: "{manager} install"
|
|
|
|
route_detection:
|
|
server_indicators:
|
|
- pattern: 'from fastapi|import fastapi|FastAPI\(\)'
|
|
description: "FastAPI ASGI framework"
|
|
frameworks: ["fastapi"]
|
|
- pattern: 'from flask|import flask|Flask\(__name__\)'
|
|
description: "Flask WSGI framework"
|
|
frameworks: ["flask"]
|
|
- pattern: 'from django|import django'
|
|
description: "Django web framework"
|
|
frameworks: ["django"]
|
|
- pattern: 'from aiohttp|import aiohttp\.web'
|
|
description: "aiohttp async web framework"
|
|
frameworks: ["aiohttp"]
|
|
- pattern: 'from starlette|import starlette'
|
|
description: "Starlette ASGI framework"
|
|
frameworks: ["starlette"]
|
|
- pattern: 'from litestar|import litestar'
|
|
description: "Litestar ASGI framework"
|
|
frameworks: ["litestar"]
|
|
|
|
cli_indicators:
|
|
- pattern: 'import click|from click'
|
|
description: "Click CLI framework"
|
|
frameworks: ["click"]
|
|
- pattern: 'import typer|from typer'
|
|
description: "Typer CLI framework"
|
|
frameworks: ["typer"]
|
|
- pattern: 'import argparse|from argparse'
|
|
description: "Standard library argparse"
|
|
frameworks: ["argparse"]
|
|
- pattern: 'import fire|from fire'
|
|
description: "Google Python Fire"
|
|
frameworks: ["fire"]
|
|
|
|
frontend_indicators: [] # Python is not typically used for frontend
|
|
|
|
patterns:
|
|
# FastAPI
|
|
- type: route
|
|
regex: '@(?:app|router)\.(get|post|put|delete|patch)\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
|
groups: [method, path]
|
|
frameworks: ["fastapi", "starlette", "litestar"]
|
|
# Flask
|
|
- type: route
|
|
regex: '@(?:app|bp|blueprint)\.(route)\s*\(\s*["\x27]([^"\x27]+)["\x27](?:.*methods\s*=\s*\[([^\]]+)\])?'
|
|
groups: [_, path, method]
|
|
frameworks: ["flask"]
|
|
# Django URLs
|
|
- type: route
|
|
regex: 'path\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
|
groups: [path]
|
|
frameworks: ["django"]
|
|
# Click
|
|
- type: command
|
|
regex: '@\w+\.command\s*\(\s*(?:name\s*=\s*)?["\x27]?([^"\x27\)]+)'
|
|
groups: [command_name]
|
|
frameworks: ["click"]
|
|
# Typer
|
|
- type: command
|
|
regex: '@app\.command\s*\(\s*(?:name\s*=\s*)?["\x27]?([^"\x27\)]*)'
|
|
groups: [command_name]
|
|
frameworks: ["typer"]
|
|
|
|
import_analysis:
|
|
list_packages: null
|
|
import_pattern: "^(?:from|import)\\s+([\\w.]+)"
|
|
source_extensions: [".py"]
|
|
module_root_file: "pyproject.toml"
|
|
|
|
layer_conventions:
|
|
patterns:
|
|
- layer: 0
|
|
paths: ["src/models", "src/schemas", "src/types", "models", "schemas"]
|
|
description: "Data models, Pydantic schemas, type definitions"
|
|
- layer: 1
|
|
paths: ["src/utils", "src/lib", "src/common", "utils", "lib"]
|
|
description: "Shared utilities"
|
|
- layer: 2
|
|
paths: ["src/services", "src/core", "src/domain", "services", "core"]
|
|
description: "Business logic, service layer"
|
|
- layer: 3
|
|
paths: ["src/api", "src/routes", "src/views", "src/handlers", "api", "routes"]
|
|
description: "API endpoints, request handlers"
|
|
- layer: 4
|
|
paths: ["src/main.py", "src/app.py", "src/cli.py", "main.py", "app.py"]
|
|
description: "Application entry points"
|
|
|
|
dependency_detection:
|
|
manifest_file: "pyproject.toml"
|
|
databases:
|
|
- pattern: "psycopg|asyncpg|sqlalchemy.*postgres|databases.*postgres"
|
|
type: "postgres"
|
|
default_port: 5432
|
|
- pattern: "pymysql|aiomysql|mysqlclient"
|
|
type: "mysql"
|
|
default_port: 3306
|
|
- pattern: "pymongo|motor"
|
|
type: "mongodb"
|
|
default_port: 27017
|
|
- pattern: "redis|aioredis"
|
|
type: "redis"
|
|
default_port: 6379
|
|
- pattern: "aiosqlite|sqlite3"
|
|
type: "sqlite"
|
|
default_port: 0
|
|
services:
|
|
- pattern: "confluent-kafka|aiokafka"
|
|
type: "kafka"
|
|
default_port: 9092
|
|
- pattern: "pika|aio-pika"
|
|
type: "rabbitmq"
|
|
default_port: 5672
|
|
- pattern: "elasticsearch|elastic-transport"
|
|
type: "elasticsearch"
|
|
default_port: 9200
|
|
env_var_patterns:
|
|
- pattern: 'os\.environ\.get\(\s*["\x27]([^"\x27]+)["\x27]'
|
|
- pattern: 'os\.environ\[["\x27]([^"\x27]+)["\x27]\]'
|
|
- pattern: 'os\.getenv\(\s*["\x27]([^"\x27]+)["\x27]'
|
|
|
|
linter:
|
|
template_section: "python-linter"
|
|
script_extension: ".py"
|
|
run_command: "python scripts/lint_deps.py src/"
|
|
|
|
naming:
|
|
file_pattern: "^[a-z][a-z0-9_]*\\.py$"
|
|
test_pattern: "^test_[a-z][a-z0-9_]*\\.py$"
|
|
directory_style: "snake_case"
|
|
|
|
ci:
|
|
github_actions:
|
|
image: "python:3.12"
|
|
setup_steps:
|
|
- "uses: actions/setup-python@v5\n with:\n python-version: '3.12'"
|
|
cache_paths: ["~/.cache/pip", ".venv"]
|
|
---
|
|
|
|
# Python Adapter
|
|
|
|
## Server Start Command Inference
|
|
|
|
1. Existing `harness/config/environment.json` startup command, if present
|
|
2. FastAPI detected → `python -m uvicorn {module}:app --port 8080`
|
|
- Module inferred from main app file location
|
|
3. Flask detected → `python -m flask run --port 8080`
|
|
4. Django detected → `python manage.py runserver 8080`
|
|
5. `main.py` exists → `python main.py`
|
|
|
|
## Virtual Environment Detection
|
|
|
|
The adapter checks for virtual environments in this order:
|
|
1. `.venv/` directory → `source .venv/bin/activate`
|
|
2. `venv/` directory → `source venv/bin/activate`
|
|
3. `poetry.lock` → `poetry shell` or prefix with `poetry run`
|
|
4. `uv.lock` → prefix with `uv run`
|
|
5. `Pipfile.lock` → prefix with `pipenv run`
|
|
|
|
## Framework-Specific Notes
|
|
|
|
### FastAPI
|
|
- Routes via decorators: `@app.get("/path")`, `@router.post("/path")`
|
|
- Dependency injection via `Depends()`
|
|
- Auto-generated OpenAPI docs at `/docs` and `/redoc`
|
|
- Start with uvicorn: `uvicorn app.main:app --reload`
|
|
|
|
### Flask
|
|
- Routes via decorators: `@app.route("/path", methods=["GET"])`
|
|
- Blueprints for modular routing
|
|
- Start with: `flask run` or `python -m flask run`
|
|
|
|
### Django
|
|
- URL configuration in `urls.py`: `path("api/", include("app.urls"))`
|
|
- Class-based views and function-based views
|
|
- Start with: `python manage.py runserver`
|
|
- Migrations: `python manage.py migrate`
|
|
|
|
### Click / Typer (CLI)
|
|
- Click: `@cli.command()` decorator pattern
|
|
- Typer: `@app.command()` decorator pattern, with auto-generated help
|
|
|
|
## Type Checking
|
|
|
|
Python projects may use type checkers:
|
|
- `mypy` — most common, configured in `pyproject.toml` or `mypy.ini`
|
|
- `pyright` — Microsoft's type checker, often via Pylance
|
|
- `pytype` — Google's type checker
|
|
|
|
Detection: check `pyproject.toml` `[tool.mypy]` or `mypy.ini` existence.
|