Repository navigation
memoryview: traverse the view for the collector, and name types as tp_name does - #8608
Conversation
Neither `memoryview` nor the `_buffer_wrapper` a `__buffer__` produces was
traversed, so the object a view looks at was never reported and a cycle
running through one was classified as reachable:
class Src:
def __buffer__(self, flags): return memoryview(b'abcdef')
o = Src(); o.keep = memoryview(o) # o is never freed
Both now report what they hold, as `memory_traverse` and `mbuf_traverse` do.
Assisted-by: Claude
The message took the short name, so a type defined in a module lost the
module: `hash(array.array('B', b'a'))` said `unhashable type: 'array'`
where the name is `array.array`, and `collections.deque` said `'deque'`.
`slot_name()` is what `tp_name` holds, and it leaves a class defined in
Python reported by its own name as before.
Assisted-by: Claude
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (5)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughThe PR adds cycle-collector traversal metadata to memoryview-related classes and tests cycle collection. It also changes unhashable type errors to use slot names and adds coverage for built-in and user-defined types. ChangesMemoryview garbage collection
Unhashable type error names
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to The changes improve collection of memoryview-related cycles and correct module-qualified unhashable-type messages, with focused tests covering both behaviors. No actionable merge-blocking risk remains after normal checks and review. Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
📦 Library DependenciesThe following Lib/ modules were modified. Here are their dependencies: [x] test: cpython/Lib/test/test_memoryview.py (TODO: 1) dependencies: dependent tests: (no tests depend on memoryview) Legend:
|
…p_name` does (#8608) * memoryview: walk the view and the buffer wrapper for the collector Neither `memoryview` nor the `_buffer_wrapper` a `__buffer__` produces was traversed, so the object a view looks at was never reported and a cycle running through one was classified as reachable: class Src: def __buffer__(self, flags): return memoryview(b'abcdef') o = Src(); o.keep = memoryview(o) # o is never freed Both now report what they hold, as `memory_traverse` and `mbuf_traverse` do. Assisted-by: Claude * Name the type in an unhashable-type message the way `tp_name` does The message took the short name, so a type defined in a module lost the module: `hash(array.array('B', b'a'))` said `unhashable type: 'array'` where the name is `array.array`, and `collections.deque` said `'deque'`. `slot_name()` is what `tp_name` holds, and it leaves a class defined in Python reported by its own name as before. Assisted-by: Claude
Two defects, both found while working through what was left after #8553. Comparisons are against CPython 3.14.6.
A cycle running through a view was never collected
Neither
memoryviewnor the_buffer_wrappera__buffer__produces reported what it held while being traversed, so the object a view looks at was invisible to the collector and the cycle was classified as reachable:The same held for a plain view over an exporter that refers back to it. Both types now report what they hold, as
memory_traverseandmbuf_traversedo.This is what
test_gcintest_memoryviewwas covering; the threeexpectedFailuredecorators are removed, and with them the overrides that only existed to carry the decorator.An unhashable-type message dropped the module from the name
The message took the short name where CPython uses
tp_name:hash(array.array('B', b'a'))unhashable type: 'array.array'unhashable type: 'array'hash(collections.deque())unhashable type: 'collections.deque'unhashable type: 'deque'hash(Foo())whereFoo.__hash__ = Noneunhashable type: 'Foo'slot_name()already holds whattp_nameholds —name()strips everything before the last dot — so this is that accessor at the two sites that build the message. A class defined in Python is still reported by its own name.Only this message is changed.
name()is read in 321 places, and which of them CPython builds fromtp_namerather than__name__is a separate audit.Tests
extra_tests/snippets/stdlib_gc.pygains five cycle shapes through a view, andbuiltin_hash.pyfive type-name cases. Both files pass under CPython 3.14.6 as well.16 suites run clean locally — memoryview, buffer, gc, weakref, array, bytes, dict, set, collections, io, re, types, descr, exceptions, pickle, struct.
Left out
pickle.PickleBufferis still missing. It is reachable only through_pickle, andtest_pickle.pyreads a successfulimport _pickleas "the C accelerator is present", then bindsdump,dumps,load,loads,PicklerandUnpicklerfrom it in a class body. A_picklecarrying onlyPickleBuffertherefore breaks that file at import, so the accelerator has to come first.readinto() argument must be read-write bytes-like objectis reported asbuffer is not a read-write bytes-like object.ArgumentError::into_exceptionnever receives the name, which is why the arity messages readexpected at least 1 arguments, got 0too. Threading it through is a change to the argument-binding path rather than to any one converter.🤖 Generated with Claude Code
https://claude.ai/code/session_01P9HewXGX8qcGSccUxGdSPV
Summary by CodeRabbit
Bug Fixes
memoryviewobjects and custom buffer exporters, helping cyclic references be collected reliably.Tests