100 Commits
Author SHA1 Message Date
Lee DogeonandClaude 76b3b0027c Cut redundant CI work (#9371)
* Document only workspace crates in the cargo doc job

cargo doc ran rustdoc on every dependency as well; in run #91 that was
284 documented crates for a check of this workspace's own docs.

Assisted-by: Claude Code
Claude-Session: https://claude.ai/code/session_01JpHqXiC3mDShqfsPxvr9ey

* Share one target directory between the example projects

Each example project is its own workspace and built into its own target
directory, so the second build recompiled the dependencies the first had
just built. Of the 359 units the frozen_stdlib build needs, 261 are
identical to units of the barebone build.

Assisted-by: Claude Code
Claude-Session: https://claude.ai/code/session_01JpHqXiC3mDShqfsPxvr9ey

* Check both macOS cross targets on one runner

macOS runners have the smallest concurrent-job limit of the hosted
runners. The aarch64-apple-ios and x86_64-apple-darwin checks now run in
one job, with one cargo invocation per feature set that passes both
targets, so they also share the host-side build scripts and proc macros.
The matrix entry lists the targets separated by a space, because the
target is part of the cache key and actions/cache rejects commas.

This renames the two "cargo check (macos-latest, ...)" checks to one.

Assisted-by: Claude Code
Claude-Session: https://claude.ai/code/session_01JpHqXiC3mDShqfsPxvr9ey

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 10:45:13 +09:00
Lee Dogeon 0f74d1cd14 ci: remove OSCCA pull request triage workflow (#9361)
Stop automatically labeling OSCCA participants' pull requests with
z-ca-2026 and assigning them, and drop the matching zizmor ignore entry.

Assisted-by: Claude Code:claude-opus-5-5
2026-10-25 19:29:20 +09:00
Lee DogeonandClaude Sonnet 5 44dcd1de2d ci: add pyperformance benchmarking scripts and workflow (#8691)
* Add script to run upstream pyperformance against RustPython

pyperformance can't be installed as-is on RustPython since pyperf hard-depends
on psutil, a C extension RustPython cannot build or load (no CPython C-API /
extension-module support). Since pyperf already disables psutil usage on
interpreters reporting Py_GIL_DISABLED=1 (which RustPython does, having no
GIL), a functionality-free pure-Python psutil stub is enough to satisfy pip's
dependency resolution and unblock any pure-Python benchmark.

scripts/pyperformance/run_all.py drives pyperformance (under a host CPython
venv) with RustPython as the --python target, installs the stub via
PIP_FIND_LINKS + --inherit-environ, and catalogs pass/fail/timeout per
benchmark with an automatic failure classifier (C-extension build blocked vs.
a genuine exception raised by the benchmark itself).

Assisted-by: Claude Code:claude-sonnet-5

* pyperformance: support targeting any Python and comparing catalogs

Generalize run_all.py from a RustPython-only runner to a --python/--label
pair, so the same script can catalog a real CPython (with --no-psutil-stub,
since it has a genuine psutil) alongside RustPython. Each label gets its own
results/<label>/ subdirectory.

Add compare.py, which loads two labels' catalogs and writes a per-benchmark
Markdown table with both targets' status/mean and the candidate/baseline
time ratio, plus the median slowdown across benchmarks both targets passed.

Assisted-by: Claude Code:claude-sonnet-5

* ci: compare base, head and CPython with pyperformance on one runner

A ratio between two pyperformance runs measured on different machines can
move further than the change under review did, so a PR's numbers are only
worth reading when base, head and CPython were measured back to back on the
same runner. This adds a job that does exactly that -- two release builds
kept side by side with the stdlib of their own commit, then three runs with
nothing in between -- and posts the table as a PR comment.

`pr_diff.py` renders the three catalogs `run_all.py` writes: per benchmark
the CPython time, both RustPython times, both ratios against CPython, and
the head/base change, with anything under 3% shown as `~` because a shared
runner is not quiet enough to say more.

The comment is handed to a `workflow_run` companion the same way
`codspeed-comment.yaml` does it, since a `pull_request` run from a fork gets
a read-only token however the workflow is configured.

The job is opt-in behind a `run:pyperformance` label: it runs 28 benchmarks
three times over and costs well over an hour, which most PRs do not need.

`run_all.py` now forwards RUSTPYTHONPATH through pyperf, which a binary
copied away from its checkout needs in order to find the stdlib at all; the
two names go in one comma-separated `--inherit-environ`, because repeating
the flag keeps only the last.

Assisted-by: Claude Code:claude-fable-5-1

* ci: comment from the pyperformance run itself when the PR allows it

The `workflow_run` companion only starts firing once it is on the default
branch, so a pull request that introduces it -- this one -- would upload the
table and never show it. A pull request opened from this repo carries a
token that may write comments, so post it from the run that measured it and
leave the companion to the forks that genuinely cannot.

Both paths upsert on the same marker, so a fork PR that reaches the
companion after this step was skipped still lands one comment.

Assisted-by: Claude Code:claude-fable-5-1

* ci: address zizmor findings and fall back to head vs. CPython

- Pin `actions/github-script` to the commit the rest of the repo pins it to;
  the hash carried over from an in-flight branch pointed elsewhere than the
  `v9.0.0` comment claimed (ref-version-mismatch).
- Read the PR number, the CPython path and version, and the two commit shas
  from `env` rather than expanding them into the shell (template-injection).
- Record the `workflow_run` trigger in `.github/zizmor.yml` next to the
  existing `pull_request_target` entry, with the same justification: the
  workflow reads one artifact and writes a comment, and never checks out or
  runs pull request code (dangerous-triggers).

Building or measuring the base commit is now non-fatal, and `pr_diff.py`
renders head against CPython alone when the base column has nothing in it --
a base that will not build should still leave a usable table rather than
failing the job. The time and ratio columns are also named apart, since
`| base | head | base | head |` gave no clue which pair was which.

Assisted-by: Claude Code:claude-fable-5-1

* ci: derive pyperformance comment target from trusted workflow_run metadata

pr_number.txt came from the artifact a `pull_request` run uploads, which a
fork could tamper with to make this privileged `workflow_run` comment on an
arbitrary PR/issue. Resolve the PR from context.payload.workflow_run instead
(falling back to a commit-associated open PR lookup for workflow_dispatch
runs), and escape any HTML comments already present in diff.md so they can't
be mistaken for the marker.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* ci: grant actions:read to the pyperformance comment workflow

download-artifact needs actions:read to fetch another run's artifact by
run-id. Specifying a permissions block sets every unlisted scope to none, so
without this the cross-run download silently failed for fork PRs -- the
scenario this workflow exists for -- continue-on-error masked it, and the
comment step found no diff.md and returned without posting.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: kill the whole process group on a benchmark timeout

subprocess.run's own timeout only terminates the direct pyperformance
process; pyperf re-execs the target interpreter as a child, which can
survive the timeout and keep burning CPU into the next benchmark's
measurement. Run each benchmark in its own session/process group instead,
and on timeout SIGKILL the whole group via os.killpg.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: compute the head-vs-base cell from head_vs_base directly

The cell was derived from base_vs_cpython and head_vs_cpython, both of which
are None when a benchmark has no CPython time -- so it rendered "-" even
though base and head both had valid times and head_vs_base was already
computed. Use that precomputed ratio instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: invalidate the resumed catalog when the target executable changes

catalog.json records results without any fingerprint of target_python, and
resume skips benchmarks by name alone, so a local rebuild (or swapping the
target) under the same --label could silently reuse stale measurements.
Store a sha256 of the executable's contents alongside the catalog and, when
it no longer matches, ignore the existing catalog and re-run everything.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* ci: fall back to github.sha for the head checkout on workflow_dispatch

github.event.pull_request.head.sha is empty on a workflow_dispatch run (no
pull_request payload), so `git checkout --quiet "" --` failed with "fatal:
invalid reference" on this non-optional step, aborting every manual run
before it could measure or render results.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: resolve --out/--cache-dir to absolute paths

Every benchmark subprocess runs with cwd=work_dir (under --cache-dir), so a
relative --out or --cache-dir passed on the command line resolved against
that directory instead of the one run_all.py was invoked from, breaking
catalog output, the pyperformance binary path, and PIP_FIND_LINKS. Both
default to absolute paths already; resolve them up front so a relative
override behaves the same way.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: persist catalog invalidation before the new fingerprint

The fingerprint file was rewritten before the invalidated catalog was ever
written back to disk. An interruption between the two (e.g. a crash during
the first benchmark of the re-run) left a fingerprint matching the new
executable pointing at a catalog.json still full of results measured
against the old one, so the next run would trust it as fresh. Write the
reset (empty) catalog first, then record the fingerprint.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: show benchmarks that fail on both base and head

Rows were dropped whenever neither side had a mean, which also hid a
benchmark that failed or timed out identically on base and head -- e.g. a
C-extension gap unrelated to the PR under review. Only skip a benchmark
never attempted on either commit; keep rows with a fail/timeout status so
they still show up in the table.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: write catalog.json atomically

write_catalog runs after every single benchmark, and Path.write_text
truncates the file before writing the replacement. An interruption
mid-write left catalog.json both missing every earlier result and invalid
JSON, so the next run's resume logic failed outright at json.loads(). Write
to a temporary sibling file and rename it into place instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: fix passed count and median population in the summary table

"Benchmarks passed" counted len(base_ratios)/len(head_ratios), which require
a *CPython* ratio too -- a CPython-only failure hid an otherwise-passing
benchmark from both sides' counts. Count actual "ok" status per side
instead.

The two medians were also computed over independently-filtered
populations: whichever benchmarks had a valid ratio on that side alone. A
benchmark that regressed to failure on only one side dropped out of only
that side's median, which could shift it well beyond what any surviving
benchmark's timing actually changed by. Restrict both medians to
benchmarks with a valid ratio on both sides, and label the population size.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: include RUSTPYTHONPATH's stdlib in the executable fingerprint

The catalog-invalidation fingerprint hashed only the executable's bytes, but
a RustPython binary copied away from its checkout finds its stdlib through
RUSTPYTHONPATH -- pyperf re-execs the target interpreter into a venv and
forwards that variable so it can still find Lib/. Changing that path, or
editing the files under it, without rebuilding the binary left resume
trusting results measured against a now-different stdlib. Fold its contents
into the fingerprint too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: require an explicit ok/fail status for pass/fail transitions

only_head/only_base flagged a benchmark as newly passing or no longer
passing based only on whether the other side had a mean, so a benchmark
never attempted on one side (e.g. a partial --benchmarks run) was reported
as a regression or fix it never was. Require the other side's status to be
an actual fail/timeout, not just missing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: don't gate the head/base geometric mean on a CPython ratio

The summary panel -- pass counts and the head/base geometric mean, neither
of which need a CPython comparison -- only rendered when at least one
benchmark also had a valid ratio against CPython on both sides. A build
with a perfectly good head-vs-base comparison but no common CPython result
lost the whole panel, including the one aggregate that didn't depend on
CPython at all.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: normalize RUSTPYTHONPATH and extract main() into named steps

Fix: a relative RUSTPYTHONPATH was fingerprinted relative to this script's
invocation directory but resolved by pyperf's subprocess relative to
work_dir (its cwd), so a relative value could be hashed against the wrong
directory entirely, or fail to resolve at runtime. Resolve it to an
absolute path up front, alongside --out and --cache-dir.

Refactor: main() had accumulated argparse setup, executable resolution, and
the fingerprint/resume block inline, each wrapped in an explanatory comment
-- a sign the function was doing too much rather than that it needed more
narration. Extracted parse_args(), resolve_target_python(), and
load_resumable_catalog() so main() reads as a short sequence of named
steps and each comment sits next to the one function it actually explains.
No behavior change; verified with unit tests against the extracted
functions (fingerprint reacting to RUSTPYTHONPATH, resume picking up a
prior catalog, invalidation on an executable change).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: split pr_diff.py's main() and fix a status-transition gap

Fix: only_head was still gated on have_base, which only asks whether *any*
base benchmark produced a timing -- so a benchmark that flipped from
failing to passing went unreported whenever every other base benchmark
also happened to fail. Status transitions don't need that gate; they
already require an explicit ok/fail/timeout status on both sides.

Refactor: main() had grown into one long function mixing argument parsing,
catalog loading, row computation, and three separate rendering concerns.
Split it into parse_args(), load_base_catalog(), build_rows(),
render_intro(), render_summary_panel(), render_table(), and
find_transitions(), each documenting the one thing it decides. No behavior
change beyond the fix above; re-verified against every scenario exercised
in the last several fixes (dual-fail rows, geo mean without a CPython
ratio, unattempted benchmarks, and the have_base gap) plus the existing
manual smoke tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* pyperformance: don't resolve an empty RUSTPYTHONPATH to the cwd

The normalization only checked "RUSTPYTHONPATH" in os.environ, so a set-but-
empty value (RUSTPYTHONPATH="") resolved to the current directory via
Path("").resolve(). executable_fingerprint() would then recursively hash
every file under wherever run_all.py was invoked from -- including its own
results directory while writing to it -- causing spurious catalog
invalidation and a lot of pointless hashing. Check for a nonempty value
instead, matching the truthiness check already used everywhere else this
variable is read.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

* docs(pyperformance): distinguish the host runner from the benchmarked target

A reviewer read "pyperformance cannot be installed as-is on RustPython" and
reasonably asked why RustPython would need to support pyperformance's CLI at
all, since it's normally run as a command under any Python (see
https://github.com/RustPython/RustPython/pull/8691#discussion_r3997957942).

It doesn't: the pyperformance CLI (the host process) always runs under a
real CPython regardless of --python. What actually needs psutil/pyperf
importable is the *benchmark* subprocess -- pyperf re-execs the --python
target and that subprocess itself does `import pyperf`. Spell out that
host/worker split up front instead of leading with "cannot be installed".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wy8J7LpmdYjesTDonNoYkv

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 15:30:21 +09:00
Lee Dogeon a582b938bd Exclude C-API tests from workspace coverage (#8619)
Assisted-by: Codex:gpt-5.6-sol
2026-09-12 09:28:09 +09:00
Lee Dogeon 29c622ca47 Document separate C-API Clippy checks (#8615)
Assisted-by: Codex:gpt-5.6-sol
2026-09-01 10:03:56 +09:00
Lee Dogeon 99a63f92aa benchmarks: add pyperformance workloads (#8633)
Add dependency-free CPU-bound workloads adapted from pyperformance 1.14.0 to cover interpreter, standard-library serialization, regex, numeric, and garbage-collection paths under the existing Criterion and CodSpeed harnesses. Keep inputs deterministic and scale expensive cases for simulation while checking that benchmark execution does not leak interpreter state.

Assisted-by: Codex:gpt-5.6-sol
2026-09-01 10:03:29 +09:00
Lee Dogeon 578217e1f6 Fix tuple subclass preservation in type bases (#8420)
* Fix tuple subclass preservation in type bases

Assisted-by: Codex:gpt-5.6-sol

* Refine type bases representation

Store validated base classes in the original typed tuple, while retaining a bootstrap vector only until a Python tuple can be materialized.

Assisted-by: gpt-5.6-sol
Assisted-by: Codex:gpt-5.6-sol

* Bootstrap tuple type with type hierarchy

Initialize tuple and the canonical empty tuple alongside type and object so every type stores an actual typed bases tuple from construction. Remove the bootstrap bases representation and keep raw initialization Miri-safe.

Assisted-by: Codex:gpt-5.6-sol
2026-08-30 22:54:22 +09:00
Lee Dogeon 07c0fda72c ci: bump actions and opt into Node.js 24 (#8616)
Assisted-by: Codex:gpt-5.6-sol
2026-08-30 21:32:39 +09:00
Lee Dogeon 1c9783ae0b Fix CodSpeed cargo install cache (#8620)
Assisted-by: Codex:gpt-5.6-sol
2026-08-30 21:31:58 +09:00
Lee Dogeon a21377a97b Match uuid.getnode() native node detection to CPython (#8612)
* uuid: expose stable hardware node

Cache native MAC address detection and advertise an extractable node only when a hardware address is available. This lets uuid.getnode() use the native UUID path while preserving its existing fallbacks.

Assisted-by: Codex:gpt-5.6-sol

* Prefer universally administered MAC addresses

Match uuid.getnode()'s documented interface-selection rule by scanning available addresses before falling back to a locally administered one. Ignore zero addresses and cover the selection behavior with Rust unit tests.

Assisted-by: Codex:gpt-5.6-sol
2026-08-30 16:14:36 +09:00
Lee Dogeon 903ba6ed81 ci: fix OSCCA pull request permissions (#8515)
Assisted-by: Codex:gpt-5.6-sol
2026-08-15 02:23:05 +09:00
Lee Dogeon 8cfa667182 ci: automate OSCCA pull request triage (#8505)
Assisted-by: Codex:gpt-5.6-sol
2026-08-13 04:29:13 +09:00
Lee Dogeon 68989a2c23 Allow automated commits and fix C-API test instructions (#8468)
* Allow automated commits through pre-commit hooks

* Fix agent C-API test instructions

Exclude rustpython-capi from root workspace test commands and run its tests from the crate directory so its Cargo configuration applies. Document the project AI policy and required commit trailer.

Assisted-by: Codex:gpt-5
2026-08-08 22:33:44 +09:00
Lee Dogeon 604934882d Fix float overflow in struct packing (#8360)
Raise OverflowError when a finite f64 value overflows while being converted for the struct f format. Remove the expected-failure marker from the corresponding regression test.

Assisted-by: Codex:gpt-5
2026-07-25 19:59:05 +09:00
Lee Dogeon ad83949471 Remove trailing whitespace from sequence TODO (#8291)
Apply the maintainer review suggestion from RustPython/RustPython#8270. Codex inspected the review context, made the one-line whitespace-only edit, and ran validation.

Assisted-by: Codex:gpt-5
2026-07-17 00:18:26 +09:00
Lee Dogeon d4a2c99d18 Implement bytearray.__str__ && bytes.__str__ (#7477)
* Implement bytearray.__str__

* Implement bytes.__str__

* Turn __str__ method into slot
2026-03-22 12:50:31 +09:00
Lee DogeonandClaude Opus 4.6 4d99a4e541 Improve CPython compatibility related with PyBoundMethod (#7476)
* Add GetDescriptor for PyBoundMethod (return self)

CPython's method_descr_get always returns the bound method unchanged.
This preserves the original binding when __get__ is called on an
already-bound method (e.g. a.meth.__get__(b, B) still returns a).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add constructor validation for PyBoundMethod

Reject non-callable functions and None instances, matching CPython's
method_new which checks PyCallable_Check(func) and instance != Py_None.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix PyBoundMethod __reduce__ to propagate errors

Previously swallowed errors from get_attr with .ok(), silently
returning None. Now propagates errors matching CPython's method_reduce.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 00:33:40 +09:00
Lee Dogeon 11608e6392 Implement Hashable for PyBoundMethod (#7474) 2026-03-20 13:15:40 +00:00
Lee DogeonCPython DevelopersClaude Opus 4.6
02bf41996c Implement complex.from_number (#7453)
Co-authored-by: CPython Developers <>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 20:50:28 +09:00
Lee DogeonandClaude Opus 4.6 2117c92b9b Cleanup some direct magic method definitions (#7441)
* Migrate direct __repr__ definitions to Representable trait

Move legacy #[pymethod] __repr__ to impl Representable for:
- PySSLContext, PySSLSocket (ssl.rs)
- BufferedReader, BufferedWriter, BufferedRandom (_io.rs)

Enable __repr__ guard in derive to prevent future direct definitions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Migrate direct __del__ definition to Destructor trait for PySocket

Move #[pymethod] __del__ to impl Destructor for PySocket.
Preserves ResourceWarning emission and close behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove redundant __iter__ pymethods from PyFuture and PyTask

Both types already have impl Iterable, so the direct #[pymethod]
__iter__ definitions were duplicates. Enable __iter__/__next__
guards in derive to prevent future direct definitions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Enable derive guards for __get__/__set__/__delete__ descriptor methods

All concrete types already use GetDescriptor/SetDescriptor traits.
Activate the compile-time guard to prevent future direct definitions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Enable derive guards for AsMapping/AsSequence slot methods

Remove redundant #[pymethod(name = "__len__")] from PyStr
(already provided via AsMapping/AsSequence trait impls).

Enable compile-time guards for __len__, __contains__, __getitem__,
__setitem__, __delitem__ to prevent future direct definitions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:49:45 +09:00
Lee Dogeon 1614e88b97 Implement missing slots for NoneType (#7437)
* Define only wrapper_descriptor

* Implement missing slots for NoneType
2026-03-16 11:58:40 +09:00
Lee Dogeon f5b1ea7c60 Preserve imaginary zero signs when adding real values to complex numbers (#7421)
* Preserve imaginary zero signs when adding real values to complex numbers

* Refactor complex_add with match expression

* Correct complex real subtract op

* Remove unnecessary vm arugment
2026-03-15 17:04:23 +09:00
Lee Dogeon 3f1ce34422 Match divmod zero-division message with CPython (#7426) 2026-03-14 20:21:23 +09:00
Lee Dogeon 257cf6fa0e Match __module__ setter behavior to CPython (#7424)
* Remove stale __firstlineno__ when updating type.__module__

* Register and use __firstlineno__ as identifier
2026-03-14 15:48:48 +09:00
Lee Dogeon ae73aab6a4 Handle chr() range checks without Rust integer overflow (#7422) 2026-03-14 15:47:45 +09:00
Lee Dogeon 3106c30d58 Make singleton builtin types immutable (#7423) 2026-03-14 09:45:43 +09:00
Lee DogeonandClaude Opus 4.6 431766912b Mark failing tests for modulefinder
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 20:52:26 +09:00
Lee Dogeon 2386ea6c8c Fold const bool with unary not (#7357)
* Fold const bool with unary not

* Fold unnecessary TO_BOOL
2026-03-05 23:00:47 +09:00
Lee Dogeon 6ac0c39a30 Prevent shell injection (#7310) 2026-03-02 19:45:58 +09:00
Lee Dogeon 550cc44fbd Update test_collections from v3.14.3 (#7189) 2026-02-19 08:48:33 +09:00
Lee DogeonandClaude Opus 4.6 0fdd3a669c Remove expectedFailure from test_types_coroutine_wrapper_state
The types.py upgrade added gi_suspended to _GeneratorWrapper,
fixing this test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 18:39:56 +09:00
Lee DogeonandClaude Opus 4.6 27a986a843 Mark failing tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 18:38:44 +09:00
4b292f46e3 Optimize redundant bool check (#7176)
* Add compile_bool_op_inner and optimize nested opposite-operator BoolOps to avoid redundant __bool__ calls

When a nested BoolOp has the opposite operator (e.g., `And` inside `Or`),
the inner BoolOp's short-circuit exits are redirected to skip the outer
BoolOp's redundant truth test. This avoids calling `__bool__()` twice on
the same value (e.g., `Test() and False or False` previously called
`Test().__bool__()` twice instead of once).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add snapshot test for nested BoolOp bytecode

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add runtime test for redundant __bool__ check (issue #3567)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Apply clippy and rustfmt

* Apply ruff format

* Refactor compile_bool_op: extract emit_short_circuit_test and unify with compile_bool_op_inner

Reduce code duplication by:
- Extracting the repeated Copy + conditional jump pattern into emit_short_circuit_test
- Merging compile_bool_op and compile_bool_op_inner into a single
  compile_bool_op_with_target with an optional short_circuit_target parameter
- Keeping compile_bool_op as a thin wrapper for the public interface

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Relocate redundant __bool__ check test snippet

* Update extra_tests/snippets/syntax_short_circuit_bool.py

* Fix assertion in syntax_short_circuit_bool

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jeong, YunWon <69878+youknowone@users.noreply.github.com>
2026-02-18 00:45:17 +09:00
Lee Dogeon 0475671421 Emit deprecation warning for array typecode u (#7157) 2026-02-15 20:34:19 +09:00
Lee Dogeon 4f3d88ce4f Align lzma and os exports for test_all expected failure (#7156) 2026-02-15 20:33:58 +09:00
Lee Dogeon 52b0fc930a Use @unittest.skip instead of @unittest.expectedFailure for codec encoding tests
The encoding errors occur in setUp() which causes ERRORs, not FAILUREs.
@unittest.expectedFailure only catches test failures, not setUp errors.
Using class-level @unittest.skip properly handles this case.
2026-02-15 14:37:06 +09:00
Lee Dogeon 2fee84e38a Mark failing tests for test_codecmaps_tw 2026-02-15 14:33:37 +09:00
Lee Dogeon 5012ae0e42 Mark failing tests for test_codecmaps_kr 2026-02-15 14:33:26 +09:00
Lee Dogeon a77df0c0c5 Mark failing tests for test_codecmaps_jp 2026-02-15 14:33:16 +09:00
Lee Dogeon 74207d92a1 Mark failing tests for test_codecmaps_hk 2026-02-15 14:33:05 +09:00
Lee Dogeon 06b0996332 Mark failing tests for test_codecmaps_cn 2026-02-15 14:32:53 +09:00
Lee Dogeon 76eb6b8033 Mark failing tests for test_codecencodings_tw 2026-02-15 14:32:10 +09:00
Lee Dogeon 06514db758 Mark failing tests for test_codecencodings_kr 2026-02-15 14:31:59 +09:00
Lee Dogeon 0096592d8f Mark failing tests for test_codecencodings_jp 2026-02-15 14:31:45 +09:00
Lee Dogeon f88d675cf2 Mark failing tests for test_codecencodings_iso2022 2026-02-15 14:31:31 +09:00
Lee Dogeon f5a2f1b79c Mark failing tests for test_codecencodings_hk 2026-02-15 14:31:18 +09:00
Lee Dogeon 556e53c02a Mark failing tests for test_codecencodings_cn 2026-02-15 14:31:06 +09:00
Lee Dogeon 77583c7e7e Include SHAKE algorithm names in HASHXOF repr (#7132) 2026-02-15 09:05:42 +09:00
Lee Dogeon dd05bac4a1 Match SymbolTable repr with CPython format (#7139) 2026-02-14 22:59:42 +09:00
Lee Dogeon ce60c16b77 Add SHA3 private attribute parity to hashlib hash objects (#7134) 2026-02-14 21:36:57 +09:00
Lee Dogeon 51bdb0617c Make HASH/HASHXOF types immutable (#7131) 2026-02-14 20:37:47 +09:00
Lee Dogeon 3f49f4107c Fix SHAKE digest length overflow in hashlib (#7125) 2026-02-14 19:57:27 +09:00
Lee Dogeon f92a7dd9ca Fix object.__init__ excess-arg checks for heap types (#7116) 2026-02-14 19:56:49 +09:00
Lee Dogeon ecc59cfdcd Fix inspect.signature introspection for attrgetter/itemgetter/methodcaller (#7111)
* Fix attrgetter signature introspection in operator

* Fix itemgetter signature introspection in operator

* Fix methodcaller signature introspection in operator
2026-02-14 09:17:41 +09:00
Lee Dogeon 85e146e868 Add float.from_number classmethod (#7107) 2026-02-13 11:47:12 +00:00
Lee DogeonandClaude Opus 4.6 7b97ff94c6 Mark failing tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:05:39 +09:00
Lee Dogeon c6f7c6e273 Remove RustPython-specific workaround in timeit module (#6923) 2026-02-01 14:52:36 +09:00
Lee Dogeon b1f158e5a8 Mark tests failing only in Windows 2026-01-31 10:11:58 +09:00
Lee Dogeon 0c174624b4 Introduce /upgrade-pylib-next (#6827)
* Simplify upgrade-pylib.md by removing manual copy steps handled by quick command

* Let upgrade-pylib run auto-mark instead marking manually

* Let upgrade-pylib a separate commit from updating module

* Correct commands' permissions

* Add open PR check to upgrade-pylib-next command

* Fix dependency pattern example in upgrade-pylib-next command

* Let upgrade-pylib command to invetigate failing tests

* Add pre-commit review to invetigate-test-failure command

* Use deps command to get dependent tests in upgrade-pylib workflow
2026-01-31 07:40:39 +09:00
Lee Dogeon 5c7f6a2afa Update types from v3.14.2 (#6833)
This pull request updates `types` module to v3.14.2. While doing it, it
fixes also async-related feature. This pull request's base is generated
by #6827.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Generators that act as iterable coroutines are now recognized as
awaitable, improving async behavior.
* Yield-from and await interactions now handle coroutine-iterable
sources more consistently.

* **Bug Fixes**
* Reduces spurious TypeError cases when awaiting or yielding from
wrapped coroutine-like generators.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-01-23 23:23:02 +09:00
9b56aa5b60 [update_lib] show dependent tests in deps subcommand (#6828)
---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jeong YunWon <jeong@youknowone.org>
2026-01-23 08:13:16 +09:00
Lee Dogeon ce1bbc7938 Bump mimetypes to 3.14.2 (#6808)
* Bump mimetypes to 3.14.2

* Unmark resolved tests

* Mark failed test in Windows
2026-01-21 20:14:30 +09:00
Lee Dogeon 4eecd15a2a Mark failing tests 2026-01-21 15:10:40 +09:00
Lee Dogeon 3bcd071e4d Bump collections to 3.14.2 (#6770)
* Bump collections to 3.14.2

* Unmark resolved tests
2026-01-20 23:58:43 +09:00
Lee Dogeon 0cad3cb8b8 Use empty list as default according to Python.asdl (#6812)
* Use empty list as default in ClassDef.{bases,keywords}

* Unmark resolved tests

* Use empty list as default in FunctionDef.type_params

* Use empty list as default in ClassDef.type_params
2026-01-20 18:02:42 +09:00
Lee Dogeon 52a854a57a Unmark resolved test 2026-01-20 15:29:05 +09:00
Lee Dogeon c8b1cb8cab Bump re to 3.14.2 2026-01-20 15:29:05 +09:00
Lee Dogeon 876d3f5e80 Correct testcase 2026-01-20 11:38:26 +09:00
Lee Dogeon fe6a60ade7 Fix error lines extraction 2026-01-20 11:38:26 +09:00
Lee DogeonandClaude Opus 4.5 4ab6a45405 Use stdlib native modules in benchmarks (#6792)
Change benchmark interpreter from without_stdlib to with_init to load
Rust-optimized native modules like _json, ensuring benchmarks measure
actual optimized performance rather than pure Python fallbacks.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 08:43:25 +09:00
Lee Dogeon 9b5eefbb7b Replace _compression with compression and update related too (#6788) 2026-01-19 00:38:51 +09:00
Lee Dogeon ed785e3d86 Bump base64 to 3.14.2 (#6776) 2026-01-19 00:04:06 +09:00
Lee DogeonandClaude Opus 4.5 4b5e73577a Add metadata when uploading benchmark data (#6759)
Generate a metadata file alongside criterion benchmark data containing
the commit hash, ref name, and timestamp for tracking purposes.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 21:51:39 +09:00
Lee Dogeon 5242ff5243 Bump json to 3.14.2 (#6774) 2026-01-18 19:16:48 +09:00
Lee Dogeon 3d86b26caf Complement upgrade-pylib Claude Code command (#6742)
* Insert unittest import line if it doesn't exist

* Complement upgrade-pylib Claude Code command

* Ensure test module having import statement at least one
2026-01-17 21:54:16 +09:00
Lee Dogeon ef871d227e Update json module to 3.13.11 (#6743) 2026-01-16 21:38:15 +09:00
Lee DogeonandClaude Opus 4.5 3a702ac772 Improve json.loads performance (#6704)
* Parse JSON in Rust

* Reuse key when decoding JSON

* Unmark resolved test

* Parse null/true/false directly in call_scan_once

Parse JSON constants (null, true, false) directly in Rust within
call_scan_once() instead of falling back to Python scan_once.
This reduces Python-Rust boundary crossings for array/object values.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Parse numbers directly in call_scan_once

Parse JSON numbers starting with digits (0-9) directly in Rust within
call_scan_once() by reusing the existing parse_number() method.
This reduces Python-Rust boundary crossings for array/object values.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Parse NaN/Infinity/-Infinity in call_scan_once

Parse special JSON constants (NaN, Infinity, -Infinity) and negative
numbers directly in Rust within call_scan_once(). This handles:
- 'N' -> NaN via parse_constant callback
- 'I' -> Infinity via parse_constant callback
- '-' -> -Infinity or negative numbers via parse_constant/parse_number

This reduces Python-Rust boundary crossings for array/object values.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Correct wrong index access

* Leave more flame span

* Refactor json scanstring with byte index

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 19:53:46 +09:00
Lee Dogeon 2e5257d098 Introduce benchmark for json.loads (#6723) 2026-01-14 14:44:34 +09:00
6cb763a332 Fix some parts of cron-ci workflow (#6724)
* Use shared PYTHON_VERSION in cron-ci benchmark job

* Correct extra-tests/jsontests.py script

When the `extra_tests/jsontests.py` script was added, it was presumably during
the time when Python versions 3.5 to 3.8 were in use. At that time,
`test.libregrtest.runtest` was a valid path, but from CPython version 3.11
onwards, the path changed to `test.libregrtest.findtests`.

* Use ssl-rustls feature instead of ssl in cron-ci workflow

Replace the ssl feature with ssl-rustls in both the CARGO_ARGS
environment variable and the cargo-llvm-cov test command to fix
the cron-ci workflow.

Since 1a783fc9ec, it is disallowed
to use ssl manually.

* Replace inspect.getargspec with inspect.getfullargspec in custom_text_test_runner

inspect.getargspec() was removed in Python 3.11, causing jsontests.py to
fail with "TypeError: 'NoneType' object is not iterable" when running on
RustPython (which targets Python 3.13).

The get_function_args() function was silently catching the AttributeError
and returning None, which then caused the error in store_class_fields()
when trying to iterate over None.

> https://docs.python.org/3/whatsnew/3.11.html
> The getargspec() function, deprecated since Python 3.0; use
> inspect.signature() or inspect.getfullargspec() instead.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Exclude rustpython-venvlauncher in cron-ci workflow

Since rustpython-venvlauncher is Windows-only,
it disables the project in the cron-ci workflow.

* Apply suggestion from @fanninpm

Co-authored-by: fanninpm <luxverdans@sbcglobal.net>

* Trigger cron-ci workflow in pull_request

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Jeong, YunWon <69878+youknowone@users.noreply.github.com>
Co-authored-by: fanninpm <luxverdans@sbcglobal.net>
2026-01-14 13:28:25 +09:00
Lee Dogeon 49e6931c7e Introduce flame_guard in rustpython-stdlib too (#6722) 2026-01-14 09:14:05 +09:00
Lee Dogeonandgithub-actions[bot] f3b7f7fd47 Clarify commit message from pr-auto-commit (#6706)
* Clarify commit message from pr-auto-commit

* Auto-format: cargo fmt --all

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-12 08:08:50 +09:00
Lee Dogeon 0cd6eb7b13 Write profile even if failed (#6685) 2026-01-10 15:26:49 +09:00
Lee Dogeon 6408228b3e Update DEVELOPMENT.md (#6671)
* Update DEVELOPMENT.md to reflect crates/ directory structure

* Update DEVELOPMENT.md to reflect Ruff parser-related changes
2026-01-07 10:09:51 +09:00
Lee Dogeon 8e21db11d6 Update architecture/architecture.md (#6437)
* Replace architecture overview image with mermaid graph

* Update architecture.md with correct paths and links

- Fix file paths to reflect crates/ directory structure
- Update GitHub permalink references to current commit
- Remove trailing slashes from package names
- Use archive.org for broken desosa.nl link
- Change master to main branch reference

* Update architecture documentation for ruff_python_parser

RustPython now uses ruff_python_parser from astral-sh/ruff instead of
the separate RustPython/Parser project. Update architecture documentation
to reflect this change.
2025-12-15 09:57:06 +09:00
Lee Dogeon 7c4c1eabf0 Fix wasm32-unknown-unknown target build (#6278) 2025-11-16 22:16:34 +09:00
Lee Dogeon 44a8c9f0b3 Remove completed TODO of extra_tests/fstring.py (#6095) 2025-08-20 14:08:53 +09:00
Lee Dogeon 5953a938bd chore: test testcases with @unittest.skip decorator (#5871)
Signed-off-by: Lee Dogeon <dev.moreal@gmail.com>
2025-06-30 19:07:58 +09:00
Lee Dogeon 8589b55203 Avoid set changed size during iteration (#5860) 2025-06-29 02:14:22 +09:00
Lee Dogeon 910077d7ae Implement _stat module (#5847)
* Implement _stat module

* Allow 'FIRMLINK' term
2025-06-28 03:15:46 +09:00
Lee Dogeon dfc8fe018f Unmark fixed tests (#5818) 2025-06-23 08:55:28 +09:00
Lee Dogeon 465627f104 Implement vm logics related with ParamSpec, TypeVarTuple 2025-02-10 21:21:38 +09:00
Lee DogeonandJeong, YunWon 60993b9d23 Bump shutil to 3.12.3 (#5228)
* Bump shutil to 3.12.3

* Implement windows platform target `is_junction` with junction library

* Add _winapi.NeedCurrentDirectoryForExePath

---------

Co-authored-by: Jeong, YunWon <jeong@youknowone.org>
2024-04-17 01:33:14 +09:00
Moreal 959e7c11ce Unmark fixed tests 2024-04-15 16:22:53 +09:00
Moreal 21ae739eec Check downcast to type first 2024-04-15 16:22:53 +09:00
Moreal b1c3c9a9d6 Bump CPython version to 3.12.3 in CI 2024-04-14 13:07:13 +09:00
Moreal bf985c8ac6 Fix None.__ne__ bug 2024-04-14 13:07:13 +09:00
Moreal 21c5eae717 Add testcase for __ne__ method 2024-04-14 13:07:13 +09:00
Lee Dogeon 4d5cf249a0 Allow update __class__ for mutable types or module subclasses (#5225)
* Allow update `__class__` for module subclasses

* Set `IMMUTABLETYPE` flag for static classes

* Unmark fixed tests
2024-04-14 13:03:48 +09:00
Lee Dogeon 1fa69ebcc9 sqlite: Throw TypeError when callable is not callable (#4923) 2023-04-22 07:10:44 +09:00
Lee DogeonandJim Fasarakis-Hilliard 8284a7cb89 Import from collections.abc instead of _collections_abc
Co-authored-by: Jim Fasarakis-Hilliard <d.f.hilliard@gmail.com>
2023-01-24 15:51:47 +09:00