Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Pythurion

Pythurion

Pythurion helps coding agents write Python you’ll want to maintain: correct, minimal, and idiomatic.

TL;DR;

An always-on Python engineering discipline for coding agents:

  1. inspect the real context;
  2. establish the behavioral contract;
  3. for performance work, locate the measured cause and define the budget and guardrails;
  4. reproduce failures before fixing them;
  5. solve the shared cause with the smallest coherent mechanism;
  6. avoid speculative abstractions and unrelated churn;
  7. verify every claim with focused checks and observed evidence.

Install

npx skills add -g arlegotin/pythurion

Pythurion is designed to activate automatically whenever your agent works with Python code, tests, project configuration, or Python performance work. It favors modern Python 3.12+ practices, the smallest design that fits, explicit risk boundaries, representative measurement, and executable evidence.

Before / after

Smaller design

Use a function until state or lifecycle earns a class.

# Before
class Slugifier:
    def __call__(self, text: str) -> str:
        return text.lower().replace(" ", "-")


slugify = Slugifier()

# After
def slugify(text: str) -> str:
    return text.lower().replace(" ", "-")

Measured performance

Collapse repeated scans

When rows are a stable tuple containing only exact built-in str keys and int amounts, aggregate once rather than running a full scan for each input row. This preserves integer totals and first-seen category order.

# Before: rescans every row for every input row
def totals_by_category(
    rows: tuple[tuple[str, int], ...],
) -> dict[str, int]:
    return {
        category: sum(
            amount
            for row_category, amount in rows
            if row_category == category
        )
        for category, _ in rows
    }


# After: one pass
def totals_by_category(
    rows: tuple[tuple[str, int], ...],
) -> dict[str, int]:
    totals: dict[str, int] = {}
    for category, amount in rows:
        totals[category] = totals.get(category, 0) + amount
    return totals

This changes repeated full scans into one pass. Verify the gain at representative row counts and keep the rewrite only when it meets the target budget.

Stop when the answer is known

When values is a stable tuple containing only exact built-in integers and only the first even value matters, stop after that match instead of building every result.

# Before: evaluates every value and materializes every match
def first_even(values: tuple[int, ...]) -> int | None:
    matches = [value for value in values if value % 2 == 0]
    return matches[0] if matches else None


# After: evaluates only through the first match
def first_even(values: tuple[int, ...]) -> int | None:
    return next((value for value in values if value % 2 == 0), None)

Measure representative input sizes and match positions. Use this pattern only when evaluating later items is not part of the contract.

Honest types and invariants

Accept the weakest useful interface and enforce equal lengths.

from collections.abc import Iterable

# Before
def prices(names: list[str], values: list[int]) -> dict[str, int]:
    return dict(zip(names, values))

# After
def prices(names: Iterable[str], values: Iterable[int]) -> dict[str, int]:
    return dict(zip(names, values, strict=True))

Precise errors

Catch only the failure you can translate, and preserve its cause.

from pathlib import Path

# Before
def load_config(path: Path) -> str | None:
    try:
        return path.read_text()
    except Exception:
        return None

# After
class ConfigError(RuntimeError):
    pass


def load_config(path: Path) -> str:
    try:
        return path.read_text()
    except OSError as error:
        raise ConfigError(f"cannot read {path}") from error

Safe SQL and resource ownership

Parameterize input and make both transaction and connection lifetimes explicit.

from contextlib import closing
import sqlite3

# Before
def add_label(path: str, label: str) -> None:
    connection = sqlite3.connect(path)
    connection.execute(f"INSERT INTO labels(value) VALUES ('{label}')")
    connection.commit()

# After
def add_label(path: str, label: str) -> None:
    with closing(sqlite3.connect(path)) as connection:
        with connection:
            connection.execute(
                "INSERT INTO labels(value) VALUES (?)",
                (label,),
            )

Structured concurrency

Own a small fail-together task set so errors and cancellation clean up the group.

import asyncio

# Before
async def refresh() -> None:
    asyncio.create_task(refresh_users())
    asyncio.create_task(refresh_orders())

# After
async def refresh() -> None:
    async with asyncio.TaskGroup() as group:
        group.create_task(refresh_users())
        group.create_task(refresh_orders())

Semantic correctness

Use aware UTC instants for persisted or cross-host time.

from datetime import UTC, datetime, timedelta

# Before
expires_at = datetime.now() + timedelta(minutes=5)

# After
expires_at = datetime.now(UTC) + timedelta(minutes=5)

About

Pythurion helps coding agents write Python you’ll want to maintain: correct, minimal, and idiomatic

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors