Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .claude/commands/investigate-test-failure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
allowed-tools: Bash(python3:*), Bash(cargo run:*), Read, Grep, Glob, Bash(git add:*), Bash(git commit:*)
---

# Investigate Test Failure

Investigate why a specific test is failing and determine if it can be fixed or needs an issue.

## Arguments
- `$ARGUMENTS`: Failed test identifier (e.g., `test_inspect.TestGetSourceBase.test_getsource_reload`)

## Steps

1. **Analyze failure cause**
- Read the test code
- Analyze failure message/traceback
- Check related RustPython code

2. **Verify behavior in CPython**
- Run the test with `python3 -m unittest` to confirm expected behavior
- Document the expected output

3. **Determine fix feasibility**
- **Simple fix** (import issues, small logic bugs): Fix and commit
- **Complex fix** (major unimplemented features): Collect issue info and report to user

4. **For complex issues - Collect issue information**
Following `.github/ISSUE_TEMPLATE/report-incompatibility.md` format:

- **Feature**: Description of missing/broken Python feature
- **Minimal reproduction code**: Smallest code that reproduces the issue
- **CPython behavior**: Result when running with python3
- **RustPython behavior**: Result when running with cargo run
- **Python Documentation link**: Link to relevant CPython docs

Report collected information to the user. Issue creation is done only upon user request.

Example issue creation command:
```
gh issue create --template report-incompatibility.md --title "..." --body "..."
```
33 changes: 33 additions & 0 deletions .claude/commands/upgrade-pylib-next.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
allowed-tools: Skill(upgrade-pylib), Bash(gh pr list:*)
---

# Upgrade Next Python Library

Find the next Python library module ready for upgrade and run `/upgrade-pylib` for it.

## Current TODO Status

!`cargo run --release -- scripts/update_lib todo 2>/dev/null`

## Open Upgrade PRs

!`gh pr list --search "Update in:title" --json number,title --template '{{range .}}#{{.number}} {{.title}}{{"\n"}}{{end}}'`

## Instructions

From the TODO list above, find modules matching these patterns (in priority order):

1. `[ ] [no deps]` - Modules with no dependencies (can be upgraded immediately)
2. `[ ] [0/n]` - Modules where all dependencies are already upgraded (e.g., `[0/3]`, `[0/5]`)

These patterns indicate modules that are ready to upgrade without blocking dependencies.

**Important**: Skip any modules that already have an open PR in the "Open Upgrade PRs" list above.

**After identifying a suitable module**, run:
```
/upgrade-pylib <module_name>
```

If no modules match these criteria, inform the user that all eligible modules have dependencies that need to be upgraded first.
83 changes: 51 additions & 32 deletions .claude/commands/upgrade-pylib.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
allowed-tools: Bash(git add:*), Bash(git commit:*), Bash(python3 scripts/update_lib quick:*), Bash(python3 scripts/update_lib auto-mark:*)
---

# Upgrade Python Library from CPython

Upgrade a Python standard library module from CPython to RustPython.
Expand All @@ -23,24 +27,19 @@ This helps improve the tooling for future upgrades.

## Steps

