Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect type inference when NewType used with Any #16021

Closed
Hnasar opened this issue Sep 2, 2023 · 2 comments
Closed

Incorrect type inference when NewType used with Any #16021

Hnasar opened this issue Sep 2, 2023 · 2 comments
Labels
bug mypy got something wrong

Comments

@Hnasar
Copy link
Contributor

Hnasar commented Sep 2, 2023

Bug Report

I created two NewTypes from a third party class which didn't have stubs. When using these NewTypes with a generic function, mypy infers the wrong result type, mixing up the two NewTypes.

To Reproduce

from some_pkg import SomeCls

Right = NewType("Right", SomeCls)
Wrong = NewType("Wrong", SomeCls)
T = TypeVar("T", Right, Wrong)

def generic_fn(data_type: type[T]) -> T: ...
assert_type(generic_fn(Right), Right)  # error: Expression is of type "Wrong", not "Right"

https://mypy-play.net/?mypy=master&python=3.11&gist=adc223e9872d9a7cae12ada10634c014

Expected Behavior

Mypy should allow for NewTypes made from Any and treat them as separate types, like other NewTypes are. (pyright handles this correctly)

Since 3.11, mypy should treat Any as subclassable, and therefore usable with NewType. (Some past discussion here: #12840 (comment))

Actual Behavior

Mypy mixes up the NewTypes made from Any.

Your Environment

  • Mypy version used: 1.2, 1.5.1, master
  • Mypy command-line flags: N/A
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: 3.10, 3.11

Non-solutions
In #12757 (comment) it was suggested to use NewType with object, but

Right = NewType("Right", cast(object, SomeCls)) gives a misc mypy error, and also even if you do
Right = NewType("Right", object) then although the generic typechecking will work, subsequent usages of the NewType instances lose all their attributes, when they should be usable like Any.

@Hnasar Hnasar added the bug mypy got something wrong label Sep 2, 2023
@erictraut
Copy link

@Hnasar, contrary to what you say above, pyright does not handle this case as you are hoping. Like mypy, pyright does not treat the types as distinct. When you derive a class from Any, many assumptions within a type checker no longer hold true.

If you want Right and Wrong to be treated as Any, you should avoid using the NewType. If you want them to be treated like distinct types (but not like Any), then you can use a pattern like this:

if TYPE_CHECKING:
    Right = NewType("Right", object)
    Wrong = NewType("Wrong", object)
else:
    from some_pkg import SomeCls

    Right = NewType("Right", SomeCls)
    Wrong = NewType("Wrong", SomeCls)

I don't think there's a way to make them work both like distinct types and like Any at the same time.

@hauntsaninja
Copy link
Collaborator

Like Eric says, I'm not sure there's a way to something Any and distinct.

Maybe something like this could be a reasonable workaround for you? https://mypy-play.net/?mypy=latest&python=3.11&gist=e12cedd85e1d0ace0f287689961997f4

@hauntsaninja hauntsaninja closed this as not planned Won't fix, can't repro, duplicate, stale Sep 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

3 participants