python

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 15, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package python is the Python-specific runner: build, test, and run Python services across native, Docker, and Nix backends.

It handles virtualenv / Poetry resolution, dependency installation, pytest invocation with filter wiring, and the agent-side helpers used by the python and python-fastapi agents.

Index

Constants

View Source
const (
	OutputJUnitXML     = "junit-xml"
	OutputUnittestText = "unittest-text"
)
View Source
const MaxCapturedOutputBytesPerCase = 32 * 1024

MaxCapturedOutputBytesPerCase mirrors the Go-runner cap. Pytest's JUnit `<failure>` elements bundle the traceback + captured stdout/stderr in the body — typically a few KB per case; very rarely exceeds 32KiB unless the test prints debug logs.

Variables

This section is empty.

Functions

func BuildUvArgs added in v0.2.0

func BuildUvArgs(spec TestFormulaSpec, junitFile string) []string

BuildUvArgs renders a TestFormulaSpec into the argv for `uv` (excluding the leading "uv"). Pure and deterministic so the data→command translation is unit-tested without executing anything. junitFile is the path the plugin allocated for junit-xml output ("" for non-junit formats).

func DeriveFormula added in v0.2.0

func DeriveFormula(sourceDir string) (cmd []string, output string, env, prov map[string]string, ok bool)

DeriveFormula inspects sourceDir and returns a runnable test formula: the argv (command), the structured-output format, env, and uv provisioning — all derived from the project. ok=false means the project declares nothing runnable (caller falls back to its default runner). No framework is hardcoded: the command comes from the project's text; provisioning comes from its packaging metadata.

func HasUVRuntime

func HasUVRuntime() bool

HasUVRuntime checks if the uv Python package manager is available.

func RunPythonLint

func RunPythonLint(ctx context.Context, sourceDir string) (string, error)

RunPythonLint runs ruff check and returns the output.

func SetPythonRuntimeContext

func SetPythonRuntimeContext(runtimeContext *basev0.RuntimeContext) *basev0.RuntimeContext

SetPythonRuntimeContext determines the runtime context based on the requested context and available Python toolchain (uv).

Types

type PythonAgentSettings

type PythonAgentSettings struct {
	PythonVersion string `yaml:"python-version"`
	SourceDir     string `yaml:"source-dir"`
}

PythonAgentSettings holds settings common to all Python service agents.

func (*PythonAgentSettings) PythonSourceDir

func (s *PythonAgentSettings) PythonSourceDir() string

PythonSourceDir returns the configured source directory. Python convention: source is at the service root (not a subdirectory).

type RunEnvError added in v0.2.0

type RunEnvError struct {
	Reason string // "missing-dependency" | "import-error" | "version-conflict" | "interpreter-missing" | "unknown"
	Detail string // the scraped failure tail, e.g. "ModuleNotFoundError: No module named 'werkzeug'"
}

RunEnvError classifies why the environment blocked the run. The python plugin owns this classification (it knows pytest/uv exit semantics); Mind maps Reason onto its BlockReason without re-parsing raw output.

func ClassifyEnvError added in v0.2.0

func ClassifyEnvError(raw string, runErr error) *RunEnvError

ClassifyEnvError inspects a run's raw output (and exit error) to decide WHY the environment blocked the run. Pattern order is most-specific first. Exported so RunFormulaStructured and tests share one classifier.

type StructuredCase added in v0.1.157

type StructuredCase struct {
	Name      string // local case name
	FullName  string // classname.name
	State     runtimev0.TestCaseState
	Duration  time.Duration
	File      string
	Line      int32
	Output    string // captured_output (populated only for FAILED/ERRORED)
	Truncated bool
	Failure   *StructuredFailure
}

StructuredCase is one pytest invocation.

type StructuredFailure added in v0.1.157

type StructuredFailure struct {
	Message string // one-line pytest summary
	Detail  string // traceback + captured output
	Kind    runtimev0.TestFailureKind
}

StructuredFailure carries the diagnostic detail for a failing case.

type StructuredSuite added in v0.1.157

type StructuredSuite struct {
	Name     string // file path (or class name when file unknown)
	File     string // absolute or repo-relative source path
	Duration time.Duration
	Cases    []*StructuredCase
}

StructuredSuite is one source-file's worth of cases.

type StructuredTestRun added in v0.1.157

type StructuredTestRun struct {
	// Suites — one per source file. Pytest's JUnit emits a flat list
	// of `<testcase>`s; we group by file to mirror the Go runner's
	// "one suite per package" shape. Source-file grouping is what
	// developers actually reason about ("did the users tests pass?").
	Suites []*StructuredSuite

	// CoveragePct is scraped from pytest-cov's terminal output passed
	// in alongside the JUnit XML. JUnit XML doesn't carry coverage.
	CoveragePct float32

	// EnvError, when set, means the run could NOT EXECUTE the tests — the
	// ENVIRONMENT was blocked (a dependency failed to install, the project failed
	// to import, the interpreter is missing) — as opposed to tests running and
	// failing. RunFormulaStructured sets it when the process exits non-zero having
	// produced ZERO cases. ToProtoResponse maps it to Result.State=ERRORED with a
	// classified reason, so a caller distinguishes "tests failed" (FAILED) from
	// "couldn't run" (ERRORED) from the STRUCTURE — never from a raw "exit status
	// 1". This is what the Mind tooling inner loop reads to heal plugin config.
	EnvError *RunEnvError
	// contains filtered or unexported fields
}

StructuredTestRun is the python-side equivalent of the Go runner's StructuredTestRun. Built by ParsePytestJUnit; convertible to runtimev0.TestResponse via ToProtoResponse.

func ParsePytestJUnit added in v0.1.157

func ParsePytestJUnit(rawXML string, coverage float32) *StructuredTestRun

ParsePytestJUnit parses the contents of pytest's --junitxml output into a StructuredTestRun. Empty raw, malformed XML, and "no tests collected" all surface as a StructuredTestRun with zero suites and zero cases — the caller decides whether that's an error.

coverage is scraped separately (pytest-cov writes to stdout, not the XML); pass it through if available, 0 otherwise.

func ParseUnittestText added in v0.2.0

func ParseUnittestText(output string) *StructuredTestRun

ParseUnittestText parses unittest TextTestRunner verbose output into a StructuredTestRun. Result lines set each test's state; FAIL:/ERROR: block headers override it (a test can print "... ok" then error during teardown) and attach the traceback as the case's captured output. Cases are grouped into one suite per test class. Empty/garbage input yields zero suites — the caller decides whether that's an environment block.

func RunFormulaStructured added in v0.2.0

func RunFormulaStructured(ctx context.Context, sourceDir string, spec TestFormulaSpec) (*StructuredTestRun, error)

RunFormulaStructured runs a test formula through `uv run` and returns the structured result, parsed by the formula's output format. One executor for every python test runner — the formula data is what differs.

func RunPythonTestsStructured added in v0.1.157

func RunPythonTestsStructured(ctx context.Context, sourceDir string, envVars []*resources.EnvironmentVariable, opts ...TestOptions) (*StructuredTestRun, error)

RunPythonTestsStructured runs pytest with --junitxml output, parses the XML into the SOTA structured run, and returns it. Preferred entry point for new code that consumes the structured TestResponse shape.

Pytest's JUnit XML carries per-case file:line, captured stdout/stderr in the `<failure>` body for failed tests, and zero-body `<testcase>` for passed tests — fits the response-size discipline rule perfectly.

Coverage is scraped from pytest-cov's terminal output (XML doesn't carry coverage); the OnEvent callback still works against the verbose stream.

func (*StructuredTestRun) LegacyTestSummary added in v0.1.157

func (r *StructuredTestRun) LegacyTestSummary() *TestSummary

LegacyTestSummary returns the flat shape callers that haven't migrated still consume. Computed from the structured tree — single source of truth.

func (*StructuredTestRun) ToProtoResponse added in v0.1.157

func (r *StructuredTestRun) ToProtoResponse(runner, suiteName string, duration time.Duration) *runtimev0.TestResponse

ToProtoResponse constructs the runtimev0.TestResponse with both the structured tree (preferred) AND legacy flat fields populated (back-compat for non-migrated consumers).

runner is "pytest"; suiteName echoes TestRequest.suite. duration is the wall-clock for the whole run.

type TestEvent

type TestEvent struct {
	Action string // "pass" | "fail" | "skip"
	Test   string // test node id (e.g. "tests/test_admin.py::test_version")
}

TestEvent is a single per-test signal extracted from pytest's verbose output. Mirrors the go-side TestEvent shape so consumers can drive a uniform UI across both languages.

type TestFormulaSpec added in v0.2.0

