# Python

> >-

- **Type:** Skill
- **Install:** `agentstack add skill-xobotyi-cc-foundry-python`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [xobotyi](https://agentstack.voostack.com/s/xobotyi)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [xobotyi](https://github.com/xobotyi)
- **Source:** https://github.com/xobotyi/cc-foundry/tree/master/plugins/python/skills/python

## Install

```sh
agentstack add skill-xobotyi-cc-foundry-python
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Python

**Readability counts. Explicit is better than implicit. If your code needs a comment to explain its control flow,
restructure it.**

Python 3.14+ is the baseline. Use modern syntax unconditionally — no backward compatibility with older Python versions
unless the project explicitly requires it.

## References

- **[`${CLAUDE_SKILL_DIR}/references/typing.md`]** — Type annotation patterns, generics, overloads, TypeVar, variance:
  full annotation examples, generic class patterns, Protocol implementation, TypeVar usage
- **[`${CLAUDE_SKILL_DIR}/references/packaging.md`]** — Project layout, pyproject.toml, uv, dependency management:
  pyproject.toml templates, uv workflows, src layout, dependency groups, build backends
- **[`${CLAUDE_SKILL_DIR}/references/modules.md`]** — Module system, imports, namespace packages, `__init__.py`: import
  resolution order, circular import fixes, lazy imports, namespace packages
- **[`${CLAUDE_SKILL_DIR}/references/concurrency.md`]** — asyncio, TaskGroup, cancellation, timeouts, threading interop:
  TaskGroup error handling, timeout scopes, cancellation semantics, to_thread, eager task factory

## Naming

- **Variables, functions, methods** — snake_case: `user_name`, `fetch_data`
- **Classes, type aliases** — PascalCase: `UserService`, `HttpClient`
- **Constants** — UPPER_SNAKE_CASE: `MAX_RETRIES`, `API_BASE_URL`
- **Modules, packages** — snake_case, short: `user_store`, `auth`
- **Private attributes/methods** — `_` prefix: `_internal_cache`, `_validate()`
- **Name-mangled attributes** — `__` prefix: `__secret` (rarely needed)
- **Type variables** — PascalCase, short: `T`, `KT`, `VT`, `ResponseT`
- **Protocols** — PascalCase, `-able`/`-ible` suffix: `Renderable`, `Serializable`

- **Descriptive names.** `user_count` not `n`. Short names (`i`, `x`) only in tiny scopes (comprehensions, simple
  lambdas).
- **No redundant context.** `car.make` not `car.car_make`.
- **Boolean names:** `is_`/`has_`/`can_`/`should_` prefix: `is_valid`, `has_access`.
- **Dunder methods are reserved for the data model.** Never invent custom dunder names.
- **Avoid single-character names** outside loop indices, comprehension variables, and well-established conventions (`f`
  for file, `e` for exception, `k`/`v` for key/value).

## Type Annotations

Python 3.14+ uses modern annotation syntax natively. No `from __future__ import annotations` needed — all annotations
are evaluated lazily by default.

### Core Rules

- **Annotate all public API boundaries** — function signatures, class attributes, module-level variables. Internal code
  often needs fewer annotations; types flow from context.
- **Use built-in generics:** `list[str]`, `dict[str, int]`, `tuple[int, ...]`, `set[float]`. Never import `List`,
  `Dict`, `Tuple`, `Set` from `typing`.
- **Union with `|`:** `str | None`, `int | float`. Never `Optional[X]` or `Union[X, Y]`.
- **`type` statement for aliases:** `type Vector = list[float]`. Not `TypeAlias` annotation.
- **`None` return:** annotate `-> None` on functions that return nothing. Omit return type only on `__init__`.
- **Avoid `Any`** — it disables type checking. Use `object` when you mean "any type but still type-safe." Use `Any` only
  at true interop boundaries with untyped code.

### Generics

- **`type` parameter syntax (3.12+):** `class Stack[T]:` and `def first[T](items: list[T]) -> T:` instead of `TypeVar`
  declarations.
- **Constrained type parameters:** `def process[T: (str, bytes)](data: T) -> T:` for a finite set of allowed types.
- **Bounded type parameters:** `def sort[T: Comparable](items: list[T]) -> list[T]:` for upper-bound constraints.
- **Variance is inferred** from usage in 3.12+ generics. No manual `covariant`/`contravariant` flags needed.

### Protocols (Structural Typing)

- **Prefer protocols over ABCs** when you don't control the implementing types or when structural compatibility is
  sufficient.
- **`@runtime_checkable`** only when you need `isinstance()` checks — it adds overhead and only validates method
  presence, not signatures.
- **Keep protocols small** — one to three methods. A protocol with many methods is a sign you need an ABC or a concrete
  base class.

```python
from typing import Protocol, runtime_checkable

@runtime_checkable
class Renderable(Protocol):
    def render(self) -> str: ...
```

### Callable Types

- **`collections.abc.Callable`** for callable annotations: `Callable[[int, str], bool]`.
- **`ParamSpec`** for decorators that preserve signatures:
  `def decorator[**P, R](fn: Callable[P, R]) -> Callable[P, R]:`.
- **Use `Protocol`** for complex callable signatures with keyword arguments or overloads.

### TypeGuard and TypeIs

- **`TypeIs`** (3.13+) for narrowing that refines the input type:
  `def is_str_list(val: list[object]) -> TypeIs[list[str]]:`.
- **`TypeGuard`** for narrowing where the output type is unrelated to input:
  `def is_valid_config(data: object) -> TypeGuard[Config]:`.

See `${CLAUDE_SKILL_DIR}/references/typing.md` for full annotation patterns, generics, overloads, and variance.

## Data Classes and Structured Data

### dataclasses

- **Use `@dataclass` for data containers** — classes that primarily hold data with minimal behavior.
- **`frozen=True`** for immutable data: `@dataclass(frozen=True)`. Default to frozen unless mutation is required.
- **`slots=True`** for memory efficiency and attribute safety: `@dataclass(slots=True, frozen=True)`.
- **`kw_only=True`** when constructors have more than 3 fields — prevents positional argument ordering bugs.
- **`field(default_factory=list)`** for mutable defaults. Never use mutable default arguments.
- **Post-init processing:** `__post_init__` for derived fields and validation.

```python
@dataclass(frozen=True, slots=True, kw_only=True)
class User:
    name: str
    email: str
    roles: list[str] = field(default_factory=list)
```

### When NOT to Use dataclasses

- **Simple value containers** with 1-2 fields: use `NamedTuple` or plain tuples.
- **Config/settings with validation:** use Pydantic or attrs with validators.
- **Persistence/ORM models:** use the ORM's model base class.

### NamedTuple

- **Use `class` syntax** over functional form: `class Point(NamedTuple): x: float; y: float`.
- NamedTuples are immutable and iterable — useful as dict keys and in destructuring.

## Enums

- **Use `enum.Enum`** for categorical constants. Never use bare strings or ints as pseudo-enums.
- **`enum.StrEnum`** when the enum must interoperate with string APIs (JSON, config keys).
- **`enum.IntEnum`** only when integer interop is mandatory (legacy protocols). Prefer `Enum` otherwise.
- **`@enum.unique`** to prevent duplicate values.
- **Access by value:** `Color(1)`. Access by name: `Color["RED"]`. Iteration: `for c in Color:`.
- **Never subclass enums with members.** Enums with members are final.

```python
from enum import StrEnum, unique

@unique
class Status(StrEnum):
    ACTIVE = "active"
    INACTIVE = "inactive"
    SUSPENDED = "suspended"
```

## Pattern Matching

`match`/`case` (3.10+) is the preferred dispatch mechanism for structural patterns.

- **Use match for structural dispatch** — matching on type, shape, or destructured values. Don't use match as a
  substitute for simple `if`/`elif` chains on a single value.
- **Always include a wildcard `case _:` arm** unless the match is provably exhaustive.
- **Guard clauses** with `if`: `case Point(x, y) if x > 0:`.
- **Use `|` for alternatives:** `case "quit" | "exit" | "q":`.
- **Capture with walrus:** `case {"error": str() as msg}:` captures while matching type.
- **Class patterns** require `__match_args__` or keyword patterns: `case Point(x=0, y=y):`.

```python
match command:
    case {"action": "move", "direction": str() as direction}:
        move(direction)
    case {"action": "attack", "target": str() as target}:
        attack(target)
    case _:
        raise ValueError(f"Unknown command: {command}")
```

## Functions

- **Early return.** Guard clauses first, happy path flat. Reduce nesting.
- **One function, one job.** If the name contains "and", split it.
- **Type-annotate all parameters and return types** on public functions.
- **Default arguments:** immutable values only. Use `None` + conditional for mutable defaults:
  `def f(items: list[int] | None = None):` then `items = items or []` in body. Never `def f(items: list[int] = []):`.
- **`*` to force keyword-only arguments** after positional params: `def connect(host: str, *, port: int = 443):`.
- **`/` to force positional-only** for parameters that callers shouldn't name: `def sqrt(x: float, /) -> float:`.
- **Prefer returning values** over mutating arguments. Functions should be referentially transparent when possible.
- **`None` means absent, not error.** Return `T | None` for optional results. Raise exceptions for errors.

## Decorators

- **Preserve signatures** with `functools.wraps`:
  ```python
  def retry[**P, R](fn: Callable[P, R]) -> Callable[P, R]:
      @functools.wraps(fn)
      def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
          ...
      return wrapper
  ```
- **Decorator order matters.** Decorators apply bottom-up. `@staticmethod` and `@classmethod` must be outermost (topmost
  in source).
- **Parametric decorators** return a decorator: `@retry(attempts=3)` means `retry` returns the actual decorator
  function.
- **Don't over-abstract with decorators.** If the decorator hides important control flow (error handling, transaction
  management), make it explicit instead.

## Context Managers

- **`contextlib.contextmanager`** for simple resource management:
  ```python
  @contextmanager
  def managed_connection(url: str) -> Iterator[Connection]:
      conn = Connection(url)
      try:
          yield conn
      finally:
          conn.close()
  ```
- **Class-based context managers** when state management is complex — implement `__enter__` and `__exit__`.
- **`contextlib.suppress(ExceptionType)`** instead of empty `except: pass`.
- **`contextlib.closing(thing)`** for objects with `.close()` but no `__exit__`.
- **`contextlib.asynccontextmanager`** for async resource management.
- **Always use `with`** for files, locks, database connections, and any resource that needs deterministic cleanup.

## Generators and Iterators

- **Generators for lazy sequences.** Use `yield` to produce values on demand instead of building full lists in memory.
- **Generator expressions** over list comprehensions when the result is iterated only once:
  `sum(x * x for x in range(1000))`.
- **`yield from`** to delegate to sub-generators — preserves `.send()`, `.throw()`, `.close()` protocol.
- **`itertools`** for composition: `chain`, `islice`, `groupby`, `batched` (3.12+), `pairwise` (3.10+).
- **Annotate generators:** `def gen() -> Iterator[int]:` for simple generators,
  `Generator[YieldType, SendType, ReturnType]` when using `.send()`.
- **Never exhaust a generator twice.** Generators are single-pass. If you need multiple passes, materialize to a list or
  use `itertools.tee`.

## Comprehensions

- **List/dict/set comprehensions** for simple transforms: `[x.name for x in users if x.active]`.
- **One level of nesting maximum.** Two nested `for` clauses are the absolute limit. Beyond that, extract to a function.
- **Don't use comprehensions for side effects.** `[print(x) for x in items]` is wrong — use a `for` loop.
- **Walrus operator in comprehensions** for compute-once-filter-and-use:
  `[y for x in data if (y := transform(x)) is not None]`.
- **Dict comprehensions** for key transformations: `{k.lower(): v for k, v in headers.items()}`.

## Exception Handling

- **Be specific.** Catch the narrowest exception type: `except ValueError:` not `except Exception:`.
- **Never bare `except:`.** It catches `SystemExit`, `KeyboardInterrupt`, and `GeneratorExit`. At minimum use
  `except Exception:`.
- **`except* ExceptionGroup`** (3.11+) for handling multiple concurrent exceptions from `TaskGroup` and similar.
- **Wrap with context.** `raise AppError("context") from err` chains the original cause.
- **Don't use exceptions for flow control.** `if key in dict:` not `try: dict[key] except KeyError:` (unless the miss is
  rare and lookup is expensive).
- **Custom exceptions** inherit from a project-specific base that extends `Exception`:
  ```python
  class AppError(Exception): ...
  class NotFoundError(AppError): ...
  class ValidationError(AppError): ...
  ```
- **Error strings:** lowercase, no trailing punctuation. They compose in chains: `"parse config: invalid format"`.
- **`else` clause** runs only when no exception was raised — use for code that should execute on success but isn't part
  of the `try` body.
- **`finally`** for unconditional cleanup — prefer context managers when possible.
- **Exception groups (3.11+):** use `ExceptionGroup` to bundle multiple errors. Handle with `except*` which matches by
  type and re-raises unhandled exceptions.
- **Add notes with `.add_note()`** (3.11+) to attach context without creating new exception types.

## Strings

- **f-strings** for interpolation. Never `%` formatting or `.format()` in new code.
- **f-string expressions must be simple.** No function calls with multiple arguments, no nested f-strings, no complex
  expressions. Extract to a variable first.
- **`str.removeprefix()` / `str.removesuffix()`** (3.9+) over slicing.
- **Triple-quoted strings** for multiline. Use `textwrap.dedent` when indentation matters.
- **`"".join(parts)`** for building strings in loops — never `+=` in a loop.
- **Raw strings `r"..."`** for regex patterns and Windows paths.

## Pathlib

- **`pathlib.Path`** for all filesystem operations. Never `os.path` in new code.
- **`/` operator** for path joining: `base / "subdir" / "file.txt"`.
- **Common operations:** `path.exists()`, `path.is_file()`, `path.is_dir()`, `path.read_text()`, `path.write_text()`,
  `path.mkdir(parents=True, exist_ok=True)`, `path.iterdir()`, `path.glob("*.py")`, `path.rglob("**/*.py")`.
- **`path.resolve()`** for absolute paths. `path.relative_to(base)` for relative paths.
- **Accept `str | Path`** in public APIs, convert to `Path` internally.

## Imports

- **Absolute imports** by default: `from mypackage.utils import helper`.
- **Relative imports** only within packages for tightly coupled modules: `from .models import User`.
- **Import grouping** (separated by blank lines):
  1. Standard library (`import os`, `from pathlib import Path`)
  2. Third-party (`import httpx`, `from pydantic import BaseModel`)
  3. Local (`from myapp.models import User`)
- **Import specific names:** `from collections import defaultdict` not `import collections` (unless you use many names
  from the module).
- **Never `from module import *`** — pollutes namespace, breaks type checkers, hides dependencies.
- **`if TYPE_CHECKING:` block** for imports used only in annotations — avoids circular imports and runtime overhead. In
  3.14+ with lazy annotations, this is less necessary but still useful for avoiding circular import side effects.
- **Lazy imports** in function bodies when a top-level import would create a circular dependency or when the import is
  expensive and rarely needed.

## Classes

### Slots

- **Always use `__slots__`** on classes that will have many instances — prevents `__dict__` creation, saves memory,
  catches typos in attribute names.
- **`@dataclass(slots=True)`** adds slots automatically.
- **Slots and inheritance:** every class in the hierarchy must declare `__slots__`. Missing slots on a parent
  reintroduces `__dict__`.

### Dunder Methods

- **`__repr__`** on every class — must be unambiguous: `def __repr__(self) -> str: return f"User(name={self.name!r})"`.
- **`__str__`** only when a human-readable form differs from repr.
- **`__eq__` and `__hash__`** — if you define `__eq__`, define `__hash__` too (or set `__hash__ = None` to make
  unhashable). Mutable objects should not be hashable.
- **`__bool__`** — define when truthiness of instances has meaningful sem

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [xobotyi](https://github.com/xobotyi)
- **Source:** [xobotyi/cc-foundry](https://github.com/xobotyi/cc-foundry)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** yes
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-xobotyi-cc-foundry-python
- Seller: https://agentstack.voostack.com/s/xobotyi
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
