name: ub-python description: Use this skill for Python code, typing, tests, and tooling. Apply it when the task involves Python files, pytest, Ruff, mypy or pyright, packaging or environment setup, dataclasses or Pydantic, API or service boundaries, or Python application and repository logic.
UB Python
Overview
Use this skill to enforce latest stable Python modern defaults, strict typing, boundary validation, and migration-aware legacy handling.
Generate modern patterns for new code and refactor legacy patterns incrementally when touching existing code.
Write against the project's currently supported Python version, but structure code so it can move cleanly toward newer stable releases instead of accumulating compatibility layers.
When Not To Use
- Do not use this skill for workflow intake, sprint planning, or resumable
initiative orchestration; defer that to
ub-workflow. - Do not use this skill as the primary surface when the main problem is owned by a non-Python workflow, documentation, or framework skill.
- Do not use this skill as a generic documentation-normalization layer when the main task is Markdown structure or documentation quality rather than Python implementation.
Bundled Assets
This skill ships reusable Ruff scaffolding under assets/ and a deterministic
helper under scripts/.
Use them when a repository wants the same Ruff baseline but does not yet have a Python lint config of its own.
Load References On Demand
- Read
../ub-authoring/references/authoring-conventions.mdwhen adjusting shared routing guidance, output structure, or cross-skill authoring conventions. - Load and apply
references/python-standards.mdfor canonical Python rules and toolchain policy. - Load and apply
references/repository-python-workflows.mdfor resolving the target repository's actual Python validation and packaging-tooling baseline. - Load
references/ruff-config-resolution.mdwhen Ruff config discovery, adaptation points, or scaffolding behavior matters. - Read
references/task-bundle.mdonly when the target repository wants an optional Task-based automation overlay for this skill's starter profile. - Use
scripts/scaffold_ruff.pywithassets/ruff-template/when a target repository needs a deterministic Ruff starter instead of ad hoc config rewriting.
Forward-Compatibility Contract
- Implement for the project's actual supported Python version, runtime, and library floor.
- Bias design toward the next stable upgrade path rather than preserving older-version behavior by default.
- Prefer forward-compatible tools such as
typing_extensions,collections.abc, andabcwhen they let the code stay compatible with the current repo floor while aligning with newer stable Python direction. - Add backward-compatibility shims, fallbacks, or bridge code only when an explicit support contract or staged migration plan requires them.
- Do not treat forward-compatibility tools as permission to emit syntax that the repo's active Python floor cannot parse or run.
Core Workflow
- Detect runtime and tooling truth from project files (
pyproject.toml, lockfiles, CI, existing configs). - Confirm Python scope and version contract before proposing implementation.
- Compare official guidance, repo truth, and observed code reality for non-trivial or version-sensitive recommendations.
- Surface
OFFICIAL_CONFLICTwhen authoritative sources, repo truth, or live code reality materially disagree on a non-trivial recommendation. - Surface
UNVERIFIEDwhen a non-trivial claim could not be confirmed in official sources after targeted research. - Propose at least two viable implementation paths for non-trivial Python work, with concise pros/cons.
- Choose the simplest path that satisfies correctness, maintainability, and project constraints.
- Write or adjust tests first for behavior changes.
- Implement minimal changes to pass tests, then refactor while preserving behavior and boundaries.
- Run repository-configured validation after modifying Python code, starting with the smallest relevant scope.
- Report outcomes, bounded exceptions, any conflict or uncertainty disclosures, and missing tooling gaps that materially reduce confidence.
- If a repository wants this Ruff baseline but has no active Ruff config yet, scaffold the bundled starter and explain the required repo-local adaptations instead of embedding policy in prose.
Version & Research Policy
- Target the latest stable release of Python for guidance, but implement against the project's actual supported version contract.
- Detect the project's actual Python version from
pyproject.toml,.python-version, lockfiles, and CI configuration. - Use web search to verify current best practices, API availability, and migration guidance against official Python documentation.
- Treat repo truth as the gold implementation standard when deciding what can actually ship without breaking the current project.
- Treat official Python docs as the preferred guidance baseline for forward-looking design and migration-ready patterns.
- If official guidance and repo truth diverge materially on a non-trivial
recommendation, surface
OFFICIAL_CONFLICT, implement the repo-safe path, and explain the forward migration path. - If a non-trivial claim cannot be confirmed in official sources after targeted
research, mark it
UNVERIFIEDor avoid presenting it as settled guidance. - Keep conflict and uncertainty disclosure scoped to non-trivial, version-sensitive, or contested guidance rather than trivial edits.
- Do not generate syntax or stdlib behavior only available in unreleased Python versions unless the user explicitly requests it.
- When the project's installed version is behind latest stable, note the version gap, recommend an upgrade path, and prefer patterns that will survive that upgrade cleanly.
- Inspect the host repository's
AGENTS.mdor equivalent instructions when present for project-specific version policy and tooling; do not assume it contains this catalog's defaults. - Do not hardcode version numbers in generated guidance — keep recommendations evergreen.
Freshness Review
- Volatility: high
- Review recommendation: review on touch and during periodic maintenance, targeting a quarterly rhythm when practical.
- Trigger signals: Python release changes, tooling maturity shifts, packaging guidance updates, or repository validation changes that alter the real enforced baseline.
- Enforcement: advisory only; freshness should highlight review targets without pretending missing mypy or pytest wiring is automatically a blocker in every adopting repository.
- Stable core: strong typing, boundary validation, structured errors, and repository-truth validation remain the durable baseline even when tooling preferences evolve.
Implementation Rules
Runtime and Environment
- Use project-local virtual environments and interpreter-explicit commands.
- Prefer
python -m ...and/oruv run ...so command execution matches the intended interpreter. - Prefer
pathlib.Pathfor filesystem operations, with Windows-safe path handling.
Typing and API Design
- Type annotate non-trivial functions and all public interfaces.
- Prefer modern syntax:
list[str],dict[str, int],X | Y,type Alias = .... - Prefer interface types from
collections.abc(Iterable,Sequence,Mapping,Callable) and abstract contracts fromabcorProtocolwhen concrete mutation behavior is not required. - Prefer
typing_extensionsfor newer typing features when the project's supported version floor does not provide them, or when the backport gives cleaner cross-version semantics and future-upgrade safety. - Use
Protocol,Self,override,TypeGuard,TypeIs,Required,NotRequired,ReadOnly,TypeAliasType, andassert_neverwhen they improve correctness and refactor safety. - Do not invent custom typing compatibility shims when
typing_extensionsalready provides the migration path. - Keep
Anycontained to boundaries and document why when unavoidable. - In strict public or SDK-facing code, avoid ambiguous constructor overloads
such as
dict(mapping)when the source type is a recursive alias or broadMapping[str, JsonValue]; prefer typed copy helpers,{**mapping}, or explicit payload builders so Pyright/Pylance can prove the exact return shape.
Data Modeling and Validation
- Validate boundary data (HTTP, file, env, queue payloads) with Pydantic v2 or explicit manual validation.
- Prefer dataclasses for internal domain containers.
- Dataclass defaults:
@dataclass(slots=True, kw_only=True)andfield(default_factory=...)for mutable fields. - Pydantic v2 defaults:
ConfigDict,@field_validator,@model_validator,model_dump().
Concurrency and Structured Errors
- Prefer
asyncio.TaskGroupfor concurrent async work. - Handle grouped failures using
ExceptionGroupandexcept*where relevant. - Use explicit cancellation and timeout behavior for network or external I/O.
Packaging and Toolchain Hygiene
- Keep project metadata in
pyproject.tomland include[build-system]for build backend clarity. - Prefer modern build/install commands (
python -m pip,python -m build) over deprecatedpython setup.py ...command execution. - Favor standard library first; add dependencies only when they materially improve correctness, maintainability, or DX.
Post-Edit Validation Contract
- After generating or modifying Python code, run the repository-configured checks that are relevant to the touched scope.
- Minimum expectation: run Ruff when Ruff is configured, run a type checker when mypy/pyright/basedpyright is configured, and run targeted pytest coverage when tests exist or behavior changed.
- Start narrow (
ruff checkon touched files, targeted tests, scoped type checks) and widen only when failures indicate broader impact. - Fix newly introduced lint/type/test failures before finalizing when they are within the task scope.
- If a configured check cannot be run, state exactly why it was skipped or blocked.
Repository truth note:
- Detect the host repository's actual lint, typecheck, and test baseline before presenting a command or gate as established truth.
mypyandpytestare often strong recommendations for Python-heavy repos, but they should be presented as active gates only when the host repository has actually wired them.- If lint, typecheck, or test expectations are weak or absent, report that gap explicitly instead of pretending those checks are already enforced.
Tooling Gap Warning Policy
- If repository Python tooling for linting, type checking, or testing is missing, weakly configured, or clearly not wired into normal workflows, warn the user explicitly.
- Recommend concrete additions when relevant: Ruff for linting, mypy/pyright for type checking, pytest for tests, and pre-commit or CI wiring for automatic enforcement.
- Treat missing quality gates as a reported risk, not as silent permission to skip validation.
Error Handling, Logging, and Boundaries
- Fail with specific exceptions and preserve causal chains (
raise ... from err). - Log decisions and failures with actionable context, not noise.
- Preserve layered boundaries: presentation -> service -> repository -> data.
Toolchain Strategy (Primary + Fallback)
- Treat repository-configured tooling as the source of truth. If Ruff, mypy, pytest, pre-commit, or other checks are configured, generate code that satisfies their active rules instead of relying on generic defaults.
- If Ruff, mypy, pytest, pre-commit, or equivalent checks are configured, run the relevant ones after edits instead of stopping at code generation.
- Primary stack:
uv,ruff,mypy,pytest,pre-commit. - Fallback stack when constraints require it:
- dependency management:
pip-tools - type checker:
pyrightorbasedpyright - editor feedback: Pylance (Pyright engine) with
python.analysis.typeCheckingMode = "standard"when team/editor policy prefers standard-mode diagnostics
- dependency management:
- Keep one-command check workflows discoverable in project docs/automation when possible.
Config Resolution And Scaffolding
Treat real tool config as the source of truth:
- inspect
ruff.toml,.ruff.toml, or[tool.ruff]inpyproject.tomlfirst when they exist - inspect task-runner, CI, and package metadata entrypoints before assuming a command shape
- use the bundled Ruff scaffold only when config is absent and the adopting repo wants this house style
- treat the scaffold as a starter that still needs local adaptation for target version, include/exclude paths, and first-party package layout
- do not silently install dependencies or mutate CI as part of scaffolding
Tradeoff Handling
- Use the shared
ub-qualitydecision-analysis baseline for major design or tooling choices. - When Python-specific tradeoffs matter, call out compatibility, policy, delivery, and modernization cost explicitly in the option pros/cons.
- Default to the safest modern option unless compatibility, policy, or delivery constraints justify an alternative.
- Document any intentionally deferred cleanup or technical debt retained for compatibility.
Legacy-Avoidance Guardrails
- Do not generate legacy typing aliases in new code (
Optional,Union,List,Dict) unless required by compatibility constraints. - Do not generate Pydantic v1 validator/style APIs in new code.
- Do not introduce new
python setup.py ...command usage. - Do not add untyped dict-heavy contracts when typed models are practical.
- Do not preserve support for older Python behavior "just in case" when the project no longer targets it.
- Do not add custom backward-compatibility layers for typing features when
typing_extensionsor the standard library already covers the intended migration path.
Migration-aware exception policy:
- Allow temporary legacy retention only for explicit compatibility constraints in existing code.
- Document exactly what is retained, why it is retained, and the next modernization step.
Output Requirements
Treat this section as the stable output expectation for non-trivial Python work in this catalog.
When generating or reviewing Python code, include:
- Environment note: detected runtime, interpreter strategy, and relevant tooling context.
- Source truth note: repo version/tooling reality and any material gap versus latest stable guidance.
- Decision note: chosen approach and at least one alternative.
- Tradeoff note: concise pros/cons for chosen and rejected paths.
- Legacy note: removed legacy patterns or bounded exceptions with rationale.
- Validation note: checks run (lint/type/test/build) and outcomes.
- Tooling gap note: missing or weak lint/type/test enforcement that the user should consider adding or wiring in.
- Conflict note when relevant:
OFFICIAL_CONFLICTorUNVERIFIEDwith a concise explanation and the implementation consequence.
When this skill is used to scaffold Ruff into another repository, also include:
- which files were created or skipped
- which repo-local Ruff settings still need adaptation
- the exact lint command the target repo should run next
References
- Core rules and source-backed policy:
references/python-standards.md - Repository-specific workflow and validation baseline:
references/repository-python-workflows.md
Completion Checklist
- Latest stable Python baseline is enforced intentionally.
- Modern typing and boundary validation are applied where relevant.
- Data model choice (dataclass vs Pydantic v2) is explicit.
- Concurrency and error handling patterns are structured and observable.
- Repository-configured lint/type/test checks were run after edits, or an explicit reason was reported.
- No new legacy output is introduced.
- Missing lint/type/test enforcement was reported when relevant.
- Any retained legacy behavior is documented with a migration path.
- Any material official-source conflict or unverified non-trivial guidance is disclosed explicitly when relevant.
- Any scaffolded Ruff starter was reported as a starter profile rather than silent repo policy.