type TestFormulaSpec struct {
	// Command is the inner test command from the formula, already split into
	// argv, e.g. ["pytest"] or ["python","tests/runtests.py","--verbosity=2"].
	Command []string
	// Selectors are the specific tests to run, appended positionally (pytest
	// node-ids, django dotted labels — the plugin doesn't interpret them).
	Selectors []string
	// Output names the format parser: "junit-xml" (the plugin adds --junitxml
	// and parses the file) or "unittest-text" (parses unittest's text output).
	Output string

	// --- provisioning (per-instance environment, all DATA) ---
	// These map to `uv run` flags. The plugin knows the FLAG NAMES (it is the
	// uv plugin); the VALUES come from the caller, so SWE-bench's per-instance
	// python version / editable install / dependency pins are injected as data
	// instead of a hardcoded brain-side command.
	NoProject    bool
	Python       string   // uv run --python <v>
	Editable     bool     // uv run --with-editable .
	Requirements []string // uv run --with-requirements <file>
	With         []string // uv run --with <spec>

	// ExtraArgs are appended to the command verbatim (power-user passthrough).
	ExtraArgs []string
	// Env are extra environment variables for the run.
	Env []*resources.EnvironmentVariable
}

TestFormulaSpec is everything needed to run one test formula. Every field is DATA supplied by the caller (Mind's captured formula + the per-instance environment); nothing here is framework-specific knowledge.

func SpecFromFormula added in v0.2.0

func SpecFromFormula(command []string, output string, env, provisioning map[string]string, selectors []string) TestFormulaSpec

SpecFromFormula translates a LANGUAGE-AGNOSTIC formula (generic command + output + env + an opaque provisioning map) into the python/uv TestFormulaSpec. This is the ONLY place python/uv knowledge interprets the provisioning bag: the keys python / editable / with / requirements / no_project become uv flags. Callers (Mind, the agent handler) stay framework- and toolchain-blind.

type TestOptions

type TestOptions struct {
	// OnEvent, when non-nil, is called for each per-test result line as
	// pytest emits it. Lets the agent forward live progress to the TUI
	// without waiting for the full summary at the end.
	OnEvent func(TestEvent)

	// CacheDir, when non-empty, persists the raw pytest output to
	// <CacheDir>/last-test.txt for post-mortem debugging.
	CacheDir string

	// Target is a directory or node id (e.g. "tests/unit",
	// "tests/test_admin.py::test_version"). Empty runs the default scope.
	Target string

	// Filters are name patterns passed to pytest's -k expression.
	// Multiple values are joined with " or " — pytest's standard idiom.
	Filters []string

	// Verbose toggles pytest's -v flag. Defaults on at the helper level
	// for backward compat; agents that want quieter output should pass
	// false explicitly via this struct.
	Verbose bool
	// VerboseSet distinguishes "use default" from "explicitly false".
	VerboseSet bool

	// Timeout maps to pytest's --timeout=<sec>. Empty leaves the
	// default. Accepts Go duration syntax ("30s", "2m") which we coerce
	// into seconds for pytest.
	Timeout string

	// Coverage enables coverage instrumentation via pytest-cov when the
	// project has it installed. Off by default.
	Coverage bool

	// ExtraArgs are appended verbatim to the pytest command — power-user
	// passthrough for flags codefly does not model.
	ExtraArgs []string
}

TestOptions controls pytest invocation.

type TestSummary

type TestSummary struct {
	Run      int32
	Passed   int32
	Failed   int32
	Skipped  int32
	Coverage float32
	Failures []string
}

TestSummary holds the parsed results of a pytest run.

func ParsePytestVerbose

func ParsePytestVerbose(output string) *TestSummary

ParsePytestVerbose parses the verbose text output from pytest -v --tb=short.

func RunPythonTests

func RunPythonTests(ctx context.Context, sourceDir string, envVars []*resources.EnvironmentVariable, opts ...TestOptions) (*TestSummary, error)

RunPythonTests runs pytest and returns parsed results. Backward-compat wrapper: calls RunPythonTestsStructured internally and converts to the flat *TestSummary shape so existing consumers keep working unchanged.

New code should call RunPythonTestsStructured directly to get the full structured run (per-case file:line, captured-on-failure-only output, proto-friendly hierarchy).

func (*TestSummary) SummaryLine

func (s *TestSummary) SummaryLine() string

SummaryLine formats a one-line summary string.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL