Skip to main content

gaze-py

CI PyPI Python

gaze-py is a Python-native port of gaze, the GazeCRAP analysis engine. It detects observable side effects in Python functions using AST-only static analysis (no code execution, no imports of analysed modules), classifies each effect as contractual or incidental using a five-signal confidence engine, and computes CRAP and GazeCRAP scores to surface functions that are both complex and under-tested. The output is schema-compatible with the Go gaze implementation.

Documentation — concepts, getting-started guide, CLI reference, configuration, glossary.

Requirements

  • Python 3.11+

Installation

# Run without installing (recommended for one-off use)
uvx --from gaze-py gazepy --help

# Permanent install
uv tool install gaze-py

# Or with pip
pip install gaze-py

Basic usage

# Analyse a source directory (CRAP will be null — no coverage provided)
gazepy analyze src/

# JSON output (default)
gazepy analyze src/ --format=json

# Human-readable text output (one line per function)
gazepy analyze src/ --format=text

# CRAP scoring — auto-runs pytest for coverage
gazepy crap src/

# CRAP scoring with a pre-generated coverage report
gazepy crap src/ --coverprofile cov.json

# Assess test quality and compute GazeCRAP scores
gazepy quality src/

# Scaffold OpenCode agent and command files into .opencode/
gazepy init

CRAP scoring with gazepy crap

CRAP scoring requires line coverage data. The crap command can collect coverage automatically by running pytest, or accept a pre-generated coverage.py JSON report:

# Auto-run pytest and collect coverage (requires pytest-cov)
gazepy crap src/

# Use a pre-generated coverage report (recommended in CI to avoid a double test run)
pytest --cov=your_package --cov-report=json:cov.json
gazepy crap src/ --coverprofile cov.json

# Fail CI if crapload exceeds a threshold
gazepy crap src/ --max-crapload 30

When coverage is provided, the line_coverage and crap fields are populated in the output. When omitted, those fields are null (not 0.0) — null means "not measured", not "zero coverage".

The analyze command detects side effects only — it does not compute CRAP scores. Use gazepy crap for CRAP scoring.

Quality assessment with gazepy quality

gazepy quality runs the full O1 pipeline: pairs test functions to their production targets, detects assertion sites, maps assertions to detected side effects, and computes GazeCRAP using contract coverage (the fraction of contractual effects covered by tests).

# Assess test quality — auto-discovers tests/ directory
gazepy quality src/

# Explicit tests directory
gazepy quality src/ --tests tests/

# JSON output
gazepy quality src/ --format=json

# Fail CI if average contract coverage drops below a threshold
gazepy quality src/ --min-contract-coverage 80

Understanding the output

Each function in the output includes:

Field Description
side_effects List of detected observable side effects with type, tier, and classification
complexity McCabe cyclomatic complexity
line_coverage Fraction of lines covered (0.0–1.0), or null if not provided
crap CRAP score (complexity² × (1 − coverage)³ + complexity), or null
gaze_crap GazeCRAP score using contract coverage; populated by gazepy quality
quadrant Q1–Q4 classification based on CRAP and GazeCRAP; populated by gazepy quality
fix_strategy Recommended action: add_tests, add_assertions, decompose_and_test, or decompose
contract_coverage Fraction of contractual effects covered by tests; populated by gazepy quality

The summary section includes recommended_actions — up to 20 functions sorted by priority (add_tests → decompose_and_test → decompose) that exceed the CRAP threshold.

AI Reports

gazepy report can pass the analysis JSON to a local or cloud AI provider to generate a narrative interpretation. Configure your provider in .gaze.yaml:

ai:
  provider: ollama       # or: vertex
  model: llama3.2:3b     # any Ollama model, or a Vertex Claude model ID
  endpoint: http://localhost:11434   # Ollama only; ignored for Vertex
  timeout: 120           # seconds per HTTP request (default: 120)

For Google Vertex AI (Claude models):

ai:
  provider: vertex
  model: claude-sonnet-4-6
  project: my-gcp-project
  region: us-east5

Environment variable overrides (higher precedence than config file):

