Skip to content

PEP 827: Type Manipulation#4834

Open
msullivan wants to merge 5 commits intopython:mainfrom
msullivan:type-manipulation
Open

PEP 827: Type Manipulation#4834
msullivan wants to merge 5 commits intopython:mainfrom
msullivan:type-manipulation

Conversation

@msullivan
Copy link
Contributor

@msullivan msullivan commented Feb 28, 2026

Basic requirements (all PEP Types)

  • Read and followed PEP 1 & PEP 12
  • File created from the latest PEP template
  • PEP has next available number, & set in filename (pep-NNNN.rst), PR title (PEP 123: <Title of PEP>) and PEP header
  • Title clearly, accurately and concisely describes the content in 79 characters or less
  • Core dev/PEP editor listed as Author or Sponsor, and formally confirmed their approval
  • Author, Status (Draft), Type and Created headers filled out correctly
  • PEP-Delegate, Topic, Requires and Replaces headers completed if appropriate
  • Required sections included
    • Abstract (first section)
    • Copyright (last section; exact wording from template required)
  • Code is well-formatted (PEP 7/PEP 8) and is in code blocks, with the right lexer names if non-Python
  • PEP builds with no warnings, pre-commit checks pass and content displays as intended in the rendered HTML
  • Authors/sponsor added to .github/CODEOWNERS for the PEP

Standards Track requirements

  • PEP topic discussed in a suitable venue with general agreement that a PEP is appropriate
  • Suggested sections included (unless not applicable)
    • Motivation
    • Specification
    • Rationale
    • Backwards Compatibility
    • Security Implications
    • How to Teach This
    • Reference Implementation
    • Rejected Ideas
    • Open Issues
    • Acknowledgements
    • Footnotes
    • Change History
  • Python-Version set to valid (pre-beta) future Python version, if relevant
  • Any project stated in the PEP as supporting/endorsing/benefiting from the PEP formally confirmed such
  • Right before or after initial merging, PEP discussion thread created and linked to in Discussions-To and Post-History

📚 Documentation preview 📚: https://pep-previews--4834.org.readthedocs.build/pep-0827/

@msullivan msullivan requested a review from a team as a code owner February 28, 2026 00:01
@msullivan msullivan force-pushed the type-manipulation branch 2 times, most recently from 034175e to bdec986 Compare February 28, 2026 00:07
Co-authored-by: Daniel W. Park <daniel.park@vercel.com>
Co-authored-by: Yury Selivanov <yury@vercel.com>
@brianschubert brianschubert added the new-pep A new draft PEP submitted for initial review label Feb 28, 2026
we don't want to tangle with yet, and because many use cases can be
simulated in other ways.

.. * Should we support building new nominal types??
Copy link
Member

Choose a reason for hiding this comment

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

It's up to you! Delete if not adding.

Suggested change
.. * Should we support building new nominal types??

Copy link
Member

@hugovk hugovk left a comment

Choose a reason for hiding this comment

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

GitHub insists "You need to leave a comment indicating the requested changes." 🤷

msullivan and others added 2 commits February 28, 2026 10:43
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
@msullivan
Copy link
Contributor Author

Thanks for the edits!

That is, it is a "consistent subtype". This is subtyping extended
to gradual types.

* ``IsEquivalent[T, S]``:
Copy link
Member

Choose a reason for hiding this comment

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

That's inconsistent with how the spec defines the term "equivalent". This is describing consistency, not equivalence.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, argh, you're right. IsConsistent seems quite a worse name, though. I've added a note indicating that the real relation is consistency, and we can discuss what the name ought to be in detail as part of the main pep discussion?

In order to allow an evaluator library to trigger type evaluation in
those cases, we add a new hook to ``typing``:

* ``special_form_evaluator``: This is a ``ContextVar`` that holds a
Copy link
Member

Choose a reason for hiding this comment

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

I don't really understand how you'd use this.

Let's look at a concrete example. If I define a Pydantic-like class like this:

class MyModel[T](BaseModel):
    x: T
    y: int if IsAssignable[T, int] else str

MyModel(1, 1) # OK
MyModel(1.0, "x") # OK
MyModel(1.0, 1) # error, second arg must be str

What would Pydantic need to do so it can typecheck this correctly at runtime?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Those particular examples I think probably wouldn't work at runtime (... though I think if you really tried you could make it) since they'd have to do inference based on the easily inferrable arguments, which pydantic doesn't do. It does support it if you supply the type with [] though, so it should be able to support:

    MyModel[int](x=1, y=1)  # OK
    MyModel[float](x=1.0, y="x")  # OK
    with pytest.raises(TypeError):
        MyModel[float](x=1.0, y=1)  # error, second arg must be str

I made an example of how it can be implemented on top of the current prototype type evaluator library we have (supporting my modified example above): https://github.com/vercel/python-typemap/blob/e0301f889037b86c3e2b83467d9e2ee0560ba879/tests/test_model_like.py#L23-L34

The approach is that we need to "evaluate" the type MyModel[float], which means to substitute in the type arguments and evaluate the members as needed, which will sometimes involve evaluating type operators.
To do this we'll call the __annotate__ function on MyModel with the type argument from the _GenericAlias injected in place of the TypeVar for T. While doing this whole process, we'll have special_from_evaluator set to point at a callback that calls back into the type evaluator, which will then evaluate IsAssignable, etc.

It's a little involved but can be well-encapsulated--the Pydantic-like constructor in the test basically just calls eval_typing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new-pep A new draft PEP submitted for initial review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants