Skip to content

Reuse checked signatures for deque, timezone and type - #9773

Draft
youknowdot wants to merge 6 commits into
RustPython:mainfrom
youknowdot:fix/legacy-native-signatures-20261110
Draft

youknowdot wants to merge 6 commits into
RustPython:mainfrom
youknowdot:fix/legacy-native-signatures-20261110

Conversation

@youknowdot

@youknowdot youknowdot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Depends on #9756's explicit checked text_signature support. This is now an actual dependent follow-up, not a second implicit docstring-header mechanism. Once #9756 merges, this PR's diff can be reduced to the remaining extensions and four applications.

  • Remove the four copied Rust docstrings and the implicit header-detection bypass from the original revision. All four documentation bodies continue to come from the existing rustpython-doc database; no production documentation text is duplicated or edited.
  • Reuse text_signature for class implementations, validated against initializer/constructor argument metadata. An explicit class display may retain an unrepresentable default without passing the ordinary representability filter.
  • Support CPython's deque bracket notation without /. Verify arity, requiredness, receiver markers, and keyword names; omitted kind notation leaves the actual binder authoritative.
  • Permit $cls as a display alias of a class receiver. For known unrestricted *args, **kwargs binders only, preserve the pre-existing declared PARAMS contract rather than imposing a different binder. Unknown binding metadata remains an error.
  • Avoid counting the implicit scalar class receiver twice while retaining rejection of unknown/custom receiver metadata. This corrects compile-time signature metadata, not argument conversion.
  • Apply these declarations to deque, deque.index, timezone, and type.__prepare__. Argument conversion, dispatch, and runtime validation remain unchanged. All additional checking/composition happens at compile time.
  • Retain exact signature/doc/inspect regression coverage and test that type.__prepare__ still ignores arbitrary supplied arguments and returns a fresh namespace.

CPython 3.15 basis

  • _collectionsmodule.c: deque constructor and index explicitly use Argument Clinic @text_signature overrides, independently of their actual parameter kinds.
  • _datetimemodule.c: timezone's optional name has a NULL default, displayed as <unrepresentable>.
  • type_prepare ignores all arguments; its method table publishes $cls, name, bases, /, **kwds separately.

Validation

  • Rebased onto main c07e0bc954.
  • builtin_signature.py: passes on the new RustPython binary and CPython 3.15.2; all four raw signatures and complete documentation bodies match exactly.
  • -m test test_deque test_datetime test_inspect: success, 1,622 tests with 152 skips.
  • Full extra_tests pytest: 495 passed, 20 failed, 15 subtests passed. Re-running the same failures against the prior baseline reproduces all 20 failures exactly (sandbox socket/IPC permissions, CPython distribution/test-package/version expectations, and _sqlite3 omitted from the default build). This is not a full-suite green claim.
  • Pre-commit checks pass. Final workspace/CAPI Rust tests and strict Clippy are still running locally; hosted CI is pending. VM optimization is preserved; only debug information is reduced for local resource limits.

AI assistance

OpenAI Codex assisted with review, implementation, and validation.

@coderabbitai

coderabbitai Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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 thread crates/stdlib/src/_datetime.rs Outdated

// timezone

/// timezone(offset, name=<unrepresentable>)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

dont' manually add docs

@youknowone youknowone left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The mechanism looks right: has_internal_doc_signature follows find_signature + skip_signature in Objects/typeobject.c (the doc must start with name(, the scan looks for )\n--\n\n, and it gives up at a blank line). These four objects get their text signatures from hand-written docstring headers in CPython as well. A few things should change before merging, though.

Observed before → after

Before: a build of 45a012cda (main at the time). After: the values asserted in this PR's snippet, which match CPython 3.15.

object __text_signature__ before after (= CPython) inspect.signature
deque None '([iterable[, maxlen]])' ValueError both
deque.index '($self, needle, start=0, stop=<unrepresentable>, /)' '($self, value, [start, [stop]])' ValueError both
timezone None '(offset, name=<unrepresentable>)' ValueError both
type.__dict__['__prepare__'] '($type, name, bases, /, **kwds)' '($cls, name, bases, /, **kwds)' (type, …) → (cls, …)

In practice this changes raw metadata only. The only inspect-visible difference is the receiver name of the unbound __prepare__.

1. Drop "legacy" from the naming; one comment is factually wrong

The feature is "an explicit internal-doc signature in the docstring is used as-is", and has_internal_doc_signature already says that. "Legacy" in the title, branch, code comment, test name and snippet comment does not describe it:

  • The comment in signature.rs, "Explicit Clinic headers cover legacy signatures that are not Python parameter lists", is wrong for __prepare__: ($cls, name, bases, /, **kwds) is an ordinary parameter list. Only the deque headers use optional groups. Something like: "A doc that starts with a complete name(...)\n--\n\n header supplies its own text signature."
  • explicit_internal_doc_preserves_legacy_signatures → e.g. explicit_internal_doc_signature_is_kept.
  • Snippet comment "Legacy Clinic headers …" and the legacy signature should remain unrepresentable message → describe them as explicit internal-doc signatures.
  • PR title → e.g. "Honor explicit internal-doc signatures for deque, timezone and type.prepare".

#9757 went through the same rename (legacy_signature → signature_from_flags) for the same reason.

2. The header is used implicitly and never checked against the Rust binding

Any /// doc that happens to be header-shaped now silently replaces the generated signature, and nothing checks the hand-written header against the real arguments. The drift is already there: deque.index binds needle in Rust, while the header says value. The displayed text is correct today, but a later change to the Rust signature would go unnoticed.

#9757 takes the opposite approach: an explicit #[pyfunction(signature_from_flags)] opt-in, plus const assertions that reject a mismatched arity at compile time. CPython does not validate hand-written headers either, so this is not a parity bug. It is still inconsistent within RustPython. Please consider at least a const check that the header's positional arity agrees with the binding metadata, or an explicit opt-in so the override cannot happen by accident.

3. Docs are now split between two sources

Because a /// doc overrides the crates/doc DB entry, the bodies of these four docstrings are now hard-coded in Rust, and regenerating crates/doc/src/data.inc.rs will no longer update them. crates/doc/generate.py stores only __doc__, which has the header stripped. A broader fix would be to have the generator also capture __text_signature__. That can be a follow-up, but it should be acknowledged here.

4. Conflict with #9757

Both PRs append to crates/vm/src/function/signature.rs and to the end of extra_tests/snippets/builtin_signature.py, so whichever lands second needs a rebase.

— commented by Claude

@youknowdot
youknowdot force-pushed the fix/legacy-native-signatures-20261110 branch 3 times, most recently from a6fadd3 to 847ee0b Compare November 11, 2026 14:42
youknowdot and others added 5 commits November 12, 2026 22:35
Keep optional-group and CSV display signatures separate from argument binding. Validate explicit overrides against binding metadata in a const context and preserve legacy call behavior.

Assisted-by: OpenAI Codex: model version not exposed
Assisted-by: OpenAI Codex:model version not exposed
Assisted-by: OpenAI Codex:model version not exposed
Assisted-by: OpenAI Codex:model version not exposed
Assisted-by: OpenAI Codex:model version not exposed
@youknowdot
youknowdot force-pushed the fix/legacy-native-signatures-20261110 branch from 847ee0b to 632530b Compare November 12, 2026 14:48
@youknowdot youknowdot changed the title Preserve legacy deque, timezone and type signatures Reuse checked signatures for deque, timezone and type Nov 12, 2026
Assisted-by: OpenAI Codex:model version not exposed
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.

3 participants