Skip to content

Preserve str subclass results from __repr__ in plain str()#7454

Open
Copilot wants to merge 56 commits intomainfrom
copilot/fix-str-subclass-type-issue
Open

Preserve str subclass results from __repr__ in plain str()#7454
Copilot wants to merge 56 commits intomainfrom
copilot/fix-str-subclass-type-issue

Conversation

Copy link
Contributor

Copilot AI commented Mar 17, 2026

str(obj) was flattening a str subclass returned by __repr__ into an exact str, diverging from CPython. This only affected the plain str(...) constructor path; subtype construction should still normalize to the requested subtype.

  • Constructor behavior

    • Change the exact str(...) fast path in PyStr::slot_new to return PyObject::str(vm) directly for the single-argument, no-kwargs case.
    • This preserves subclass identity when __str__/__repr__ returns a str subclass, instead of rebuilding a new exact str from the underlying data.
  • Regression coverage

    • Re-enable Lib/test/test_str.py::StrTest.test_conversion, which already covers WithRepr(StrSubclass(...)) and related conversion cases.
    • Keep the Lib/test/test_str.py change aligned with CPython v3.14.3 rather than adding RustPython-only assertions there.
    • Add RustPython-owned identity regression coverage under extra_tests/snippets/builtin_str_subclass.py for the exact str(...) path preserving a str subclass returned by __str__ and __repr__.

Example:

class MyStr(str):
    pass

class Foo:
    def __repr__(self):
        return MyStr("hello")

result = str(Foo())
type(result)  # now: MyStr
Original prompt

This section details on the original issue you should resolve

<issue_title>str() discards str subclass type returned by __repr__</issue_title>
<issue_description>## Description

str() on an object whose __repr__ returns a str subclass instance incorrectly returns a plain str, discarding the subclass type. CPython preserves the subclass type as-is. This is a CPython compatibility issue.

Root Cause

PyStr::py_new calls input.str(vm) which correctly resolves to the __repr__ return value (a str subclass instance), but then extracts only the raw string data via Self::from(s.as_wtf8().to_owned()) and creates a new plain PyStr, discarding the subclass type.

CPython reference: unicodeobject.c#L15575-L15596

// Key branch: only convert when type is a str subclass
if (unicode != NULL && type != &PyUnicode_Type) {
    Py_SETREF(unicode, unicode_subtype_new(type, unicode));
}
return unicode;   // when type is exactly str → return PyObject_Str result as-is

When type == &PyUnicode_Type (plain str() call), unicode_new_impl returns the PyObject_Str result without conversion, preserving the subclass type.

Reproduction

class MyStr(str):
    pass

class Foo:
    def __repr__(self):
        return MyStr('hello')

result = str(Foo())
print(result)
print(type(result))

Output

RustPython:

hello
<class 'str'>

CPython:

hello
<class '__main__.MyStr'>

Environment

  • RustPython d248a04 (Python 3.14.0)
  • CPython 3.14.3
  • OS: Debian 12</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

Summary by CodeRabbit

  • Bug Fixes
    • Improved string conversion behavior to ensure consistent handling of arguments passed to the string constructor.

Copilot AI and others added 2 commits March 17, 2026 11:27
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix str() to preserve str subclass type from __repr__ Preserve str subclass results from __repr__ in plain str() Mar 17, 2026
Copilot AI requested a review from youknowone March 17, 2026 11:30
@youknowone youknowone marked this pull request as ready for review March 17, 2026 11:40
Comment on lines 398 to 400
if cls.is(vm.ctx.types.str_type)
&& func_args.args.len() == 1
&& func_args.kwargs.is_empty()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[auto-format] reported by reviewdog 🐶

Suggested change
if cls.is(vm.ctx.types.str_type)
&& func_args.args.len() == 1
&& func_args.kwargs.is_empty()
if cls.is(vm.ctx.types.str_type) && func_args.args.len() == 1 && func_args.kwargs.is_empty()

@github-actions
Copy link
Contributor

github-actions bot commented Mar 17, 2026

📦 Library Dependencies

The following Lib/ modules were modified. Here are their dependencies:

[x] test: cpython/Lib/test/test_str.py (TODO: 14)
[x] test: cpython/Lib/test/test_fstring.py (TODO: 19)
[x] test: cpython/Lib/test/test_string_literals.py (TODO: 4)

dependencies:

dependent tests: (no tests depend on str)

Legend:

  • [+] path exists in CPython
  • [x] up-to-date, [ ] outdated

@youknowone
Copy link
Member

@copilot fix CI failure

Copy link
Contributor Author

Copilot AI commented Mar 17, 2026

@copilot fix CI failure

Fixed by a555ce4. The only failing CI job was the old format_check run on 0852fa6, and it failed in the final formatting-diff step. a555ce4 contains the formatting fix, cargo fmt --check passes locally, and the targeted regression test still passes while the refreshed PR checks are running on the updated head.

@youknowone
Copy link
Member

@copilot Fix still failng ci.

Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 17, 2026

@copilot Fix still failng ci.

Pushed 008e4c6. I traced the red CI to the old 0852fa6 run: the real reported failure was test.test_multiprocessing_fork.test_processes, and it passes locally on current HEAD. This follow-up tightens the existing str regression and triggers fresh workflows for the updated branch state; the new runs are on 008e4c6, but GitHub currently shows them as action_required with no jobs started yet.

@youknowone
Copy link
Member

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 19, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 19, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 609ffbcc-40d9-4d2e-af34-f8b63c890459

📥 Commits

Reviewing files that changed from the base of the PR and between 2a61237 and 008e4c6.

⛔ Files ignored due to path filters (1)
  • Lib/test/test_str.py is excluded by !Lib/**
📒 Files selected for processing (1)
  • crates/vm/src/builtins/str.rs

📝 Walkthrough

Walkthrough

The PyStr.slot_new optimization path is modified to invoke string conversion on arguments via str(vm) instead of requiring the argument to be an existing PyStr instance. This enables the optimization to coerce non-string single arguments to strings while preserving subclass types.

Changes

Cohort / File(s) Summary
String Constructor Optimization
crates/vm/src/builtins/str.rs
Modified the exact str type optimization path to call str(vm) on the single positional argument instead of type-checking for PyStr, enabling string coercion while preserving subclass types returned by __str__/__repr__.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

  • Add tp_str #6495: Implements the tp_str/__str__ slot mechanism that enables the .str(vm) method call used in this optimization path to properly invoke string conversion with subclass type preservation.

Poem

🐰 A str() call once crude and plain,
Now honors types with careful strain,
Subclasses preserved, not cast away,
The optimization wins the day! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main change: preserving str subclass results from repr in plain str() calls, matching the core objective documented in issue #7450.
Linked Issues check ✅ Passed The PR changes PyStr::slot_new to return the str conversion result directly instead of rebuilding a plain str, which directly addresses issue #7450's requirement to preserve str subclass types returned by repr to match CPython behavior.
Out of Scope Changes check ✅ Passed The changes to PyStr::slot_new are narrowly scoped to the optimization path that triggered the bug, with no unrelated modifications present in the provided changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch copilot/fix-str-subclass-type-issue
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@youknowone
Copy link
Member

@copilot where the test_str.pychanges came from? we have strict rule not editing test_str.py ourselves. that must be came from CPython Lib/test/test_str.py. Please check and confirm which version we copied it from. Otherwise revert them and add tests under extra_tests/snippets, which owns our own tests

Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 19, 2026

@copilot where the test_str.pychanges came from? we have strict rule not editing test_str.py ourselves. that must be came from CPython Lib/test/test_str.py. Please check and confirm which v...

Checked and fixed in ae2b62e. The extra identity assertions in Lib/test/test_str.py were PR-local and not from a CPython sync, so I moved them to extra_tests/snippets/builtin_str_subclass.py. I also verified that the remaining test_conversion hunk matches CPython v3.14.3, so Lib/test/test_str.py now only keeps the CPython-aligned change.

dependabot bot and others added 27 commits March 25, 2026 06:49
Bumps [aws-lc-fips-sys](https://github.com/aws/aws-lc-rs) from 0.13.12 to 0.13.13.
- [Release notes](https://github.com/aws/aws-lc-rs/releases)
- [Commits](aws/aws-lc-rs@aws-lc-fips-sys/v0.13.12...aws-lc-fips-sys/v0.13.13)

---
updated-dependencies:
- dependency-name: aws-lc-fips-sys
  dependency-version: 0.13.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Enable PEP 709 inlined comprehensions for function-like scopes

Activate the existing compile_inlined_comprehension() implementation
by fixing 6 bugs that prevented it from working:

- LoadFastAndClear: push NULL (not None) when slot is empty so
  StoreFast can restore empty state after comprehension
- StoreFast: accept NULL from stack for the restore path
- sub_tables.remove(0) replaced with next_sub_table cursor to
  match the pattern used elsewhere in the compiler
- in_inlined_comp flag moved from non-inlined to inlined path
- is_inlined_comprehension_context() now checks comp_inlined flag
  and restricts inlining to function-like scopes
- comp_inlined set only when parent scope uses fastlocals

Symbol table analysis handles conflict detection:
- Nested scopes in comprehension → skip inlining
- Bound name conflicts with parent symbol → skip inlining
- Cross-comprehension reference conflicts → skip inlining
- Splice comprehension sub_tables into parent for nested scope tracking

* Add localspluskinds, unify DEREF to localsplus index

- Add CO_FAST_LOCAL/CELL/FREE/HIDDEN constants and
  localspluskinds field to CodeObject for per-slot metadata
- Change DEREF instruction opargs from cell-relative indices
  (NameIdx) to localsplus absolute indices (oparg::VarNum)
- Add fixup_deref_opargs pass in ir.rs to convert cell-relative
  indices to localsplus indices after finalization
- Replace get_cell_name with get_localsplus_name in
  InstrDisplayContext trait
- Update VM cell_ref/get_cell_contents/set_cell_contents to use
  localsplus indices directly (no nlocals offset)
- Update function.rs cell2arg, super.rs __class__ lookup with
  explicit nlocals offsets

* Fix clippy warnings, formatting, restore _opcode_metadata.py

Fix cast_possible_truncation, nonminimal_bool, collapsible_if,
manual_contains clippy lints. Restore _opcode_metadata.py to
upstream/main version (3.14 aligned).

Pre-copy closure cells in Frame::new for coroutine locals().
Handle raw values in merged cell slots during inlined comps.
Exclude async comprehensions from inlining path.

* Exclude async/await comprehensions from PEP 709 inlining in symboltable

Async comprehensions and comprehensions with await in the element
expression need their own coroutine scope and cannot be inlined.
The symboltable builder was not checking these conditions, causing
incorrect symbol scope resolution when an async comprehension was
nested inside an inlined comprehension (e.g. [[x async for x in g]
for j in items]).
* Disallow instantiation of sys.getwindowsversion type

Add slot_new to PyWindowsVersion that raises TypeError,
matching sys.flags behavior.

* Remove incorrect WSAHOS errno constant

WSAHOS was hardcoded as an alias for WSAHOST_NOT_FOUND, but
CPython guards it with #ifdef WSAHOS which doesn't exist in
modern Windows SDK headers.

* Fix mmap resize to raise OSError instead of SystemError

* Fix CreateProcess with empty environment on Windows

Empty env dict produced a single null terminator, but
CreateProcessW requires a double null for a valid empty
environment block.

* Revert mmap resize error to SystemError and fix errno.rs formatting

mmap resize raises SystemError (not OSError) when mremap is unavailable,
matching CPython behavior. test_mmap catches SystemError to skip unsupported
resize operations.

* Fix named mmap resize to raise OSError and unmark test_sleep expectedFailure

Named mmap resize on Windows should raise OSError (not SystemError).
Remove expectedFailure mark from TimeEINTRTest.test_sleep as it now passes.

* Use expectedFailureIf for TimeEINTRTest.test_sleep on Linux

test_sleep passes on macOS but fails on Linux due to timing.

* Remove expectedFailure for TimeEINTRTest.test_sleep

test_sleep now passes on all platforms.
Bumps [rustls-webpki](https://github.com/rustls/webpki) from 0.103.9 to 0.103.10.
- [Release notes](https://github.com/rustls/webpki/releases)
- [Commits](rustls/webpki@v/0.103.9...v/0.103.10)

---
updated-dependencies:
- dependency-name: rustls-webpki
  dependency-version: 0.103.10
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Implement bytearray.__str__

* Implement bytes.__str__

* Turn __str__ method into slot
…7480)

When an inlined comprehension's first iterator expression contains
nested scopes (such as a lambda), those scopes' sub_tables appear at the
current position in the parent's sub_table list. The previous code
spliced the comprehension's own child sub_tables (e.g. inner inlined
comprehensions) into that same position before compiling the iterator,
which shifted the iterator's sub_tables to wrong indices.

Move the splice after the first iterator is compiled so its sub_tables
are consumed at their original positions.

Fixes nested list comprehensions like:
```python
    [[x for _, x in g] for _, g in itertools.groupby(..., lambda x: ...)]
```

Disclosure: I used AI to develop the patch though I was heavily
involved.
* Emit TO_BOOL before conditional jumps, fix class/module prologue

- Emit TO_BOOL before POP_JUMP_IF_TRUE/FALSE in the general case
  of compile_jump_if (Compare expressions excluded since they
  already produce a bool)
- Module-level __doc__: use STORE_NAME instead of STORE_GLOBAL
- Class body __module__: use LOAD_NAME instead of LOAD_GLOBAL
- Class body: store __firstlineno__ before __doc__

* Emit MAKE_CELL and COPY_FREE_VARS before RESUME

Emit MAKE_CELL for each cell variable and COPY_FREE_VARS N for
free variables at the start of each code object, before RESUME.
These instructions are no-ops in the VM but align the bytecode
with CPython 3.14's output.

* Emit __static_attributes__ at end of class bodies

Store a tuple of attribute names (currently always empty) as
__static_attributes__ in the class namespace, matching CPython
3.14's class body epilogue. Attribute name collection from
self.xxx accesses is a follow-up task.

* Remove expectedFailure from DictProxyTests iter tests

test_iter_keys, test_iter_values, test_iter_items now pass
because class bodies emit __static_attributes__ and
__firstlineno__, matching the expected dict key set.

* Use 1-based stack indexing for LIST_EXTEND, SET_UPDATE, etc.

Switch LIST_APPEND, LIST_EXTEND, SET_ADD, SET_UPDATE, MAP_ADD
from 0-based to 1-based stack depth argument, matching CPython's
PEEK(oparg) convention. Adjust the VM to subtract 1 before
calling nth_value.

* Use plain LOAD_ATTR + PUSH_NULL for calls on imported names

When the call target is an attribute of an imported name (e.g.,
logging.getLogger()), use plain LOAD_ATTR (method_flag=0) with
a separate PUSH_NULL instead of method-mode LOAD_ATTR. This
matches CPython 3.14's behavior which avoids the method call
optimization for module attribute access.

* Duplicate return-None epilogue for fall-through blocks

When the last block in a code object is exactly LOAD_CONST None +
RETURN_VALUE (the implicit return), duplicate these instructions
into blocks that would otherwise fall through to it. This matches
CPython 3.14's behavior of giving each code path its own explicit
return instruction.

* Run cargo fmt on ir.rs

* Remove expectedFailure from test_intrinsic_1 in test_dis

* Emit TO_BOOL before conditional jumps for all expressions including Compare

* Add __classdict__ cell for classes with function definitions

Set needs_classdict=true for class scopes that contain function
definitions (def/async def), matching CPython 3.14's behavior for
PEP 649 deferred annotation support. Also restore the Compare
expression check in compile_jump_if to skip TO_BOOL for comparison
operations.

* Emit __classdictcell__ store in class body epilogue

Store the __classdict__ cell reference as __classdictcell__ in
the class namespace when the class has __classdict__ as a cell
variable. Uses LOAD_DEREF (RustPython separates cell vars from
fast locals unlike CPython's unified array).

* Always run DCE to remove dead code after terminal instructions

Run basic dead code elimination (truncating instructions after
RETURN_VALUE/RAISE/JUMP within blocks) at all optimization
levels, not just optimize > 0. CPython always removes this dead
code during assembly.

* Restrict LOAD_ATTR plain mode to module/class scope imports

Only use plain LOAD_ATTR + PUSH_NULL for imports at module or
class scope. Function-local imports use method call mode LOAD_ATTR,
matching CPython 3.14's behavior.

* Eliminate unreachable blocks after jump normalization

Split DCE into two phases: (1) within-block truncation after
terminal instructions (always runs), (2) whole-block elimination
for blocks only reachable via fall-through from terminal blocks
(runs after normalize_jumps when dead jump instructions exist).

* Fold BUILD_TUPLE 0 into LOAD_CONST empty tuple

Convert BUILD_TUPLE with size 0 to LOAD_CONST () during constant
folding, matching CPython's optimization for empty tuple literals.

* Handle __classcell__ and __classdictcell__ in type.__new__

- Remove __classcell__ from class dict after setting the cell value
- Add __classdictcell__ handling: set cell to class namespace dict,
  then remove from class dict
- Register __classdictcell__ identifier
- Use LoadClosure instead of LoadDeref for __classdictcell__ emission
- Reorder MakeFunctionFlag bits to match CPython
- Run ruff format on scripts

* Revert __classdict__ cell and __classdictcell__ changes

The __classdict__ cell addition (for classes with function defs)
and __classdictcell__ store caused cell initialization failures
in importlib. These require deeper VM changes to properly support
the cell variable lifecycle. Reverted for stability.

* Fix unreachable block elimination with fixpoint reachability

Use fixpoint iteration to properly determine block reachability:
only mark jump targets of already-reachable blocks, preventing
orphaned blocks from falsely marking their targets as reachable.
Also add a final DCE pass after assembly NOP removal to catch
dead code created by normalize_jumps.

* Check enclosing scopes for IMPORTED flag in LOAD_ATTR mode

When deciding whether to use plain LOAD_ATTR for attribute calls,
check if the name is imported in any enclosing scope (not just
the current scope). This handles the common pattern where a module
is imported at module level but used inside functions.

* Add __classdict__ cell for classes with function definitions

Set needs_classdict=true when a class scope contains function
definitions (def/async def), matching CPython 3.14 which always
creates a __classdict__ cell for PEP 649 support in such classes.

* Store __classdictcell__ in class body epilogue

Store the __classdict__ cell reference as __classdictcell__ in
the class namespace using LoadClosure (which loads the cell
object itself, not the value inside). This matches CPython 3.14's
class body epilogue.

* Fix clippy collapsible_if warnings and cargo fmt

* Revert __classdict__ and __classdictcell__ changes (cause import failures)

* Revert type.__new__ __classcell__ removal and __classdictcell__ handling

Revert the class cell cleanup changes from e6975f9 that cause
import failures when frozen module bytecode is stale. The original
behavior (not removing __classcell__ from class dict) is restored.

* Re-add __classdict__ cell and __classdictcell__ store

Restore the __classdict__ cell for classes with function
definitions and __classdictcell__ store in class body epilogue.
Previous failure was caused by stale .pyc cache files containing
bytecode from an intermediate MakeFunctionFlag reorder attempt,
not by these changes themselves.

* Reorder MakeFunctionFlag to match CPython's SET_FUNCTION_ATTRIBUTE

Reorder discriminants: Defaults=0, KwOnlyDefaults=1, Annotations=2,
Closure=3, Annotate=4, TypeParams=5. This aligns the oparg values
with CPython 3.14's convention.

Note: after this change, stale .pyc cache files must be deleted
(find . -name '*.pyc' -delete) to avoid bytecode mismatch errors.

* Use CPython-compatible power-of-two encoding for SET_FUNCTION_ATTRIBUTE

Override From/TryFrom for MakeFunctionFlag to use power-of-two
values (1,2,4,8,16,32) matching CPython's SET_FUNCTION_ATTRIBUTE
oparg encoding, instead of sequential discriminants (0,1,2,3,4,5).

* Remove expectedFailure from test_elim_jump_after_return1 and test_no_jump_over_return_out_of_finally_block

* Remove __classcell__ and __classdictcell__ from class dict in type.__new__

* Remove expectedFailure from test___classcell___expected_behaviour, cargo fmt

* Handle MakeCell and CopyFreeVars as no-ops in JIT

These prologue instructions are handled at frame creation time
by the VM. The JIT operates on already-initialized frames, so
these can be safely skipped during compilation.

* Remove expectedFailure from test_load_fast_known_simple

* Restore expectedFailure for test_load_fast_known_simple

The test expects LOAD_FAST_BORROW_LOAD_FAST_BORROW superinstruction
which RustPython does not emit yet.
* CPython-compatible marshal format

Unify marshal to a single CPython-compatible format. No separate
"cpython_marshal" reader — one format for frozen modules, .pyc
files, and the Python-level marshal module.

- ComparisonOperator: `(cmp_index << 5) | mask` matching COMPARE_OP
- MakeFunctionFlag: bit-position matching SET_FUNCTION_ATTRIBUTE
- Exception table varint: big-endian (matching Python/assemble.c)
- Linetable varint: little-endian (unchanged)
- Integer: TYPE_INT (i32) / TYPE_LONG (base-2^15 digits)
- Code objects: CPython field order (argcount, posonlyargcount, ...,
  co_localsplusnames, co_localspluskinds, ..., co_exceptiontable)

- FLAG_REF / TYPE_REF for object deduplication (version >= 3)
- allow_code keyword argument on dumps/loads/dump/load
- Subclass rejection (int/float/complex/tuple/list/dict/set/frozenset)
- Slice serialization (version >= 5)
- Buffer protocol fallback for memoryview/array
- Recursion depth limit (2000) for both reads and writes
- Streaming load (reads one object, seeks file position)
- TYPE_INT64, TYPE_FLOAT (text), TYPE_COMPLEX (text) for compat

serialize_code writes co_localsplusnames/co_localspluskinds from
split varnames/cellvars/freevars. deserialize_code splits them back.
Cell variable DEREF indices are translated between flat (wire) and
cell-relative (internal) representations in both directions.

Replace bitwise trick with match for new ComparisonOperator values.

21 -> 3 expected failures. Remaining: test_bad_reader (IO layer),
test_deterministic_sets (PYTHONHASHSEED), testIntern (string interning).

* Address code review: preserve CO_FAST_HIDDEN, fix varint overflow

- Use original localspluskinds from marshal data instead of
  rebuilding, preserving CO_FAST_HIDDEN and other flags
- Fix write_varint_be to handle values >= 2^30 (add 6th chunk)
- Remove unused build_localspluskinds_from_split

* Add depth guard to deserialize_value_typed

Prevents usize underflow when dict key deserialization path calls
deserialize_value_typed with depth=0 on composite types.
* Set dependabot cooldown

* Increase default to 7 days
Bumps [libsqlite3-sys](https://github.com/rusqlite/rusqlite) from 0.36.0 to 0.37.0.
- [Release notes](https://github.com/rusqlite/rusqlite/releases)
- [Changelog](https://github.com/rusqlite/rusqlite/blob/master/Changelog.md)
- [Commits](rusqlite/rusqlite@v0.36.0...v0.37.0)

---
updated-dependencies:
- dependency-name: libsqlite3-sys
  dependency-version: 0.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [github/gh-aw](https://github.com/github/gh-aw) from 0.58.3 to 0.62.5.
- [Release notes](https://github.com/github/gh-aw/releases)
- [Changelog](https://github.com/github/gh-aw/blob/main/CHANGELOG.md)
- [Commits](github/gh-aw@08a903b...48d8fdf)

---
updated-dependencies:
- dependency-name: github/gh-aw
  dependency-version: 0.62.5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](actions/cache@cdf6c1f...6682284)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [cargo-bins/cargo-binstall](https://github.com/cargo-bins/cargo-binstall) from 1.17.7 to 1.17.8.
- [Release notes](https://github.com/cargo-bins/cargo-binstall/releases)
- [Changelog](https://github.com/cargo-bins/cargo-binstall/blob/main/release-plz.toml)
- [Commits](cargo-bins/cargo-binstall@1800853...113a77a)

---
updated-dependencies:
- dependency-name: cargo-bins/cargo-binstall
  dependency-version: 1.17.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: EtherealPsyche <EtherealPsyche@users.noreply.github.com>
Bumps [lz4_flex](https://github.com/pseitz/lz4_flex) from 0.12.1 to 0.13.0.
- [Release notes](https://github.com/pseitz/lz4_flex/releases)
- [Changelog](https://github.com/PSeitz/lz4_flex/blob/main/CHANGELOG.md)
- [Commits](PSeitz/lz4_flex@0.12.1...0.13.0)

---
updated-dependencies:
- dependency-name: lz4_flex
  dependency-version: 0.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Cleanup matrix usage. enables jit on macos

* Pin some actions to commit hash

* Disable node cache

* Inline `CARGO_ARGS`

* Add `stdio` and `host_env` features

* Only upload to pages if not running on fork
* Pin `setup-node` action to a commit hash

* Don't use cache for release

* Revert changes of `release.yml`
* Handle EINTR retry in os.write() (PEP 475)

Add EINTR retry loop to os.write(), matching the existing
pattern in os.read() and os.readinto(). Remove the
expectedFailure marker from test_write in _test_eintr.py.

* Add atomic snapshot for dict/dict_keys in extract_elements

Add fast paths for dict and dict_keys types in
extract_elements_with, matching _list_extend() in CPython
Objects/listobject.c. Each branch takes an atomic snapshot
under a single read lock, preventing race conditions from
concurrent dict mutation without the GIL.

Remove expectedFailure from test_thread_safety.
Copy link
Contributor Author

Copilot AI commented Mar 25, 2026

@copilot rebase to upstream/main

Updated in 7a4ca2f. The branch now has origin/main as its merge-base again, and the PR diff is back to the intended 3 files. I also re-ran the targeted test.test_str.StrTest.test_conversion unittest and extra_tests/snippets/builtin_str_subclass.py on the final branch tip.

Copilot AI requested a review from youknowone March 25, 2026 06:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

str() discards str subclass type returned by __repr__

7 participants