python / python/mypy

Should `*args` narrow in type guards?

Open
#14,273 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-typeguard-typeis
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

While making a PR I found a TODO that goes along the lines of "is *args support for TypeGuard even worth it?"

I want to approach this from a different perspective. Pyright supports this:

from typing_extensions import TypeGuard

def typeguard(*args: object) -> TypeGuard[int]:
  ...

def f(x: object, y: object) -> None:
  if typeguard(x, y):
    reveal_type(x)  # revealed `int`
    reveal_type(y)  # revealed `object`

I'm ... not quite sure that should be allowed. Going strictly by the specification:

Type checkers should assume that type narrowing should be applied to the expression that is passed as the first positional argument to a user-defined type guard.

(PEP 647, emphasis my own)

Notice how it says first and argument (no s). (and the "passed as" sets up that we're talking about function signature, not how the function is called)


Anyways, given that:

  • other type checkers support it
  • but it doesn't seem widely used (there's been no issue on here AFAICT about it)
  • it's not part of the specification
  • it's not clear how it should extend (first *args argument (like pyright)? all of them (which would allow more flexibility)?)

Should this even be attempted in the first place? I'm in favor of removing the TODO.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the TypeGuard *args TODO referenced in the issue and compare mypy's behavior with the PEP 647 wording and the linked Pyright example. Determine whether narrowing should apply to the first *args argument, all arguments, or none; done means the project has a decided behavior and the TODO is resolved accordingly.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.