* csv: reject reentrant reader advancement
Snapshot the reader generation before calling the input iterator. If a nested
call completes a record and advances the same reader, reject the outer call
with csv.Error instead of continuing with stale parser state.
Increment the generation on each successful record path, matching CPython's
handling of the existing reentrant-reader regression. Enable that test by
removing its expectedFailure marker.
Assisted-by: Codex:gpt-5.6-sol
* csv: invalidate outer reads after reentry
Advance the reader generation immediately after the reentrancy check, before
validating or parsing the returned input item. This invalidates the outer call
even when a nested read later fails validation or parsing.
Remove the per-return generation updates now that the common path advances it
exactly once.
Assisted-by: Codex:gpt-5.6-sol
* csv: generation type conversion(usize to u64)
On 32-bit targets (like WebAssembly, which RustPython supports), usize is 32-bit.
Csv with over 32-bit rows can raise panic on these platform.
type conversion from usize to u64.
* csv: quote embedded CR/LF under QUOTE_MINIMAL with custom lineterminator
QUOTE_MINIMAL rows were serialized by csv-core, which only quotes bytes
registered for the configured terminator, so fields containing '\r' or
'\n' were left unquoted when the lineterminator was not CR/LF (e.g. '!'
or '\0'). Route QUOTE_MINIMAL through a hand-written path that uses
field_needs_quotes, which always treats '\r'/'\n' as needing quotes.
A single empty field is quoted and an empty row emits only the
terminator, matching CPython. QUOTE_ALL / QUOTE_NONNUMERIC still use
csv-core.
Assisted-by: Claude Code:claude-opus-4-8
* csv: unmark now-passing writer tests
test_write_iterable and test_write_empty_fields pass with the
QUOTE_MINIMAL writer fix (empty rows no longer emit an empty field).
Assisted-by: Claude Code:claude-opus-4-8
The function is used in 'feature = ssl'. However, the current codebase
defines it without a conditional compilation expression and always be
compiled.
This commit removes the unused warning by adding a conditional
compilation expression, '#[cfg(feature = "ssl")]'.
* Store StopIteration.value in a struct field like SystemExit
* Unmark test_pydoc's test_member_descriptor
* Use expect instead of unwrap in new_stop_iteration
Dual-Root Mismatch in RustPython:
Unlike CPython, RustPython manages the standard library
in two separate locations in the workspace:
- Workspace 'Lib/': Contains the test suite ('Lib/test/...') and
standard library files.
- crates/pylib/Lib/: A helper directory used for packaging.
'crates/pylib/Lib' is a symlink pointing to the real workspace '../../Lib/'.
Runtime Directory Discrepancy:
- 'sys.path' contains 'crates/pylib/Lib' (the path to the symlink).
- Thus, when 'test.support' is imported, its '__file__' is resolved relative
to the symlink: '/opt/RustPython/crates/pylib/Lib/test/support/__init__.py'.
- Consequently, 'STDLIB_DIR' resolves to the symlink root:
'/opt/RustPython/crates/pylib/Lib'.
- However, since 'test_program.py' is executed directly from the workspace,
its 'pkg_dir' is: '/opt/RustPython/Lib/test/test_unittest/testmock'.
- When 'os.path.relpath(pkg_dir, top_dir)' is called:
---
os.path.relpath(
"/opt/RustPython/Lib/test/test_unittest/testmock",
"/opt/RustPython/crates/pylib/Lib"
)
# Result: "../../../Lib/test/test_unittest/testmock"
---
Because the relative path starts with '..', the assertion fails.
Assisted-by: Gemini
* weakref: reuse callback-less proxy objects like CPython
Make PyWeakProxy a #[repr(transparent)] view sharing PyWeak's payload
(manual PyPayload with shared PAYLOAD_TYPE_ID + class check), so a proxy
is the weakref-list node itself and add()'s reuse applies to it
directly. Port CPython's insert_weakref/get_basic_refs slot discipline:
genericref at head, generic proxy right after it, with callback/class
re-verificationbefore reuse. Constructor moves to a slot_new override
since reuse returns an existing object. Drops the hidden __weakproxy
marker subclass and the proxy branch in PyWeakref_GetRef.
Assisted-by: Claude Code:claude-opus-4-8
* weakref: always validate class in basic-proxy slot lookup
* weakref: rustfmt find_generic_proxy_ptr
* weakref: unify reuse check shape
stdlib/_symtable.rs previously provided the public Symbol API. When
7f1fc3602 imported Lib/symtable.py, responsibility for the public Symbol
implementation moved to Python, but the native implementation remained.
Remove it along with the unused identifiers getter.
Assisted-by: Codex:gpt-5.6-sol
When `ordered_attributes` is set, report attributes to the
StartElementHandler as a flat `[name, value, ...]` list matching
CPython's my_StartElementHandler, instead of always passing a dict.
`xml.etree.ElementTree` and `xml.dom.minidom` (via expatbuilder) both
enable this flag and rely on the flat-list contract, so parsing any
element with attributes previously failed: the dict made `_start` do
integer indexing, raising KeyError which was silently swallowed by the
handler invoker, leaving the tree empty ("missing toplevel element").
Reference (CPython 3.14):
https://github.com/python/cpython/blob/3.14/Modules/pyexpat.c#L439-L443
Remove `@unittest.expectedFailure` from tests that now pass
(23 in test_xml_etree, 15 in test_minidom, 1 in test_regrtest).
Assisted-by: Claude:claude-opus-4-8
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* vm: replace fetch_update() with try_update()
fetch_update() in atomic namespace is in the deprecation stage.
* host_env: replace libc::RLIM_NLIMITS with const RLIM_NLIMITS
Define a new const, RLIM_NLIMITS instead of libc::RLIM_NLIMITS in order
to clean up the deprecated const and to prevent breaking API where the const
is still used.
* Validate TextIOWrapper chunk size
Match CPython for non-positive, oversized, and index-compatible values.
Assisted-by: Codex:GPT-5
* Use explicit AssertionError in io snippet
Assisted-by: Codex:GPT-5
* Report original type in chunk size overflow
Assisted-by: Codex:GPT-5
* Chain io snippet assertion error
Assisted-by: Codex:GPT-5
* Match CPython chunk size setter behavior
Assisted-by: Codex:GPT-5
* Format io snippet assertion
Assisted-by: Codex:GPT-5.6
* Match CPython type name truncation
Assisted-by: Codex:GPT-5
* Format non-ASCII chunk size test
Assisted-by: Codex:GPT-5
Casting a u32 to a u16 would truncate the value. It's safer to use
Wtf::encode_wide which already handles converting a CodePoint to a u16.
I removed vec_into_bytes because it was only used in two places. The
function was unsound for T but sound in the way RustPython used it (POD
to POD, less strict alignment).
AI disclosure: I linted this code with AI. I found this issue by
accident while working on another patch in which I introduced a similar
mistake. AI caught that mistake, so I linted the original code to
cross-check it. I wrote the code myself in both instances.
Assisted-by: Codex:gpt-5.4
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
* csv: map QUOTE_MINIMAL to Necessary quote style
QuoteStyle::Minimal was mapped to csv_core's Always, which quoted every
field even under QUOTE_MINIMAL. Map it to Necessary so only fields that
require quoting are quoted.
Unmarks Test_Csv.test_write_quoting.
Assisted-by: Claude Code:claude-opus-4-8
* csv: apply dialect quoting and lineterminator in writer
csv.writer ignored the quoting and lineterminator from a dialect (whether
passed by name or object), always using the defaults. Resolve both from the
dialect via get_quoting()/get_lineterminator(), mirroring get_delimiter(), so
an explicit keyword argument still overrides the dialect.
Unmarks TestDialectUnix.test_simple_writer.
Assisted-by: Claude Code:claude-opus-4-8
* _queue: check for pending signals during blocking get()
Semaphore::acquire() waited on the condvar in a single uninterrupted call,
so a Python-level signal handler never ran until the wait itself returned.
check_signals() is only invoked from the bytecode dispatch loop, and this
native wait never passed through it -- CPython chunks its equivalent
blocking wait for the same reason.
Cap each wait at a short interval and call check_signals() between chunks,
only giving up once the caller's real deadline has actually elapsed. The
mutex guard must be dropped before check_signals() runs: a signal handler
that calls back into the same queue on the same thread would otherwise try
to relock a mutex it's still holding and deadlock against itself.
Add a regression snippet that arms a SIGALRM well before a helper thread
unblocks the queue, and asserts the handler ran near the alarm instead of
only once get() returned.
Refs #8250
Assisted-by: Claude
* _queue: correct SIGNAL_CHECK_INTERVAL doc comment
The old comment claimed this mirrors CPython's PyThread_acquire_lock_timed,
but CPython doesn't chunk its wait either -- it makes one sem_timedwait call
and relies on the OS reporting EINTR. parking_lot's Condvar has no equivalent
signal to surface, so polling is a workaround for that gap, not a mirror of
CPython's approach.
Assisted-by: Claude
* Apply suggestions from code review
Co-authored-by: Jeong, YunWon <69878+youknowone@users.noreply.github.com>
* _queue: fix comment indentation (cargo fmt)
Assisted-by: Claude
---------
Co-authored-by: Jeong, YunWon <69878+youknowone@users.noreply.github.com>
* Make SystemExit.code a writable attribute set at init
* Read exit status from SystemExit.code in handle_exit_exception
* Store SystemExit.code in a struct field instead of the instance dict
* Create SystemExit through the full constructor path
* module: honor module-level __dir__ (PEP 562)
dir(module) ignored a module-level __dir__ function and returned the raw
__dict__ keys. Look up __dir__ in the module dict and, when present, call
it and return its result — matching CPython's module___dir___impl. The
existing expectedFailure markers on test_module_dir/test_module_dir_errors
are removed since both now pass.
Fixes#8231
Assisted-by: Claude Code:claude-opus-4-8
* test: unmark zoneinfo test_dir_contains_all (PEP 562 __dir__)
Honoring a module-level __dir__ makes dir(zoneinfo) contain everything
in __all__, so test_dir_contains_all now passes. Remove its stale
expectedFailure marker to avoid an unexpected-success CI failure.
Assisted-by: Claude Code:claude-opus-4-8
* test: unmark test_support.test_check__all__ (PEP 562 __dir__)
check__all__ iterates dir(module); honoring a module-level __dir__ fixes
dir(unittest), so test_check__all__ now passes. Remove its stale
expectedFailure marker to avoid an unexpected-success CI failure.
Assisted-by: Claude Code:claude-opus-4-8
* Support array 'w' (Py_UCS4) typecode
Python 3.13 added the 'w' typecode holding fixed 4-byte unicode code
points, unlike 'u' which is platform-dependent wchar_t. Add a Ucs4Char
element type and route it through the existing unicode-array paths:
constructor from str, fromunicode()/tounicode(), __reduce_ex__, repr,
byteswap, and the machine-format code (Utf32). Also register 'w' as a
struct format char in vm::buffer.
Remove the now-passing expectedFailure markers for 'w' tests in
test_array.py.
Assisted-by: Claude
* Reject non-native byte order for the 'w' format char
FormatType::parse accepted 'w' after '<', '>', '!', or '=', but the
non-native branch of FormatType::info has no Ucs4Char arm and hits
unreachable!(), so struct.calcsize('>w') panicked the interpreter.
Add Ucs4Char to the existing native-only filter in FormatCode::parse
(alongside SSizeT/SizeT/VoidP) so those formats fail with the regular
"bad char in struct format" error instead. Native 'w' and
memoryview(array('w', ...)) are unaffected.
Assisted-by: Claude
* Unmark 'w'-typecode tests in test_re and test_csv
test_re's test_empty_array and test_csv's test_char_write construct
array('w', ...) and were marked expectedFailure while the typecode was
unsupported. Now that 'w' works they pass, and regrtest counts the
unexpected successes as failures in CI. Remove the two markers, which
restores both tests to their CPython v3.14.6 form; test_re, test_csv,
and test_array all pass.
Assisted-by: Claude
* Restore pyexpat lexical callback compatibility
Forward processing instructions, comments, and CDATA boundaries already emitted by xml-rs so registered Python handlers observe CPython-compatible events.
Constraint: Reuse existing xml-rs events without changing the dependency
Confidence: high
Scope-risk: narrow
Tested: prek; test_pyexpat; test_sax; 402 extra tests; workspace tests; clippy
Assisted-by: Codex:gpt-5.6-sol
* Recognize XML compatibility restored by lexical events
Remove stale expected-failure markers for CPython XML tests now satisfied by pyexpat lexical-event forwarding, and simplify parser event error propagation.
Constraint: CPython test edits are limited to removing stale expectedFailure markers
Confidence: high
Scope-risk: narrow
Directive: Keep parser event dispatch aligned with pyexpat handler behavior
Tested: user-verified full suite; prek run --all-files; cargo run --release -- -m test test_pyexpat test_xml_etree test_xml_etree_c test_minidom test_sax
Assisted-by: Codex:gpt-5.6-sol
getpath: on Windows, default_prefix falls back to the executable
directory instead of a bare "C:" when landmark search fails.
host_env: errno_io_error carries the raw CRT errno as an io::Error
payload (CrtErrno) instead of translating it to a Win32 error code and
back. The round-trip collapsed every errno outside the errno_to_winerror
table to EINVAL and attached a spurious winerror to the OSError.
posix_errno recovers the exact errno from the payload; ftruncate reuses
the same path. fstat now reports ERROR_INVALID_HANDLE for an invalid fd.
* csv: apply dialect escapechar when reading
ReaderBuilder only received escapechar when it was passed directly as a
keyword argument. A dialect object's or registered dialect's escapechar was
visible through reader.dialect but not used by csv_core.
Pass escapechar through for named, object, and default dialect paths. This
makes escaped delimiters inside quoted fields follow the configured dialect,
for example '"abc\,def"' reads as 'abc,def'.
Unmark TestQuotedEscapedExcel.test_read_escape_fieldsep.
Assisted-by: Codex
* csv: handle escaped delimiters with QUOTE_NONE
csv_core applies escapechar while reading quoted fields, but its unquoted
field state treats an escaped delimiter as a delimiter. Consequently,
QUOTE_NONE with escapechar split 'abc\,def' into 'abc\' and 'def'.
Add a small QUOTE_NONE record parser for dialects with escapechar. It keeps
the byte following an escape character as field data, so escaped delimiters
do not end a field while ordinary delimiters and record terminators retain
their usual meaning.
Unmark TestEscapedExcel.test_read_escape_fieldsep.
Assisted-by: Codex
* csv: respect skipinitialspace with QUOTE_NONE
The QUOTE_NONE parser returned before the normal reader's whitespace
preprocessing, so it ignored skipinitialspace when escapechar was set.
Track whether parsing has just followed a delimiter and skip only ordinary
spaces in that position. Escaped spaces remain field data.
Add a stdlib_csv snippet regression test for QUOTE_NONE with escapechar and
skipinitialspace.
Assisted-by: Codex:gpt-5.6-terra
* csv: deduplicate reader dialect configuration
to_reader configured ReaderBuilder separately for named, object, and default
dialects even though the configuration was identical.
Resolve the PyDialect once, then apply delimiter, double_quote, escapechar,
and quotechar in one place. Preserve the existing unregistered-name fallback
and required excel dialect lookup behavior.
Assisted-by: Codex:gpt-5.6-terra
Match.expand delegated to re._expand, which CPython removed in 3.12
during the template-expansion refactor. With the 3.14 stdlib that
helper no longer exists, so expand raised AttributeError.
Route expand through the compiled-template path
(Template::compile -> re._compile_template) and share the
template-filling logic with Pattern.sub via a Match::expand_template
helper. Each caller still compiles the template once, so sub keeps
its no-recompile-per-match fast path.
Remove the expectedFailure marker on test_re.test_expand.
Assisted-by: Claude Code:claude-opus-4-8