Skip to content

Commit 3657da3

Browse files
Technologicatclaude
andcommitted
Archive CC modernization briefs into briefs/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 49bacff commit 3657da3

3 files changed

Lines changed: 753 additions & 0 deletions

File tree

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# CC Brief: unpythonic Modernization — Phase 1 (Audit)
2+
3+
## Context
4+
5+
unpythonic is being updated from Python 3.8–3.12 to 3.10–3.14. This follows the mcpyrate 4.0.0 update — unpythonic is mcpyrate's primary downstream consumer. Version will be 2.0.0 (floor bump + mcpyrate 4.0.0 dependency is breaking).
6+
7+
unpythonic has three tiers: pure Python layer (`unpythonic/`), macro layer (`unpythonic/syntax/`), and dialect layer (`unpythonic/dialects/`). The macro and dialect layers depend on mcpyrate. The pure Python layer has no mcpyrate dependency at runtime.
8+
9+
No code changes in this phase, only a report.
10+
11+
## Reference
12+
13+
- unpythonic CLAUDE.md (in repo root) — architecture, conventions.
14+
- unpythonic issue #93: consolidated AST change notes (covers mcpyrate, unpythonic, Pyan3).
15+
- mcpyrate 4.0.0 changelog: removed `getconstant()`, `Num`, `Str`, `Bytes`, `NameConstant`, `Ellipsis`, `Index`, `ExtSlice` from `astcompat` public API.
16+
- mcpyrate 4.0.0 source tree: `~/Documents/koodit/mcpyrate/` — consult when you need to check what `astcompat` exports, how the unparser handles new nodes, or any other mcpyrate 4.0.0 API details.
17+
18+
## What to audit
19+
20+
### 1. Imports from mcpyrate.astcompat (mcpyrate 4.0.0 breakage)
21+
22+
mcpyrate 4.0.0 removed these from `astcompat`: `getconstant`, `Num`, `Str`, `Bytes`, `NameConstant`, `Ellipsis`, `Index`, `ExtSlice`.
23+
24+
**Find all imports from `mcpyrate.astcompat`** and flag any that reference removed names.
25+
26+
**Known instances** (verify — there may be more):
27+
- `syntax/lambdatools.py`: imports `getconstant`, `Str`, `NamedExpr`
28+
- `syntax/letdoutil.py`: imports `getconstant`, `Str`, `NamedExpr`
29+
- `syntax/tailtools.py`: imports `getconstant`, `NameConstant`, `TryStar`
30+
- `syntax/autoref.py`: imports `getconstant`
31+
- `syntax/util.py`: imports `getconstant`
32+
- `syntax/autocurry.py`: imports `TypeAlias` (still valid)
33+
- `syntax/lazify.py`: imports `TypeAlias` (still valid)
34+
- `syntax/scopeanalyzer.py`: imports `TryStar`, `MatchStar`, `MatchMapping`, `MatchClass`, `MatchAs` (still valid)
35+
- `syntax/tests/test_letdoutil.py`: imports `getconstant`, `Num`
36+
- `syntax/tests/test_util.py`: imports `getconstant`, `Num`, `Str`
37+
38+
For each removed import, find all usage sites in that file. Most will be type checks like `type(k) in (Constant, Str)` that collapse to `type(k) is Constant`, and `getconstant(node)` calls that become `node.value`.
39+
40+
### 2. `hasattr` checks on AST node fields (3.13)
41+
42+
In Python 3.13, omitted optional fields on AST nodes are set to `None` instead of being absent. Code that uses `hasattr(node, "field")` to detect absence will now always return `True`, breaking guards that relied on absence to detect "not set".
43+
44+
**Known instances** (scan for more):
45+
46+
**Dialect files:**
47+
- `dialects/listhell.py` (~line 29): `if hasattr(self, "lineno"):`
48+
- `dialects/lispython.py` (~lines 45, 82): `if hasattr(self, "lineno"):`
49+
- `dialects/pytkell.py` (~line 45): `if hasattr(self, "lineno"):`
50+
51+
Note: these check `hasattr(self, "lineno")` on dialect classes, not directly on AST nodes. The comment says "mcpyrate 3.6.0+". Check whether `self` here is an AST node or a dialect instance — if it's a dialect instance, the 3.13 AST field change doesn't apply.
52+
53+
**Macro layer:**
54+
- `syntax/testingtools.py` (~lines 803, 904, 941, 1013): `hasattr(tree, "lineno")` / `hasattr(first_stmt, "lineno")`
55+
- `syntax/dbg.py` (~lines 229, 240): `hasattr(tree, "lineno")`
56+
- `syntax/lambdatools.py` (~line 403): `if hasattr(tree, "lineno"):`
57+
- `syntax/lambdatools.py` (~line 539): `tree.ctx if hasattr(tree, "ctx") else None`
58+
- `syntax/scopeanalyzer.py` (~lines 389, 411): `hasattr(tree, "ctx") and type(tree.ctx) is Store/Del`
59+
- `syntax/letdoutil.py` (~line 763): `hasattr(oldb, "lineno") and hasattr(oldb, "col_offset")`
60+
- `syntax/letdo.py` (~line 478): `hasattr(tree, "ctx")`
61+
62+
**Tests:**
63+
- `syntax/tests/test_conts_multishot.py` (~line 68): `hasattr(tree, "ctx")`
64+
65+
For `ctx` checks: these are likely checking whether a macro-generated node has had `ctx` set. In 3.13, `ctx` defaults to `Load()` on omission, so `hasattr` will always be `True` — but the node *does* have a meaningful `ctx` now (`Load()`). Determine whether this is a behavior change or harmless.
66+
67+
### 3. `sys.version_info` guards (floor bump cleanup)
68+
69+
With floor at 3.10, all `>= (3, 8)` and `>= (3, 9)` checks are always true. Find all and list.
70+
71+
**Known instances** (~14+ sites, mostly `ast.Index` wrapper removal):
72+
- `syntax/testingtools.py` (~line 883): `>= (3, 9, 0)``ast.Index` wrapper
73+
- `syntax/letsyntax.py` (~line 372): `>= (3, 9, 0)``ast.Index` wrapper
74+
- `syntax/prefix.py` (~line 197): `>= (3, 9, 0)``ast.Index` wrapper
75+
- `syntax/letdoutil.py` (~lines 25, 30): `>= (3, 9, 0)``ast.Index` wrapper
76+
- `syntax/nameutil.py` (~line 127): `>= (3, 9, 0)``ast.Index` wrapper
77+
- `syntax/letdo.py` (~line 595): `>= (3, 8, 0)` — positional-only args
78+
- `syntax/tailtools.py` (~line 1118): `>= (3, 8, 0)` — positional-only args
79+
- `syntax/tests/test_conts_multishot.py` (~line 194): `>= (3, 9, 0)``ast.Index`
80+
- `syntax/tests/test_letdoutil.py` (~lines 611, 624, 631, 650, 663, 670): `>= (3, 9, 0)``ast.Index`
81+
- `typecheck.py` (~line 187): `>= (3, 10, 0)``types.UnionType`. Always true with floor at 3.10.
82+
- `tests/test_fun.py` (~line 259): `< (3, 11, 0)` — check what this guards
83+
84+
### 4. Direct references to deprecated/removed AST node types
85+
86+
Outside of `mcpyrate.astcompat` imports, check for any direct `ast.Num`, `ast.Str`, etc. references.
87+
88+
**Known instance:**
89+
- `syntax/letdoutil.py` (~line 732): error message mentions `ast.Str` — just a string literal, but should be updated for accuracy.
90+
91+
### 5. `autoreturn` and `match`/`case` (feature gap from issue #93)
92+
93+
`autoreturn` in `syntax/tailtools.py` doesn't handle `match`/`case` statements. This is a known gap — it's a feature addition, not strictly a compat fix, but it's the most significant modernization issue identified in issue #93.
94+
95+
**Scope the work:** check how `autoreturn` handles other compound statements (`if`/`elif`/`else`, `try`/`except`, `with`). The `match`/`case` handler should follow the same pattern — autoreturn the last expression in each `case` body.
96+
97+
**Decision:** Include in 2.0.0. The 3.10 floor means `match`/`case` is always available, and the version bump is happening anyway. This is self-contained relative to the rest of the `autoreturn` machinery — the scary parts of unpythonic (TCO, lazify, autocurry, continuations) are not involved.
98+
99+
### 6. AST constructor calls (3.13 strictness)
100+
101+
In 3.13, omitting required fields or passing unknown kwargs on `ast.*` node constructors emits `DeprecationWarning` (becomes an error in 3.15). Scan for AST node constructor calls that omit required fields or pass unknown kwargs.
102+
103+
Focus on the macro layer (`syntax/*.py`) which constructs AST nodes extensively. The pure Python layer doesn't touch AST.
104+
105+
**Exception — `ctx` fields**: Many AST node constructors intentionally omit `ctx` — mcpyrate's `astfixers.fix_ctx()` auto-injects the correct `ctx` after macro expansion. In 3.13, omitted `ctx` defaults to `Load()`, which is harmless since `astfixers` overwrites it. Don't flag missing `ctx`.
106+
107+
### 7. Version metadata
108+
109+
- `pyproject.toml`: `python_requires`, classifiers, mcpyrate dependency version
110+
- CI workflow: matrix versions, PyPy versions
111+
- `CLAUDE.md`: version range mentions
112+
- `README.md`: any version range mentions
113+
- `CHANGELOG.md`: will need a 2.0.0 entry (not part of audit, just note)
114+
- Module docstrings mentioning version ranges
115+
116+
## Deliverable
117+
118+
A report (markdown) listing all sites that need attention, grouped by file. For each site, note:
119+
- File and line number
120+
- What the issue is
121+
- Category: mcpyrate 4.0.0 breakage / floor bump cleanup / 3.13 compat / 3.14 compat / feature gap
122+
- Severity (will break / will warn / cleanup only)
123+
124+
No code changes.

0 commit comments

Comments
 (0)