Variable Description
GAZEPY_AI_PROVIDER Provider name (ollama or vertex)
GAZEPY_AI_MODEL Model ID (setting only this implies ollama)
GAZEPY_AI_ENDPOINT Ollama base URL (default: http://localhost:11434)
GAZEPY_AI_PROJECT GCP project ID (Vertex only)
GAZEPY_AI_REGION GCP region (Vertex only)
GAZEPY_AI_TIMEOUT HTTP timeout in seconds

Prerequisites:

  • Ollama: install from ollama.com and pull your model (ollama pull llama3.2:3b)
  • Vertex: install the Google Cloud SDK and run gcloud auth application-default login

If no provider is configured, gazepy report emits the raw analysis JSON to stdout and a tip to stderr.

Migration from --ai flag: the --ai and --ai-timeout flags have been removed. Configure your provider in .gaze.yaml instead (see above).

Troubleshooting

Symptom Likely cause Fix
gcloud auth print-access-token failed (exit 1) Not authenticated Run gcloud auth application-default login
vertex provider requires gcloud CLI gcloud not on PATH Install the Google Cloud SDK
unexpected response format from gcloud auth print-access-token Outdated gcloud Run gcloud components update
Ollama request timed out after Ns Model is slow or timeout too short Increase ai.timeout in .gaze.yaml (e.g. timeout: 300)
Ollama request failed: Connection refused Ollama not running Start Ollama: ollama serve
Ollama returned HTTP 404 Model not pulled Pull the model: ollama pull llama3.2:3b
Vertex AI rate limited after 5 retries API quota exceeded Wait and retry, or reduce request frequency
Vertex AI returned HTTP 401 after token refresh Credentials expired Run gcloud auth application-default login again
Warning: ollama provider configured but not available Model not pulled or Ollama not running Pull the model or start Ollama; report falls back to prompt-only mode
Invalid value for GAZEPY_AI_TIMEOUT Non-integer or non-positive timeout Set GAZEPY_AI_TIMEOUT to a positive integer (e.g. 120)

Releasing

Releasing a new version

  1. Bump version in pyproject.toml and __version__ in src/gaze_py/__init__.py in a PR. Merge to main.
  2. Go to GitHub Actions → Release → Run workflow.
  3. Enter the tag matching the version (e.g. v0.3.0).
  4. Approve the pypi environment gate if configured.
  5. The workflow validates, tags, builds, and publishes automatically.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gaze_py-0.9.0.tar.gz (920.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gaze_py-0.9.0-py3-none-any.whl (160.6 kB view details)

Uploaded Python 3

File details

Details for the file gaze_py-0.9.0.tar.gz.

File metadata

  • Download URL: gaze_py-0.9.0.tar.gz
  • Upload date:
  • Size: 920.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for gaze_py-0.9.0.tar.gz
Algorithm Hash digest
SHA256 4fb8f31b9291dbf909c00e23dd233ceaef46369d8cbc5a564e29338514852049
MD5 995dee2a6408b3322da5fdf05485fe99
BLAKE2b-256 c0810b79c2d71059051b255034df1269c6c685a2af2cde177dffda73e87a7f6f

See more details on using hashes here.

Provenance

The following attestation bundles were made for gaze_py-0.9.0.tar.gz:

Publisher: release.yml on mpeter/gaze-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gaze_py-0.9.0-py3-none-any.whl.

File metadata

  • Download URL: gaze_py-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 160.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for gaze_py-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 035d6591c875879e9e584346978dfd6b884e8baa1a61c6b7deef678f254f4f3a
MD5 e64967aa7e2220a3842bc4acdd5143b7
BLAKE2b-256 6a3843559a22a1022829a7a4c9bf09223fb401a1959c6b6daf6034893040c07b

See more details on using hashes here.

Provenance

The following attestation bundles were made for gaze_py-0.9.0-py3-none-any.whl:

Publisher: release.yml on mpeter/gaze-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.9.3

2 files

0.9.2

2 files

0.9.1

2 files

This release

0.9.0 This release

2 files

0.8.2

2 files

0.8.1

2 files

0.8.0

2 files

0.7.2

2 files

0.7.1

2 files

0.4.1

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page