Skip to content

Forward class keyword arguments in mypyc - #21962

Open
MarthalaJagruthiReddy wants to merge 5 commits into
python:masterfrom
MarthalaJagruthiReddy:fix/mypyc-class-keyword-forwarding
Open

Forward class keyword arguments in mypyc#21962
MarthalaJagruthiReddy wants to merge 5 commits into
python:masterfrom
MarthalaJagruthiReddy:fix/mypyc-class-keyword-forwarding

Conversation

@MarthalaJagruthiReddy

Copy link
Copy Markdown

Fixes #21938

Class-definition keyword arguments were preserved in mypy's AST but silently dropped by mypyc. This change forwards them through the native and non-native class-generation paths.

Specifically:

  • forwards keywords to __init_subclass__ for native extension classes
  • forwards keywords to the metaclass constructor for non-native classes
  • excludes metaclass= because Python consumes it for metaclass selection
  • evaluates keyword expressions before __prepare__ and the class body

Tests:

  • added native and non-native runtime regression coverage
  • updated IR expectations for the expanded runtime operation
  • mypyc class runtime suite: 125 passed
  • mypyc class IR suite: 64 passed
  • mypyc self-check: passed
  • pre-commit hooks: passed

I used an AI coding assistant to help investigate the issue and draft the implementation; I reviewed the resulting code and test behavior locally.

Fixes python#21938 by forwarding class-definition keywords to __init_subclass__ for native classes and to the metaclass for non-native classes. Adds regression coverage for both compiler paths.
Update the runtime declaration and C implementation so native classes can forward keyword arguments to __init_subclass__.
Expose the kwargs dictionary as an argument to the native __init_subclass__ operation.
Cover native and non-native class keyword forwarding and update the corresponding IR expectations.
Comment thread mypyc/irbuild/classdef.py
Comment on lines +271 to 275
# Class header expressions are evaluated before invoking __prepare__.
self.class_keyword_values = load_class_keyword_values(self.builder, self.cdef)
non_ext_dict = setup_non_ext_dict(
self.builder, self.cdef, non_ext_metaclass, non_ext_bases
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

setup_non_ext_dict calls __prepare__ of the metaclass which it looks like should also receive the keyword args.

This test works with interpreted python and fails when compiled:

from typing import Any, MutableMapping
from mypy_extensions import mypyc_attr

seen: dict[str, object] = {}

@mypyc_attr(native_class=False)
class Meta(type):
    @classmethod
    def __prepare__(
        mcls, name: str, bases: tuple[type, ...], /, **kwargs: Any
    ) -> MutableMapping[str, object]:
        global seen
        seen = kwargs
        return {}

@mypyc_attr(native_class=False)
class Base(metaclass=Meta):
    def __init_subclass__(cls, **kwargs: object) -> None:
        pass

@mypyc_attr(native_class=False)
class Child(Base, marker=1):
    pass

def test_prepare_received_class_keywords() -> None:
    assert seen == {"marker": 1}, seen

test_prepare_received_class_keywords()

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.

mypyc silently drops class keyword arguments

3 participants