1. **Delete existing library in Lib/**
- If `Lib/$ARGUMENTS.py` exists, delete it
- If `Lib/$ARGUMENTS/` directory exists, delete it

2. **Copy from cpython/Lib/**
- If `cpython/Lib/$ARGUMENTS.py` exists, copy it to `Lib/$ARGUMENTS.py`
- If `cpython/Lib/$ARGUMENTS/` directory exists, copy it to `Lib/$ARGUMENTS/`

3. **Upgrade tests (quick upgrade with update_lib)**
- Run: `python3 scripts/update_lib quick cpython/Lib/test/test_$ARGUMENTS.py` (single file)
- Or: `python3 scripts/update_lib quick cpython/Lib/test/test_$ARGUMENTS/` (directory)
1. **Run quick upgrade with update_lib**
- Run: `python3 scripts/update_lib quick $ARGUMENTS` (module name)
- Or: `python3 scripts/update_lib quick cpython/Lib/$ARGUMENTS.py` (library file path)
- Or: `python3 scripts/update_lib quick cpython/Lib/$ARGUMENTS/` (library directory path)
- This will:
- Copy library files (delete existing `Lib/$ARGUMENTS.py` or `Lib/$ARGUMENTS/`, then copy from `cpython/Lib/`)
- Patch test files preserving existing RustPython markers
- Run tests and auto-mark new test failures (not regressions)
- Remove `@unittest.expectedFailure` from tests that now pass
- **Handle warnings**: If you see warnings like `WARNING: TestCFoo does not exist in remote file`, it means the class structure changed and markers couldn't be transferred automatically. These need to be manually restored in step 4 or added in step 5.
- Create a git commit with the changes
- **Handle warnings**: If you see warnings like `WARNING: TestCFoo does not exist in remote file`, it means the class structure changed and markers couldn't be transferred automatically. These need to be manually restored in step 2 or added in step 3.

4. **Review git diff and restore RUSTPYTHON-specific changes**
2. **Review git diff and restore RUSTPYTHON-specific changes**
- Run `git diff Lib/test/test_$ARGUMENTS` to review all changes
- **Only restore changes that have explicit `RUSTPYTHON` comments**. Look for:
- `# XXX: RUSTPYTHON` or `# XXX RUSTPYTHON` - Comments marking RustPython-specific code modifications
Expand All @@ -49,13 +48,37 @@ This helps improve the tooling for future upgrades.
- **Do NOT restore other diff changes** - these are likely upstream CPython changes, not RustPython-specific modifications
- When restoring, preserve the original context and formatting

5. **Verify tests**
- Run: `cargo run --release -- -m test test_$ARGUMENTS -v`
- The `-v` flag shows detailed output to identify which tests fail and why
- For each new failure, add appropriate markers based on the failure type:
- **Test assertion failure** → `@unittest.expectedFailure` with `# TODO: RUSTPYTHON` comment
- **Panic/crash** → `@unittest.skip("TODO: RUSTPYTHON; <panic message>")`
- **Class-specific markers**: If a test fails only in the C implementation (TestCFoo) but passes in the Python implementation (TestPyFoo), or vice versa, add the marker to the specific subclass, not the base class:
3. **Investigate test failures with subagent**
- First, run tests to collect the list of failures:
```
cargo run --release -- -m unittest test.$ARGUMENTS -v 2>&1 | grep -E "^(FAIL|ERROR):"
```
- For each failure, use the Task tool with `general-purpose` subagent to investigate:
- Subagent should follow the `/investigate-test-failure` skill workflow
- Pass the failed test identifier as the argument (e.g., `test_inspect.TestGetSourceBase.test_getsource_reload`)
- If subagent can fix the issue easily: fix and commit
- If complex issue: subagent collects issue info and reports back (issue creation on user request only)
- Using subagent prevents context pollution in the main conversation

4. **Mark remaining test failures with auto-mark**
- Run: `python3 scripts/update_lib auto-mark Lib/test/test_$ARGUMENTS.py --mark-failure`
- Or for directory: `python3 scripts/update_lib auto-mark Lib/test/test_$ARGUMENTS/ --mark-failure`
- This will:
- Run tests and mark ALL failing tests with `@unittest.expectedFailure`
- Remove `@unittest.expectedFailure` from tests that now pass
- **Note**: The `--mark-failure` flag marks all failures including regressions. Review the changes before committing.

5. **Handle panics manually**
- If any tests cause panics/crashes (not just assertion failures), they need `@unittest.skip` instead:
```python
@unittest.skip("TODO: RUSTPYTHON; panics with 'index out of bounds'")
def test_crashes(self):
...
```
- auto-mark cannot detect panics automatically - check the test output for crash messages

6. **Handle class-specific failures**
- If a test fails only in the C implementation (TestCFoo) but passes in the Python implementation (TestPyFoo), or vice versa, move the marker to the specific subclass:
```python
# Base class - no marker here
class TestFoo:
Expand All @@ -70,25 +93,21 @@ This helps improve the tooling for future upgrades.
def test_something(self):
return super().test_something()
```
- **New tests from CPython**: The upgrade may bring in entirely new tests that didn't exist before. These won't have any RUSTPYTHON markers in the diff - they just need to be tested and marked if they fail.
- Example markers:
```python
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_something(self):
...

# TODO: RUSTPYTHON
@unittest.skip("TODO: RUSTPYTHON; panics with 'index out of bounds'")
def test_crashes(self):
...
```
7. **Commit the test fixes**
- Run: `git add -u && git commit -m "Mark failing tests"`
- This creates a separate commit for the test markers added in steps 2-6

## Example Usage
```
# Using module names (recommended)
/upgrade-pylib inspect
/upgrade-pylib json
/upgrade-pylib asyncio

# Using library paths (alternative)
/upgrade-pylib cpython/Lib/inspect.py
/upgrade-pylib cpython/Lib/json/
```

## Example: Restoring RUSTPYTHON changes
Expand Down