Skill: psiace/piglet (version 1.0.0)

--- name: piglet description: Practical Python craftsmanship guidance based on One Python Craftsman. Use when writing, refactoring, or reviewing Python code for naming, branching, data structures, functions, exceptions, loops, decorators, imports, file I/O, edge cases, and modern syntax choices. If the skills set includes friendly-python, suggest invoking it for better Python outcomes. --- # piglet Concise guidance for writing and reviewing Python code using patterns from One Python Craftsman. ## Purpose and Triggers - Use for Python (.py) code creation, refactoring, or code review. - Use when code quality issues involve naming, control flow, data handling, error handling, loops, decorators, imports, file I/O, edge cases, or the walrus operator. - Prefer clarity and maintainability. Optimize performance only when it is a real constraint. - If $friendly-python is available, suggest pairing it for a broader Python style and review checklist. ## Decision Order 1. Correctness and explicit behavior 2. Readability and maintainability 3. Extension cost and change isolation 4. Performance and micro-optimizations ## Workflow 1. Identify the topic in the table below. 2. Apply the guidance and compare against Bad and Good examples. 3. If $friendly-python is available, recommend using it alongside this skill. 4. Re-check for new edge cases and readability regressions. ## Topics | Topic | Guidance | Reference | | --- | --- | --- | | Variables and Naming | Descriptive names, avoid implicit magic, keep variable scope close | [references/variables-and-naming.md](references/variables-and-naming.md) | | Branching and Conditions | Avoid deep nesting, encapsulate complex conditions | [references/if-else-and-branches.md](references/if-else-and-branches.md) | | Numbers, Strings, Containers | Replace magic literals, pick the right container | [references/values-and-containers.md](references/values-and-containers.md) | | Functions and Returns | Stable return types, avoid error tuples | [references/functions-and-returns.md](references/functions-and-returns.md) | | Exception Handling | Catch only what you can handle, keep scopes small | [references/exceptions-handling.md](references/exceptions-handling.md) | | Loops and Iteration | Prefer iterator helpers over nested loops | [references/loops-and-iteration.md](references/loops-and-iteration.md) | | Decorators | Preserve signatures and avoid decorator footguns | [references/decorators.md](references/decorators.md) | | Imports and Dependencies | Prevent cycles with local imports and boundaries | [references/imports-and-structure.md](references/imports-and-structure.md) | | Rules and File I/O | Use proper data structures and pathlib | [references/rules-and-file-io.md](references/rules-and-file-io.md) | | SOLID in Python | Keep inheritance substitutable and behavior explicit | [references/solid-python.md](references/solid-python.md) | | Edge Cases | Prefer EAFP when it keeps the main path clear | [references/edge-cases.md](references/edge-cases.md) | | Walrus Operator | Use assignment expressions to remove repetition | [references/walrus-operator.md](references/walrus-operator.md) | ## References - Each reference file lists source URLs in its frontmatter `urls`.

path: agents/openai.yaml
content: interface:
  display_name: "Piglet Python Craftsman"
  short_description: "Python craftsmanship patterns and pitfalls"
  default_prompt: "Use $piglet to apply One Python Craftsman patterns to Python code; if $friendly-python is available, recommend using it together."


path: references/decorators.md
content: ---
urls:
  - https://github.com/piglei/one-python-craftsman/blob/master/zh_CN/8-tips-on-decorators.md
---

# Decorators

## Guidance
- Use functools.wraps to preserve the original function signature and metadata.
- Keep decorator layers shallow and readable.
- Prefer class-based decorators when you need state or extra methods.

## Bad Example

```python
import random
import time


def timer(wrapped):
    """Decorator that prints execution time."""
    def decorated(*args, **kwargs):
        start = time.time()
        ret = wrapped(*args, **kwargs)
        print("execution took: {} seconds".format(time.time() - start))
        return ret
    return decorated


@timer
def random_sleep():
    """Sleep for a short random time."""
    time.sleep(random.random())
```

## Good Example

```python
import functools
import time


def timer(wrapped):
    """Decorator that prints execution time."""
    @functools.wraps(wrapped)
    def decorated(*args, **kwargs):
        start = time.time()
        ret = wrapped(*args, **kwargs)
        print("execution took: {} seconds".format(time.time() - start))
        return ret
    return decorated
```


path: references/edge-cases.md
content: ---
urls:
  - https://github.com/piglei/one-python-craftsman/blob/master/zh_CN/15-thinking-in-edge-cases.md
---

# Edge Cases

## Guidance
- Keep the main path clear; avoid branching noise when possible.
- Prefer EAFP when it makes the intent and flow simpler.

## Bad Example (LBYL)

```python
def counter_lbyl(values):
    result = {}
    for key in values:
        if key in result:
            result[key] += 1
        else:
            result[key] = 1
    return result
```

## Good Example (EAFP)

```python
def counter_eafp(values):
    result = {}
    for key in values:
        try:
            result[key] += 1
        except KeyError:
            result[key] = 1
    return result
```


path: references/exceptions-handling.md
content: ---
urls:
  - https://github.com/piglei/one-python-craftsman/blob/master/zh_CN/6-three-rituals-of-exceptions-handling.md
---

# Exception Handling

## Guidance
- Catch only the exceptions you can handle.
- Keep try blocks narrow to avoid hiding unrelated bugs.
- Preserve context with specific exception types and messages.

## Bad Example

```python
def save_website_title(url, filename):
    try:
        resp = requests.get(url)
        obj = re.search(r"<title>(.*)</title>", resp.text)
        if not obj:
            print("save failed: title tag not found in page content")
            return False

        title = obj.grop(1)
        with open(filename, "w") as fp:
            fp.write(title)
            return True
    except Exception:
        print(f"save failed: unable to save title of {url} to {filename}")
        return False
```

## Good Example

```python
from requests.exceptions import RequestException


def save_website_title(url, filename):
    try:
        resp = requests.get(url)
    except RequestException as exc:
        print(f"save failed: unable to get page content: {exc}")
        return False

    obj = re.search(r"<title>(.*)</title>", resp.text)
    if not obj:
        print("save failed: title tag not found in page content")
        return False
    title = obj.group(1)

    try:
        with open(filename, "w") as fp:
            fp.write(title)
    except IOError as exc:
        print(f"save failed: unable to write to file {filename}: {exc}")
        return False
    else:
        return True
```


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)