Skip to content

Let plugins customize class MRO #4527

@snarkmaster

Description

@snarkmaster

The Python metaclass data model allows the mro() method to be overloaded. This is a genuinely useful feature for dealing with metaclasses whose classes must support inheritance. See "Example" below.

I wrote a mypy plugin for type-checking instances of my metaclass. I was able to model its semantics almost correctly with the existing plugin hooks, except for one thing — customizing the MRO.

The best way I can get my type-checker unblocked is by adding a plugin hook for customizing the MRO. My idea is roughly this:

  • Move calculate_class_mro to be a member of SemanticAnalyzerPass2
  • Add a plugin hook that gets to customize the computed MRO.

@JukkaL, does this sound like a feature you would take?

Example of needing to customize the MRO:

  • My metaclass M injects a implementation-detail base M_classname_base into each class it creates. M's semantics demand that M_classname_base be at the very end of the MRO (to allow overloading of its features).
  • Let us define class A(metaclass=M) and class B(A).
  • Each class injects its own base: M_A_base and M_B_base. That means that B actually has both implementation-detail bases.
  • Unfortunately, M_A_base and M_B_base conflict, and M_B_base ends up after M_A_base in the MRO, which is the opposite of what you want (child must overload parent, not vice versa).
  • At runtime, M.mro() can simply remove the A-produced base from B's MRO, and all is well.
  • In current mypy, removing M_A_base from B's MRO seems impossible.

Cc: @carljm, if you're curious.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions