Summary
Share object/type directory collection and correct bound-method controls across directory entry points and related production Rust controls (252 changed lines across nine files).
-
Merge dynamic class __dict__ and __bases__ metadata through one recursion-guarded collector. Preserve repeated-base callbacks, mapping-only updates, non-string keys and insertion order. Return unsorted deduplicated keys; builtin dir() remains responsible for sorting.
-
Copy the instance dictionary before class lookup, retaining dict-subclass mapping behavior. Extract a mapping-only mode from the existing shared dictionary merge path rather than duplicating parsing; ordinary dict.update retains iterable-pair fallback.
-
Release the temporary keys callable before consuming its output. Preserve the distinct iterator/key/value cleanup order for mapping lookup and insertion failures, without changing native dictionary merge algorithms.
-
Compare bound-method callables through equality and truth conversion before checking owner identity. Remove the extra __module__ descriptor that suppressed exceptions and the custom __dir__ that incorrectly invoked callable directory hooks. Release callable before owner during method destruction. Existing method hash, repr and reduction remain unchanged.
-
Preserve errors from the special dir descriptor, retain the subject through sorting, and release hook results after sequence-list conversion but before comparisons.
-
Reuse sized sequence collection for object-directory hints and mapping-key conversion for no-argument dir, preserving exact list identity from custom locals.
-
Route the public object directory helper and C-API PyObject_Dir through the same VM implementation; propagate PyListRef results through builtin dir and GenericAlias.
-
Only convert missing/AttributeError dict lookup to the vars TypeError; propagate all other exceptions.
Validation
Compared with pinned CPython object directory collection, method controls, and mapping merge/copy.
Independent source review passed. Pinned CPython reference probes cover 26 method cases, 21 directory cases, 10 mapping-copy cases and four mapping-failure cleanup cases, plus two implementation lifecycle probes. These establish reference behavior and source reasoning, not a RustPython runtime pass. No unsafe proxy cycles or constructed code were executed.
Limits and integration
No repository test, Lib, marker or workflow changes. Native RustPython execution, full workspace/C-API suites and separate cross-platform graphs remain unperformed. Hosted CI is required.
The existing descriptor-construction PR #9707 is untouched. Fresh relevant method/object/type/dictionary PR patches were reviewed; this group does not duplicate them. When composing #9693, preserve its independent sparse-copy threshold and native merge mutation improvements. Do not replace the shared native dictionary algorithm with the directory-specific generic mapping path. Existing interpreter-local ownership work remains separate.
AI-assisted implementation and independent review using OpenAI Codex; model version is not exposed.
Final validation: focused threaded host-env/VM/stdlib cargo check passed in 1m06s and all-targets Clippy in 3m20s. Diagnostics exactly match the 12 unchanged baseline warnings; no suppression or unrelated baseline edits. Normal repository commit hooks passed.
Directory entry-point follow-up
Independent exact-patch source review passed; 49 pinned CPython non-debugger cases and six explicit assertions passed. Focused threaded host-env/VM/stdlib cargo check passed in 1m03s and all-targets Clippy in 2m19s; all 12 baseline diagnostics match unchanged. Normal commit hooks passed. Read-only three-way previews with #9711 head 9b809cc and held #9707 head 3125f01 show no textual conflicts and preserve both changes; combined trees were not compiled and neither branch was modified.
VirtualMachine::dir and PyObjectRef::dir now return PyListRef rather than an owned PyList payload. All in-tree callers were updated or reviewed. C-API source routing was independently reviewed but its separate crate graph was not compiled under the current disk limit; hosted C-API validation remains required. Public downstream Rust callers may need to adapt to the reference result. Debugger hooks and unrelated attribute-name diagnostics are outside this change.