Preserve newly merged Python 3.14 compatibility work before applying the three required final-3.15 contract adjustments exposed by merge CI.
Assisted-by: OpenAI Codex:model identifier unavailable
Keep the existing conversion and initialization path while binding format as positional-or-keyword, matching Python 3.14.
Assisted-by: OpenAI Codex:model identifier unavailable
Preserve the wrapper-pickle regressions merged into main while refreshing the independent length checks.
Assisted-by: OpenAI Codex:model identifier unavailable
Preserve existing coverage while following verified final behavior for script metadata, builtin signatures and loading, AST fixture construction, memoryview diagnostics, mmap search bounds, and struct format errors. The unchanged final comparator exposes the earlier expectations; focused native baseline failures establish the required implementation changes.
Assisted-by: OpenAI Codex:model identifier unavailable
* Cover Windows time conversion error classes
Require OSError with EINVAL for representable timestamps rejected by the Windows C runtime, while preserving OverflowError for float(2**63). This initial regression-only commit intentionally exposes the current Windows error mapping before the implementation follows.
AI assistance covered source comparison, regression design, and automated Linux baseline/reference controls. Native Windows results are pending. No human validation is claimed.
Assisted-by: Codex:model-version-unavailable
* Record native Windows time conversion outcomes
The first hosted regression run failed on CPython 3.14.7 as well as RustPython because a presumed-invalid CRT timestamp succeeded. Add bounded diagnostics before the unchanged assertions to capture full version/build metadata and every conversion result, including negative half-day controls. No implementation or canonical test changes are included.
The existing time snippet still passes the repository pytest runner on Linux CPython 3.14.7 and the current RustPython baseline. Native diagnostic results remain pending.
Assisted-by: Codex:model-version-unavailable
* Use the observed UCRT rejection boundary in time regression
Hosted Windows diagnostics show that CPython 3.14.7 and RustPython both accept gmtime(-1) and gmtime(-43200), while -86400 is rejected by all three converters. Correct only the newly added shared negative test value. CPython raises OSError(errno 22) for every selected rejected value, while the RustPython baseline raises OverflowError. Canonical tests and the recorded diagnostics remain unchanged.
The existing snippet passes both Linux reference and baseline controls. Assisted source investigation and automated verification used no manual validation.
Assisted-by: Codex:model-version-unavailable
* Preserve Windows CRT time conversion errors
Return CRT errno failures from the Windows calendar helpers and translate them to Python OSError. Adapt the datetime caller while retaining its Unix behavior. Use an exclusive signed float upper bound so float(2**63) still raises OverflowError before reaching the CRT.
Keep Windows negative-time FILETIME fallback and time64 ABI changes outside this Python 3.14 extraction. Existing datetime local-error coverage is retained and a UTC error control is added for the observed rejected timestamp -86400.
Hosted native diagnostics prove CPython 3.14.7 raises OSError(errno 22) where the baseline raises OverflowError. Windows-GNU host_env check and warnings-denied Clippy pass. Selected canonical datetime and complete time/datetime snippet Linux controls pass, with six existing baseline canonical skips. Fixed native Windows verification remains pending CI.
AI assistance covered source comparison, implementation, regression design, and automated verification. No manual validation is claimed.
Assisted-by: Codex:model-version-unavailable
* Reject empty quoted POSIX timezone abbreviations
Split the Python 3.14-compatible parser guard from #8954. Cover empty standard and daylight-saving abbreviations and preserve valid quoted names.
Assisted-by: OpenAI Codex:model identifier unavailable
* Keep zoneinfo regression in module snippet
Rename the snippet as requested during review without changing test contents.
Assisted-by: OpenAI Codex:model identifier unavailable
Collect raw dialect fields and keyword overrides before converting them in CPython 3.14 order. Preserve truth-conversion exceptions, read classes without instantiating them, and retain defaulting for failed attribute lookup.
Use one shared parser for reader, writer, registry, and native dialect construction. Extend the existing CSV snippet with class, instance, direct-construction, lookup, override, conversion-order, and argument-binding regressions.
Assisted-by: OpenAI Codex:model identifier unavailable
Use the natural logarithm path for both operands, evaluating x first. Preserve large integer bases and raise ZeroDivisionError for base one while retaining noninteger conversion errors.
Split the Python 3.14-compatible behavior from #8954 without its additional __index__ fallback or changes to log2 and log10.
Assisted-by: OpenAI Codex:model identifier unavailable
Split the Python 3.14-compatible empty native dictionary fast path from #8954. Extend the existing JSON snippet with root, nested, sorting, and nonempty subclass regression coverage.
Assisted-by: OpenAI Codex:model identifier unavailable
* Synchronize mmap buffer exports with close and resize
Assisted-by: Codex:gpt-6
* Keep mmap export checks ahead of data locks
Assisted-by: Codex:gpt-6
* Prevent ContextVar cache hits after Context address reuse
Give each Context, including copies, a non-reused cache identity instead
of using its heap address. Disable cache hits if the identity counter
saturates. This prevents an empty Context from reading a destroyed
Context's cached value while preserving existing locking and drop order.
Assisted-by: Codex:model-version-unavailable
* Cover ContextVar reads after context destruction
Exercise fresh and copied contexts with variable defaults, explicit defaults and missing values. The repeated lifecycle check complements canonical context tests without relying on a fixed allocator address-reuse count.
Assisted-by: Codex:model-version-unavailable
* Move ContextVar cache regression into the contextvars snippet
Preserve the fresh and copied Context lifetime checks, defaults and missing-value assertions while removing the redundant Rust interpreter wrapper.
Assisted-by: Codex:model-version-unavailable
* Take re pos/endpos as signed integers
Negative values clamp to 0, and values beyond Py_ssize_t raise
OverflowError.
Assisted-by: Claude Code:claude-opus-5-5
* Port the remaining runtime fixes from #7993
- bytearray: keep the buffer exported while converting the needle of
find/count/index/rfind/rindex/__contains__/split/rsplit and the hex
separator, so resizing from there raises BufferError
- str(): report non-str encoding/errors as "str() argument 'X' must be
str, not T", and check argument counts and name/position duplicates
for keyword calls
- _json.scanstring: take end as a signed integer and raise ValueError
when it is out of bounds
- lzma: reject filter specs with keys the filter does not take
- mmap: raise ValueError when growing a shared anonymous mapping on
Linux/NetBSD
- _sqlite3: check that the backup progress argument is callable
- Remove the expectedFailure markers of the tests these fix
Assisted-by: Claude Code:claude-opus-5-5
* Reject arguments given by name and position in FuncArgs::bind_for
bind_for reports a keyword that fills a parameter already given by
position before other binding errors, using the parameter list of the
FromArgs type. getargs shares the message, str() drops its own check,
and blake2b/blake2s name themselves in binding errors.
Assisted-by: Claude Code:claude-opus-5-5
---------
Co-authored-by: James David Clarke <james@jamesdavidclarke.com>
* vm: drop trailing space from RecursionError text
Format Python-limit and native-stack RecursionError messages
through one helper so empty context is not a trailing space
or an empty string.
Assisted-by: Grok 4.6
* test: deepen nested hash snippets for release stack frames
The cold RecursionError helper thins with_recursion's hot frame,
so 100_000 nested hashes no longer trip the native stack guard
in release.
Assisted-by: Grok 4.6
* vm: let RecursionError callers own the where-clause space
The helper concatenates an empty suffix or one that already
starts with a space. Call sites supply that space.
Assisted-by: Grok 4.6
#8828 made bin(), chr() and several other arguments that were bound
as PyIntRef go through __index__, but these still downcast to int and
reject an object that only defines __index__: the start and end of the
str/bytes/bytearray find family, enumerate(start=),
itertools.combinations/combinations_with_replacement/batched,
_thread.stack_size, resource.getrlimit/setrlimit, pwd.getpwuid,
grp.getgrgid, fcntl.fcntl/lockf and mmap.move/madvise. CPython converts
all of them with _PyNumber_Index or _PyEval_SliceIndex.
Bind them as ArgIndex, as #8828 did for the others.
test_mmap.test_madvise and test_mmap_closed_by_int_scenarios now pass,
so drop their expectedFailure markers.
Assisted-by: Claude Code:claude-opus-5-5
* Match CPython's SyntaxError range for unparenthesized `except` types
CPython's `invalid_except_stmt` rule raises the error only once the whole
clause has matched, and reports a range that starts at the first exception
type and ends at the `:` closing the clause, so it covers the `as NAME`
part as well:
invalid_except_stmt:
| 'except' a=expression ',' expressions 'as' NAME ':' {
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types
must be parenthesized when using 'as'") }
The parser reports the exception types alone, so look up that `:` in the
source and widen the range to match. Only `as NAME` may follow the
exception types, which is why the first `:` after them is the one closing
the clause.
try:
pass
except A, B, C as e:
pass
CPython 3.14: ('x.py', 3, 8, 'except A, B, C as e:\n', 3, 20)
before: ('x.py', 3, 8, 'except A, B, C as e:\n', 3, 15)
Fixes#8496
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Clarify that the `except` error range stops before the closing colon
`invalid_except_stmt_end` returns the exclusive end of the range, so the
column it yields is the one the `:` sits on even though the `:` is not part
of the range. The previous "ending at the `:`" wording read as if the colon
were included, which invites an off-by-one "fix".
Comments only; no behavior change.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Fix the `except ... as` error column for non-ASCII names and line joins
`invalid_except_stmt_end` recovers the end of CPython's range by scanning the
source, which has to redo by hand what CPython gets from its tokenizer:
- The column was the byte distance from the line start, but `end_offset` is a
character column. `except Ä, B as e:` reported 18 instead of 17. CPython
converts explicitly, in `_PyPegen_byte_offset_to_character_offset`.
- The colon scan already spans explicit line joins, but the `as` check ran on
the raw slice, so a `\` before `as` left the range unextended.
`except A, B \` + `as exc:` reported (3, 12) instead of (4, 7).
Add regression cases to `syntax_invalid.py` covering both, plus the whitespace,
`except*` and line-join placements that already worked. All values are verified
against CPython 3.14.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Update the Ruff fork to 0.16.10
Point the rustpython-ruff_* dependencies at the 0.16.10-rustpython tag
of the RustPython Ruff fork and port to its AST changes:
`ExprCompare` stores all operands in `operands`, call arguments use
`ThinVec`, dict comprehension generators and f-string elements are boxed
slices, `FStringValue` iterates `FStringPartRef`, and `TokenKind::Name`
is now `TokenKind::Identifier`.
Assisted-by: Grok:grok-4.6
Assisted-by: Claude Code:claude-opus-5-5
* Drop the source scan for the `except ... as` error range
The parser now reports the unparenthesized exception types error with a
range ending at the `:` that closes the clause, so
`invalid_except_stmt_end` and the message match that widened the range
are removed.
Assisted-by: Claude Code:claude-opus-5-5
* Take parse error messages from the parser as they are
The Ruff fork now emits the final message texts, so `vm_new.rs` no
longer rewrites parse error messages by matching their text and no
longer lowercases the first character of every message.
`analyze_compile_error` keeps only the caret narrowing for starred
expressions and the line number in the unterminated string message.
The compiler matches the new lowercase texts for indented block and
mixed bytes literal errors.
The fork is referenced by revision until it is published.
Assisted-by: Claude Code:claude-opus-5-5
* Take starred and bytes literal error ranges from the parser
The Ruff fork now reports misplaced starred expressions at the `*` and
non-ASCII bytes literal errors over the whole literal. `vm_new.rs` drops
`narrow_caret` together with `SyntaxErrorInfo`, which only carried the
message after that, and the compiler drops `bytes_literal_span`.
Assisted-by: Claude Code:claude-opus-5-5
* Take indentation error kinds and positions from the parser
The Ruff fork now reports `TabError` and `TooDeepIndentation` as their
own lexer errors and places indentation and line continuation errors
itself. `vm_new.rs` picks TabError or IndentationError from the error
kind instead of scanning the source for mixed indentation, drops the
TabError message override, and sets the end offset of tokenizer errors
to 0 or -1 by kind. The compiler drops the line-end relocation of
unindent errors and the line continuation rewrite. `_tokenize` raises
TabError and depth errors for the token they replace, also for sources
containing tabs.
Remove expectedFailure from test_tokenize.test_max_indent and four
test_tabnanny tests.
Assisted-by: Claude Code:claude-opus-5-5
* Take unterminated string messages from the parser
The Ruff fork's unterminated string errors now include the detected
line and are reported at the start of the string. `vm_new.rs` drops its
message override for `UnclosedStringError`, and the shell continues a
line on an unterminated triple-quoted string by the error's
`triple_quoted` flag instead of reading the quotes from the source.
Assisted-by: Claude Code:claude-opus-5-5
* Take bracket errors and tokenizer error priority from the parser
Bump the ruff fork, which now reports unmatched, mismatched, unclosed
and too deeply nested brackets and decides whether a tokenizer error
replaces the parser's first error.
Remove the bracket, unterminated string and nesting depth source
scanners and `pre_parse_source_error`. A tokenizer error from the
parser now wins over source scanner diagnostics found after it. An
unclosed bracket is incomplete input only when the parser reports it
as such, and other tokenizer errors end where they start.
Remove the expected failure markers from test_unicode_identifiers
test_invalid and the `import ä £` doctest in test_syntax.
Assisted-by: Claude Code:claude-opus-5-5
* Take number literal, string prefix and non-printable errors from the parser
Bump the ruff fork, which now reports malformed number literals,
incompatible string prefixes and non-printable characters itself.
Remove the number literal, string prefix and non-printable character
source scanners and the override classes that ranked them. Leading zero
and string prefix errors keep their range instead of ending where they
start.
Assisted-by: Claude Code:claude-opus-5-5
* Take the missing indented block error from the parser
Bump the ruff fork, which now reports `ExpectedIndentedBlock` with the
clause and the line of its header keyword.
Remove the message rewrite that derived the clause and line from the
source. The VM chooses IndentationError or incomplete input by the
error variant instead of its message.
Assisted-by: Claude Code:claude-opus-5-5
* Take binding target errors from the parser
Bump the ruff fork, which now names the invalid expression in
assignment, augmented assignment, delete, `for`, `with`, import,
pattern and `except` target errors.
Remove the source scanners for those targets and the message rewrites
of `InvalidAssignmentTarget` and `InvalidNamedAssignmentTarget`.
Remove the expected failure markers from test_syntax doctests that now
pass.
Assisted-by: Claude Code:claude-opus-5-5
* Take parameter, argument, star, comma and dictionary errors from the parser
Bump the ruff fork to 36919b62fa. Remove the source scanners for type
parameters, parameter lists, star annotations, call arguments, def type
parameters, parenthesized groups, missing commas and dictionary items.
Set end_offset 0 for ExpectedColonAfterDictionaryKey. Remove 14
EXPECTED_FAILURE markers in test_syntax and test_unpack_ex.
Assisted-by: Claude Code:claude-opus-5-5
* Take expression errors from the parser
Bump the ruff fork to 4f922d2124. Remove the source scanners for
comprehensions, collection and condition assignments, expressions
between strings, named expression targets, missing `in` after for-loop
variables and statements in `if` expressions. Remove the now passing
expected failure markers in test_syntax and test_named_expressions.
Assisted-by: Claude Code:claude-opus-5-5
* Take statement errors from the parser
Bump the ruff fork to c7f6594ed6. Remove the source scanners for
standalone except, `import ... from`, `**_` mapping rests, `elif` after
`else` and mixed except handlers, and the post-parse scanners for call
arguments, match targets, yield after a comma and parenthesized star
imports.
Assisted-by: Claude Code:claude-opus-5-5
* Take string and f-string errors from the parser
Bump the ruff fork to 6b46d0dfc8. Remove the source scanners for
malformed `\N` escapes, f-string and t-string replacement fields, mixed
t-string literals and `print`/`exec` statements, and the override
plumbing they used. Drop the `f'{x'; '` case from the compiler test,
whose expected message differs from CPython 3.14.
Assisted-by: Claude Code:claude-opus-5-5
* Restore the bracket depth check and fix incomplete unclosed strings
Restore `pre_parse_source_error`, which rejects bracket nesting past 200
levels before parsing. The parser reports the same error but still
builds the full tree, which overflows the native stack when dropped.
Remove the VM's unclosed string scanner, which ignored the mode and
treated `'abc` in exec mode as incomplete input. The compiler's check
now skips escaped newlines.
Assisted-by: Claude Code:claude-opus-5-5
* Report multiple statements before later errors in single mode
In single mode, when the first statement is a simple statement, report
code after its line as multiple statements before any error found
later, at the newline token or the comment before it. This replaces the
multiple statements check on the parsed body and also applies to
`ast.parse(mode='single')`.
An unclosed string that follows an earlier syntax error is no longer
incomplete input. The bracket depth error range is now empty.
Assisted-by: Claude Code:claude-opus-5-5
* Update the Ruff fork for parser speed and starred annotations
Bump the ruff fork to 8b59b85344, which skips the tokenizer error pass
when parsing finds no errors, stops allocating for every identifier's
string prefix check, and reports `def f(*args: *b = ...)` as invalid
syntax.
Remove expected failure markers from test_code_module
test_indentation_error and test_sysexcepthook_indentation_error, and
from test_dictcomps test_illegal_assignment.
Assisted-by: Claude Code:claude-opus-5-5
* Use the published Ruff fork 0.16.10 crates
Switch the rustpython-ruff_* dependencies from the git revision to the
0.16.10 crates.io release, published from the same commit (8b59b85344).
Assisted-by: Claude Code:claude-opus-5-5
---------
Co-authored-by: zzarbttoo <qodbwls70@naver.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* Match CPython's str subscript TypeError message
`str.__getitem__` with a non-index key raised the shared sequence
wording ("str indices must be integers or slices or classes that
override __index__ operator, not 'x'") instead of CPython's
str-specific "string indices must be integers, not 'x'" (bpo-44110 /
gh-88276, Python 3.11).
Add `SequenceIndex::try_from_borrowed_object_with_err`, which takes a
caller-supplied error closure, and have the existing
`try_from_borrowed_object` delegate to it with the unchanged shared
message. `str._getitem` now supplies the CPython-accurate message,
which flows through both `__getitem__` and the mapping subscript slot.
Other sequence types keep the shared wording.
Removes the expectedFailure marker on
`string_tests.StringLikeTest.test_subscript`, fixing it for both
test_str and test_userstring.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Fold str's subscript TypeError into the shared index helper
The previous commit added `SequenceIndex::try_from_borrowed_object_with_err`
(a closure-taking function) so `str` could raise CPython's
"string indices must be integers, not ..." message. Per review, a whole
helper API plus a thin wrapper was overkill for a single caller.
Instead, inline that one error case into `try_from_borrowed_object`: when
`type_name` is "str", raise the str-specific message; every other type keeps
the shared sequence wording. `str._getitem` goes back to the plain `match`
over `SequenceIndex` with no duplicated index parsing. A bad slice key
(e.g. `'a'[::'x']`) still surfaces the slice-specific error, since only the
non-index/non-slice branch is customized.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Truncate index TypeError type names to 200 characters
Route str's non-index TypeError through a function pointer
message helper. Sequence index errors use the same 200-character
type-name cap.
Assisted-by: Grok:4.6
* Encode sequence index TypeError names as type params
`&'static str` cannot be a const generic. SequenceIndexName
holds the name as an associated constant, matching ArgName.
Both str and sequence errors go through one fn(&str) -> String
and a cold TypeError helper.
Assisted-by: Grok:4.6
---------
Co-authored-by: Jaedeok Kim <rn.6d17s2@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* Use populated entries for unpickler MEMOIZE indexes
A sparse BINPUT followed by MEMOIZE must use the number of occupied memo
entries, not the largest index plus one. Store populated entries in a map,
preserve ascending memo copies, reserve fallibly, and release displaced
references after memo guards end.
Keep existing memo assignment/proxy behavior and add one bounded regression
for sparse BINPUT, MEMOIZE identity and copy order. No protocol version,
GC traversal or unrelated pickle input changes are included.
Extracted from the Python 3.15 migration onto the unchanged 3.14 target.
Assisted-by: Codex:model-version-unavailable
* Move sparse memo regression to standard pickle snippet
Use the module-level snippet name requested in review without changing the regression assertions.
Assisted-by: Codex:model-version-unavailable
Let quote-only fields use the existing unquoted escaping path and enable
the existing CPython regression test.
Tested: test_csv, CSV snippet, 240 CPython comparisons, workspace and C-API tests, Clippy, prek
Assisted-by: Codex:gpt-6.1-sol
* Add a native _zoneinfo module
ZoneInfo reads TZif tuples from zoneinfo._common.load_data. The stdlib
module implements utcoffset, dst, tzname, fromutc, and the zone cache.
whats_left compares that class. Cache tests no longer expect failure.
Assisted-by: Grok:grok-4.7
* Fix ZoneInfo layout and keep its cache on the module
utcoffset, dst, and tzname take the object. Zone data is boxed so the
payload lines up with tzinfo on 32-bit. The strong, weak, and timedelta
caches live on each interpreter's _zoneinfo module.
Assisted-by: Grok:grok-4.7
Some of the FFI wrappers take in a byte slice that's presumed to be NUL
capped. It's more ergonomic and safer to take in a &CStr which is
impossible to get wrong because it's validated at the margins.
Additionally, there were a few areas where a NUL was embedded directly
into the source (i.e. "COMMIT(NUL)" which displayed as "COMMIT^@"). This
had the interesting effect of breaking grep on the source code.
* Report errors from #[pyclass] trait items
The trait branch of impl_pyclass_impl built its own ImplContext, so the
errors collected while extracting trait items were never emitted: an
invalid #[pymethod] or #[pygetset] in a #[pyclass] trait was left out of
the class without a compile error. The trait branch now uses the shared
context whose errors are emitted.
Assisted-by: Claude Code:claude-opus-5-5
* Pass the object to #[pymethod] and #[pygetset] receivers outside vm
Outside crates/vm, where impl Py<T> cannot be written, #[pymethod] and
#[pygetset] receivers that took &self become zelf: &Py<Self> inside the
existing impl T blocks. Where Rust code calls one of these methods on a
payload value, the logic stays in a payload method and the Python method
forwards to it.
Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Reject payload receivers on #[pymethod] and #[pygetset]
A #[pymethod] or #[pygetset] item with a self receiver is now a compile
error when self is the payload: in an impl for T rather than Py<T> or
PyRef<T>, and in a #[pyclass] trait. The error points to taking
zelf: &Py<Self> or zelf: PyRef<Self>, or defining the item in impl Py<T>.
Assisted-by: Claude Code:claude-opus-5-5
* Pass the object to the layout test getter
The subclass layout test's extra getter is a #[pygetset] on the
payload. Take zelf: &Py<Self> so the receiver is the object.
Assisted-by: Grok:4.7
* Set builtin __doc__, __module__, and datetime signatures
Expose empty doc-db member entries as ''. Heap __dict__ and __weakref__
getsets carry their descriptor docs. Member repr uses the qualified
type name.
__module__ is collections for the deque iterators, _csv for Dialect,
ctypes for ArgumentError and CField, _lzma for LZMAError, operator for
the getter types, pickle for PickleBuffer, _ssl for MemoryBIO,
SSLSession, _SSLContext and _SSLSocket, weakref for the proxy types,
and posix (nt on Windows) for times_result and uname_result.
unicodedata's copied UCD functions set __module__ to unicodedata.
_testinternalcapi function docs and weakproxy.__str__ use the stored
text. datetime replace defaults render as unchanged, __replace__ is
($self, /, **changes) and binds through replace, now defaults tz to
None, and fromisoformat and tzinfo methods name the parameter object.
Assisted-by: Grok:grok-4.7
* Move doctext helpers above the test module
db_slice and docs sat after mod tests.
Remove expectedFailure from test_html_doc, test_text_doc,
test_help_output_redirect, test_method_aliases, and test_long_signatures.
Assisted-by: Grok:grok-4.7
* Record native docstrings the doc DB generator skipped
- Stop ignoring `__dir__`; skip `__base__`, `__bases__` and `__module__` instead.
- Recurse into native classes whose metaclass is not `type`, and also key a
class stored under another attribute name by its own `__name__`.
- Collect native objects exposed by pure-Python modules, such as the codec
error handlers, under their own `__module__` and `__name__`.
- Key types found through `object.__subclasses__()` by their own module as
well as `builtins`.
- Record getset/member descriptors named like class metadata
(`coroutine.__name__`), and native types a module exposes only through an
instance (`sys.flags`).
- Treat a class as native only when it owns its C descriptors, so an enum
holding a copied `str.__format__` is skipped.
- Keep docstrings unstripped, and import every module in sorted order before
walking them.
- Apply the resulting key delta, measured on macOS with CPython 3.14.7, to
data.inc.rs.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Stop Rust comments on Python items from becoming __doc__
Use `//` instead of `///` on Python-exposed items so their comments are not
published as `__doc__`.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Match native names, signatures and doc lookup
- Rename the weakref type to `weakref.ReferenceType` and define
`__class_getitem__` on `_ctypes.Array` instead of its metaclass.
- Give each name of a multi-name `#[pymodule(sub)]` function
(`posix.remove`/`unlink`) its database doc.
- Fill methods from `with(...)` traits (dict view `__reversed__`,
`isdisjoint`) with the implementing class's database doc.
- Resolve database docs for `#[pymodule]` classes at macro time, and for the
codec error handlers and `_lzma.LZMAError` in const context.
- Add `Context::new_exception_type_with_doc`.
- Match `posix_spawn` parameter names and defaults, make `dict_keys` and
`dict_items` unhashable, add `_CData.__ctypes_from_outparam__`, and omit
the Windows-only lines of `sys.__doc__` on other platforms.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Give struct sequence fields their database docs
`new_readonly_tuple_member` takes the field doc, looked up in the class's
attribute doc table through the new `class_attr_item_doc`.
Assisted-by: Claude:claude-opus-5-5
* Look up pymodule(sub) docs by an explicit module name
posix and nt share one doc entry. A sub module sets name to the
Python module it is merged into, and doc lookup uses that name.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Record pending class doc bodies on PyMethodDef
The pymethod derive sets doc_body_pending when a method has no Rust
doc body and expansion did not resolve a database span.
concat_with_attr_docs copies that span from the class table and
clears the flag. Other constructors leave the flag false.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Name argument fields after their Python parameters
PosixSpawnArgs.args is renamed to argv, and nt's follow_symlinks field
drops a name override equal to the field name.
Assisted-by: Claude:claude-opus-5-5
* Address review findings on member descriptors
Member definitions carry an internal `PY_ATOMIC` flag taken from
`MemberLayout::ATOMIC`, and loads use an atomic access only for atomic
storage; extension members never set it. `XMLParser` publishes its new
state, `entity` and `target` only after every handler lookup succeeds.
`subs_parameters` reads type names only for the error. The unraisable
hook prints `<unknown>` when `__module__` fails or is not a str. The
builtin function `__reduce__` decides on the bound object alone.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Fix member layout assertions on 32-bit targets
The tp_flags assertion compared AtomicU64 with u64 alignment, which differs
on i686. The kevent assertion required usize, isize, c_ulong and c_long to be
64-bit. Both now check only what the member cells need.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Use bitflags for member definition flags
PY_READONLY, PY_AUDIT_READ, PY_RELATIVE_OFFSET and PY_ATOMIC become the
repr(transparent) PyMemberFlags. C extension flags are read with
from_bits_retain.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
Use `//` instead of `///` on Python-exposed items so their comments are not
published as `__doc__`.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* fix(contextvars): isolate context stack per interpreter and thread on VirtualMachine
* style: format and sort imports in extra_tests/snippets/stdlib_contextvars.py
Assisted-by: Antigravity:Gemini-3.8-Flash
* Read type.__module__ from the dict only for heap types
A static type's `__module__` is the text before the last `.` of its name,
or `builtins`. A heap type reads its dict and raises `AttributeError`
when the entry is missing; `type` and `object` reprs ignore that error.
`type()` no longer stores `__module__ = None` when the caller's globals
have no `__name__`.
`#[pyexception(module = ...)]` now reaches the type name, and static
types that relied on a dict `__module__` (ast nodes, pyexpat, ssl,
_hashlib and _interpchannels errors, ExceptionGroup) carry their module.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Expose more builtin attributes as member descriptors
`code.co_flags`, `co_nlocals`, `co_filename`, `super.__self__`,
`__self_class__`, `__thisclass__`, `traceback.tb_frame`, `tb_lasti`,
`type.__itemsize__` and `builtin_function_or_method.__module__` are now
`#[pymember]` fields instead of getsets. `super` keeps its three
references in atomic cells instead of a lock, `tb_lasti` is an `i32`,
`co_nlocals` is stored at construction, and the builtin function
`__module__` is a writable object cell.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Expose stdlib attributes as member descriptors
Decompressor `eof`/`needs_input`/`unused_data` (bz2, lzma, zlib, plus
lzma `check`), `ContextVar.name`, `functools.partial` `func`/`args`/
`keywords`, socket `family`/`type`/`proto`, `select.kevent` fields,
`SemLock` `handle`/`kind`/`maxvalue`/`name`, `Pickler.bin`/`fast`,
`xmlparser.intern`, ElementTree `XMLParser.entity`/`target`,
`UCD.unidata_version`, `_ExceptHookArgs` fields, multibytecodec
`stream`, and `_io` `Buffered*.raw` and `TextIOWrapper`
`buffer`/`encoding`/`line_buffering`/`write_through` are now
`#[pymember]` fields instead of getsets.
Values that changed under a lock move to atomic cells on the payload.
New member kinds `Short`, `Long`, `String`, `UShort`, `ULong`,
`LongLong` and `ULongLong` access exactly the width of their C type.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Match bare super and static type itemsize
`super.__new__(super)` leaves `__thisclass__`, `__self__` and
`__self_class__` empty, and a super with no type takes the
zero-argument path when bound.
Static types carry their `tp_itemsize` (`type`, `memoryview`, `code`,
`frame`, generators, `_sre` objects, `_ctypes` thunks), inherit it from
their direct base when they leave it at 0, and a variable-size base
rejects any nonempty `__slots__` and a weakref slot.
`_thread._ExceptHookArgs` is a struct sequence.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Expose SimpleNamespace.__dict__, __basicsize__ and __flags__ as members
`SimpleNamespace.__dict__` addresses the instance dict cell the same way
`module.__dict__` does. `slots.basicsize` now holds the full
`tp_basicsize` (header plus payload), so `__basicsize__` reads it
directly. Type flags are one atomic word: `__abstractmethods__` and
`_abc` set their bits in it in place, the separate `abc_tpflags` word is
gone, and `__flags__` reads the word as an unsigned long member.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Skip Python-defined classes when collecting builtin type docs
generate.py recorded every object.__subclasses__() entry as builtins.<name>
after importing the whole stdlib, so classes written in Python (tkinter,
unittest, tarfile, ...) ended up in the doc database. Classes that are
mutable heap types without C method descriptors and whose module is not a
C extension are now skipped, and their entries are removed from
data.inc.rs.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Store database docstrings xz-compressed behind an optional doc feature
- rustpython-doc's build script compresses all database docstrings into
one xz blob with an offset index; identical texts share one offset.
- Macros emit blob references for database docs; vm decompresses the
blob on first access.
- New `doc` cargo feature (default on) in rustpython, rustpython-vm and
rustpython-stdlib. Without it the blob and xz are not linked and
database-backed __doc__ is None; __text_signature__ is unaffected.
- Native types without a docstring get __doc__ = None in their dict.
- Workflows that build with --no-default-features enable `doc` where
tests or releases need docstrings.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Address builtin members by field offset
`#[pymember]` now declares a field of the payload and generates a
PyMemberDef whose offset is the payload offset plus the field offset.
The getter/setter function form and `MemberAccess::Func` are removed;
builtin, slot, and C-API members share one get/set path. The macro
checks the field type against the member type.
Converted members: property fget/fset/fdel/__doc__, function
__globals__/__closure__/__builtins__/__doc__/__module__, staticmethod
and classmethod __func__/__wrapped__, complex real/imag (T_DOUBLE),
frame f_trace_lines (T_BOOL), defaultdict default_factory, getset and
member descriptor __name__/__objclass__, module __dict__.
frame.f_trace_opcodes is a getset.
Writable member fields are atomic pointer cells. The instance dict
pointer is an atomic cell at a fixed offset in front of the object,
and dict presence follows the type's HAS_DICT flag. The pickle
basicsize check no longer counts dict, weakref, and slot storage,
which live outside the payload.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Address member review findings
- `#[pymember]` keeps leading `#[cfg]` attributes on the generated
registration, and malformed `field`/`offset` values are compile
errors.
- The `descriptor` module and the items the expansion names are public.
- Writable double members are an `AtomicU64` cell, loaded and stored
with relaxed atomics. Readonly double members stay plain `f64` reads.
- `LOAD_ATTR_SLOT` is not specialized for `Py_AUDIT_READ` members.
- `defaultdict.__reduce__` passes no factory argument when
`default_factory` is None.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Declare members on payload fields
`#[pymember]` goes on a payload struct field, or on the struct with an
explicit `offset` when the storage is not a payload field. The struct
`#[pyclass]` builds `PyClassDef::MEMBERS`, a static `PyMemberSpec`
table, and `extend_class` registers one member descriptor per entry.
`path` addresses a subfield, one field may carry several members, and a
`#[cfg]` on the field gates its entry. The impl-side const form is
removed and now a compile error.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Split nullable and non-null atomic cells
The nullable cell API (`new_empty`, `load_owned`, `store`,
`compare_exchange_empty`) moves from `PyAtomicRef<PyObject>` to
`PyAtomicRef<Option<PyObject>>`, and the typed `PyAtomicRef<Option<T>>`
shares it. The non-null `PyAtomicRef<PyObject>` gets `load_owned` and
`store` that return the object directly.
Slot cells, property fget/fset/fdel/__doc__, and defaultdict
default_factory are nullable cells. staticmethod and classmethod
callable are non-null cells and are read without `unwrap`. The
instance dict cell is `PyAtomicRef<Option<PyDict>>`, so reading it no
longer downcasts.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Drop the unused cold trace_lines flag
`FrameColdData::trace_lines` had no writer after `f_trace_lines`
became a frame object member. A frame without a frame object traces
lines by default.
Assisted-by: Claude:claude-opus-5-5
* Compute payload offsets from the merged Py header
`PyInner` is now `Py`, so the payload offset and the dict member
offset are measured from `Py<T>`.
Assisted-by: Claude:claude-opus-5-5
* Expose descriptor names and owner types as members
method_descriptor, classmethod_descriptor, and wrapper_descriptor
expose `__objclass__` and `__name__` as readonly members, and
method-wrapper exposes `__self__` as a readonly member. The separate
`objclass` field of method and classmethod descriptors always equaled
`common.typ` and is removed.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Expose remaining builtin tp_members as members
Attributes stored in a payload field become readonly or writable
member descriptors: bound method __func__/__self__, code
co_argcount/co_posonlyargcount/co_kwonlyargcount/co_stacksize (Py_T_UINT),
generic alias, coroutine and async generator members, interpolation and
template, range and slice start/stop/step, type __base__, union, and the
typing TypeVar, ParamSpec, TypeVarTuple, and TypeAliasType members.
`MemberKind` gains `Int` and `Uint` with the `PyMember_GetOne`/`SetOne`
range checks.
Attributes computed on access or kept behind a lock stay getsets.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Spell a docless member as doc = false
`#[pymember(doc = false)]` stores no docstring, matching the
`doc = "..."` form, and replaces the separate `no_doc` flag.
Assisted-by: Claude:claude-opus-5-5
* Make pymember readonly by default
`#[pymember]` declares a readonly member unless `writable` is given.
The `readonly` option is removed and every declaration is converted.
Assisted-by: Claude:claude-opus-5-5
* Check the receiver of method descriptors
Binding or calling a method_descriptor with an object that is not an
instance of the owner type raises TypeError before the native function
runs. Static and class methods are exempt.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Expose exception attributes as members
BaseException.__suppress_context__, StopIteration.value, SystemExit.code,
ImportError, NameError, AttributeError, OSError, SyntaxError,
BaseExceptionGroup and the UnicodeEncode/Decode/TranslateError attributes
are member descriptors backed by payload fields. ImportError, NameError,
AttributeError and SyntaxError gain payloads for their fields, and the
methods that read those attributes read the fields. Add the Py_ssize_t
member kind for UnicodeError start and end.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Avoid same-type casts in unsigned member conversion
On targets where c_ulong is u32, casting through c_ulong was a no-op
cast that clippy rejects.
Assisted-by: Claude:claude-opus-5-5
* Prefer an explicit pymember doc over the doc table
doc = "text" is used as the docstring without consulting the stored
attribute documentation; only an omitted doc looks it up. Drop the member
doc strings that repeated the stored documentation.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Infer pymember kinds from field types
MemberLayout gives the member kind of each accepted field type, and the
macro reads it from the field or path subfield, so type = "bool" and
the other numeric spellings are gone. type only selects object_ex.
Writable doubles use a new AtomicF64 cell instead of AtomicU64 bits.
MemberLayout and MemberCell replace the per-kind marker traits.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Read nullable atomic cells only through load_owned
PyAtomicRef<Option<T>> and PyAtomicRef<Option<PyObject>> lose to_owned,
to_owned_ordering and try_to_owned; load_owned, which retries the
incref until it applies to the pointer still in the cell, is the one
owned read. Callers that kept a deref borrow across VM calls now take a
strong reference.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Inherit static type slots from the whole MRO
extend_class copied slots only from the direct bases, and tp_init is
copied only from a base that defines it, so TabError missed the
SyntaxError init that IndentationError inherits. Walk the MRO the same
way init_slots does.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Let Rust doc comments win over stored docstrings
A /// comment on a Python-exposed item is its docstring; the
rustpython-doc entry is used only when there is none. #[pymember] reads
the field's /// comment instead of doc = "...". Doc comments that were
shadowed by a stored docstring become // comments, so no docstring
changes. AGENTS.md describes the rule.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Adapt members to upstream changes
_collections._tuplegetter.__doc__ is a writable nullable member on the
payload field. The impl-side const form no longer compiles.
Assisted-by: Grok:4.7
* Drop docstring text left as comments and inline downcast_cell
Comments that only repeated an item's docstring are removed; developer
notes stay as // comments. The typed cell methods call
downcast_unchecked directly, each with its own safety note.
Assisted-by: Grok:4.7
Assisted-by: Claude:claude-opus-5-5
* Read sqlite row factories through load_owned
The nullable cell no longer has to_owned; the sqlite module is built only
with the sqlite feature, so the default build did not catch it.
Assisted-by: Claude:claude-opus-5-5
* Read PyTuple payloads through as_slice()
- Add Py<PyTuple<R>>::as_slice(); it is generic over R, so typed tuples use
the same view.
- Callers reach slice methods, indexing and slice arguments through
as_slice().
- PyTuple's own sequence and mapping slots and marshal's set_marshal_item reach
the remaining PyTuple methods through the payload field.
- The Py<T>::payload field is pub(crate).
Assisted-by: Claude Code:claude-opus-5-5
* Read PyBytes payloads through as_bytes()
- Callers read bytes through Py<PyBytes>::as_bytes().
- bytes.rs reaches PyBytesInner and the remaining PyBytes methods through
the payload field; fspath and os call payload.contains_nuls().
- DictKey for [u8] falls back to the PyObject key_eq; it previously resolved
to its own key_eq through Deref.
Assisted-by: Claude Code:claude-opus-5-5
* Copy capi tuple arguments with as_slice().to_vec()
Assisted-by: Claude Code:claude-opus-5-5
* Read sqlite3 Row tuples through as_slice()
Assisted-by: Claude Code:claude-opus-5-5
* Read platform-specific tuples and bytes through as_slice() and as_bytes()
Assisted-by: Claude Code:claude-opus-5-5
* Read PyInt and PyFloat payloads through as_bigint() and to_f64()
Add `Py<PyInt>::as_bigint()`, `Py<PyInt>::try_to_primitive()` and
`Py<PyFloat>::to_f64()`, which forward to the payload methods of the same
name. Reads of the `value` field and primitive conversions go through
these views; other PyInt and PyFloat methods are called through the
`payload` field inside rustpython-vm and through payload() outside it.
Assisted-by: Claude Code:claude-opus-5-5
* Read PyComplex payloads through as_complex()
Add Py<PyComplex>::as_complex() and use it at the call sites that
read the payload directly.
Assisted-by: Claude Code:claude-opus-5-5
* Move PyInt conversion helpers to Py<PyInt>
try_to_i64_fast(), to_str_radix_10(), as_u32_mask(), as_u64_mask(),
try_to_primitive() and try_to_primitive_raw() only read the integer
value, so they are defined on Py<PyInt> and callers no longer go through
the payload. PyRange computes its protocol length from the BigInt
directly instead of building a PyInt payload.
Assisted-by: Claude Code:claude-opus-5-5
* Share one conversion between try_to_primitive() and its OverflowError variant
Py<PyInt>::try_to_primitive() and try_to_primitive_in_range(), renamed
from try_to_primitive_raw(), both call to_primitive(). They differ only
in how a negative value for an unsigned type is reported: ValueError for
try_to_primitive(), OverflowError for try_to_primitive_in_range(). The
target type is bound with `for<'a> TryFrom<&'a BigInt>`, so the methods
no longer tie a lifetime to &self.
Assisted-by: Claude Code:claude-opus-5-5
* Move PyInt bitwise operators to Py<PyInt>
__xor__, __or__, __and__ and their int_op() helper are defined on
Py<PyInt>. PyBool calls them without going through the payload.
Assisted-by: Claude Code:claude-opus-5-5
* Move PyBytes operators to Py<PyBytes>
__add__, __contains__, __getitem__ and __mod__ are defined on
Py<PyBytes>. The subscript, contains and remainder slots call them
without going through the payload.
Assisted-by: Claude Code:claude-opus-5-5
* Move PyInt general_op() and modpow() to Py<PyInt>
The power slot calls them on Py<PyInt> without going through the
payload.
Assisted-by: Claude Code:claude-opus-5-5
* Accept `__index__` objects for integer arguments
CPython converts these nine arguments with `__index__`, RustPython
required an exact `int`. Uses the existing `ArgSize`/`ArgPrimitiveIndex`
converters at each call site rather than widening the blanket `int`
conversion, so argument paths CPython keeps strict (ctypes pointers,
thread handles) are unaffected, and the range check happens while the
argument is bound rather than in the method body.
Also widens `maxsplit` before adding one. `sys.maxsize` was already
reachable there with a plain `int` and overflowed in a debug build.
Assisted-by: Claude Code:claude-opus-5
* Add snippet for `__index__` argument conversion
Expectations verified against CPython 3.14.
Assisted-by: Claude Code:claude-opus-5
* Call __index__ in primitive integer conversion; add ArgStrictInt
The TryFromObject impls for isize, usize and the fixed-width integer
types now take an int (or subclass) as-is and otherwise call __index__,
instead of accepting only int instances.
ArgStrictInt<T> keeps the old int-only conversion. The ctypes address
and handle arguments (from_address, PyObj_FromPtr, dlsym, dlclose,
call_function, call_cdeclfunction, non-Windows FreeLibrary) use it.
_thread._make_thread_handle checks for an int itself and raises
"ident must be an integer".
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Accept __index__ where arguments were bound as int objects
chr, bin, math.factorial, zlib.crc32/adler32, binascii.crc32/crc_hqx,
the start/stop of sequence index(), the select event mask and a
__len__ result took an int object directly and rejected other objects
with __index__. They now go through __index__.
math.ldexp still accepts only an int for its exponent and raises
"Expected an int as second argument to ldexp." otherwise.
Extend protocol_index_argument.py with the newly accepted calls, an int
subclass whose __index__ is not called, and the sites that still
reject __index__.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Replace ArgPrimitiveIndex and ArgSize with PySsize/PySize aliases
The primitive integer conversions call __index__ themselves, so
ArgPrimitiveIndex<T> and its alias ArgSize behaved the same as T. They
are removed. Arguments that used ArgSize or ArgPrimitiveIndex<isize>
now take PySsize (= isize), ArgPrimitiveIndex<usize> takes PySize
(= usize), and the other ArgPrimitiveIndex<T> take T. Those with a
literal fallback take it as a `default`; those where a missing argument
is a distinct state stay OptionalArg.
list.insert is a #[pymethod] again instead of going through a wrapper.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
---------
Co-authored-by: Roshan Ramani <roshanramani.dev@gmail.com>
* Resolve class attribute docs at macro time and drop rustpython-doc from vm
- #[pyclass] and #[pystruct_sequence] emit a sorted PyClassDef::ATTR_DOCS
table from the doc database; attribute and slot docs look up that table.
- rustpython-vm no longer depends on rustpython-doc.
- _operator.attrgetter, itemgetter, methodcaller and object get
constructor Args with FromArgs::PARAMS, replacing the hardcoded class
signature docs in class.rs.
- methodcaller() with no arguments raises "methodcaller needs at least one
argument, the method name".
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Drop default values that equal the field type's default
Bare `default` on integer and bool fields already renders the zero value
in the text signature, so `default = 0` and `default = false` are
replaced with bare `default`.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Return the empty str singleton from Context::new_str
Assisted-by: Claude:claude-opus-5-5
* Speed up exec/eval and audited builtins when no audit hooks are set
Assisted-by: Claude Code:claude-opus-5-5
* move audit hooks from `VirtualMachine` to `PyGlobalState`
* addaudithook only appends once the lock
* sync with main
* Render CPython defaults in generated text signatures
Arguments whose default rendered as `<unrepresentable>`, while the
same callable has a representable default in CPython, now render that
default:
- Where the Rust value can be a literal, the argument becomes a plain
field with `default = <literal>`.
- The remaining cases keep their Rust default and add `py_default`
with a comment. These are wrappers such as ArgIntoFloat or
ArgIntoBool, values that need the VM, enums, and Option where None
means another value.
Byte string literals render as Python bytes. A function registered
under several names gets an internal doc per name, so its __doc__ no
longer carries the signature header.
Removed expectedFailure from test_pydoc tests that now pass.
Assisted-by: Grok:grok-4.7
Assisted-by: Claude:claude-opus-5-5
* Match native callable signatures to CPython names and kinds
Rename parameters and adjust positional-only / keyword-only kinds and
defaults of native functions and methods so their generated text
signatures match CPython. Remove expectedFailure markers from tests
that now pass.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Fix Windows console read size and keep type.__prepare__ permissive
Assisted-by: Claude:claude-opus-5-5
* Derive signature defaults from typed Rust values
Param.default is now a DefaultRepr rendered by the const writer.
Literals, integer and bool constants become typed defaults, and other
default expressions use the type's const fn py_default. A bare
`optional` renders as None, so `default = None` rewrites are reverted.
Address review comments: zlib max_length defaults, get_ca_certs
binary_form keyword, getpeercert der, WASM ssl certificate keywords,
fstatvfs fd-only, and _sre endpos shown as sys.maxsize.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Generate class constructor text signatures at compile time
A #[pyclass] impl composes the type's internal doc from the Args of
its Initializer or Constructor, so type.__text_signature__ and
inspect.signature work for native classes. __doc__ stays the plain
doc. Struct sequences get (iterable=(), /) and __reduce__ (self, /).
Hand-parsed constructors are converted to FromArgs structs, and
_weakref.proxy is split from ProxyType.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Remove expectedFailure from test_hmac tests that now pass
Assisted-by: Claude:claude-opus-5-5
* Match remaining native signatures and count missing CPython signatures as matches
Give lock.__enter__ and RLock.__enter__ their own no-argument methods,
add FromArgs for start_new_thread and start_joinable_thread keeping
their errors, take RTLD_GLOBAL/RTLD_LOCAL from libc, and align names,
kinds and <unrepresentable> defaults where CPython's signature is
invalid (bytes.hex, reduce, warn, link, setlocale, add_done_callback,
...). getaddrinfo accepts keyword arguments. whats_left treats a
callable CPython has no signature for as matching.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Drop unfulfilled dead_code expectation on os.link dir_fd args
Assisted-by: Claude:claude-opus-5-5
* Distinguish OptionalArg and Option in signature defaults
An `optional` field's signature default now comes from its type:
Option<T> renders None, while OptionalArg<T> (a missing argument that
is not any Python value) renders <unrepresentable>. Fields where a
missing argument behaves exactly like None become Option<T>; fields
whose missing state differs keep OptionalArg. Redundant
py_default = "<unrepresentable>" entries are removed.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Remove expectedFailure from test_rlcompleter.test_attr_matches
Assisted-by: Claude:claude-opus-5-5
* Use Option for optional arguments whose missing and None states match
OptionalOption and OptionalArg<Option<T>> fields that treat a missing
argument like None become Option<T> with #[pyarg(optional)], which renders
=None in the text signature. Plain optional parameters of that kind move
into small FromArgs structs. Uses where missing and None differ (reduce
initial, StringIO newline, TextIOWrapper.reconfigure, set_asyncgen_hooks)
keep OptionalOption.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Render ::NAME defaults by name and restore named constant defaults
- default = ::NAME writes NAME into the text signature and stores
Into::into(NAME) as the Rust value.
- A one-field tuple-struct argument pattern such as Fildes(fd) names the
parameter after its binding, so fcntl and termios keep destructuring.
- zlib, lzma, syslog, mmap and select defaults use their named constants
again instead of literals or <unrepresentable>.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Name FromArgs fields after their Python parameters
Drop #[pyarg(name = ...)] where the Python name is a valid Rust field name
and rename the field instead. The option stays only for keywords (fn, loop,
final, type, self) and the non-snake_case memLevel.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Build literal defaults from Python values and type <unrepresentable>
- default = LIT on a non-primitive field converts the literal through
ToPyObject and TryFromObject when the argument is missing, so object
fields no longer need a vm expression plus a matching py_default.
- A bare default on a primitive integer, bool or float field renders its
zero value.
- DefaultRepr::Unrepresentable replaces the <unrepresentable> text, and
py_default = "<unrepresentable>" is a compile error.
- pyexpat.ParserCreate distinguishes a missing intern from intern=None,
mmap AccessMode renders its value, and sqlite blobopen names rowid.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Resolve native docstrings from the doc database at compile time
- rustpython-doc stores its table as a sorted const slice with const fn
lookups (get, get_attr, class_attr_doc) instead of a phf map, and the
update-doc-db workflow emits that form.
- Class, method, getset, module function and struct sequence docs, and
per-class slot wrapper docs, are chosen by const lookups in the derive
output. The database text wins over Rust doc comments.
- Macros reach the table through rustpython_vm::__exports, so only the vm
depends on rustpython-doc.
- Remove expectedFailure markers from doctest and pydoc tests that pass.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Grok:grok-4.7
* Keep time.gmtime, localtime and ctime without a text signature
Their [seconds] parameter has no text signature, and unittest.mock relies
on inspect.signature failing for them. Take OptionalOption again so the
default stays unrepresentable, and treat None like a missing argument.
Assisted-by: Claude:claude-opus-5-5