Skip to content

Type inference problem with overloaded mkdtemp #1541

Closed

Description

@JukkaL

tempfile.mkdtemp returns str (in Python 2) if given no arguments. However, if any of the optional arguments is unicode, the return type should be unicode. We can use an overloaded function to represent this:

@overload
def mkdtemp() -> str: ...
@overload
def mkdtemp(suffix: AnyStr = ..., prefix: AnyStr = ..., dir: AnyStr = ...) -> AnyStr: ...

However, mypy infers type Any for call mkdtemp(), because it thinks that both signatures could match equally well. Instead, mypy should give preference to the first signature.

Activity

  1. refi64 commented on May 17, 2016

    @refi64
    Contributor

    As a workaround:

    What if the optional arguments were of type Union[AnyStr, str] and the return type AnyStr? The extra Union would ensure that unicode and str can be mixed, but if unicode values are passed in, then the return type will end up as unicode.

    Note that this is completely untested...

  2. gvanrossum commented on May 17, 2016

    @gvanrossum
    Member
  3. JukkaL commented on May 17, 2016

    @JukkaL
    CollaboratorAuthor

    Yeah, using the type of the defaults would likely be a better approach. For example:

    def mkdtemp(suffix: AnyStr = '', prefix: AnyStr = ..., dir: AnyStr = ...) -> AnyStr: ...
    

    Just one default would be sufficient here. dict.get also has a related issue once we introduce strict optional checking.

  4. matthiaskramm commented on May 17, 2016

    @matthiaskramm
    Contributor

    This highlights an interesting difference in how mypy and pytype interpret @overload in pyi.

    pytype will pick the first matching signature, mypy (it seems?) all matching signatures.

  5. JukkaL commented on May 18, 2016

    @JukkaL
    CollaboratorAuthor

    Mypy doesn't just pick all matching signatures, though it's more complex than just picking the first signature. The way the example handled is a bug in mypy.

    Originally overloads used runtime dispatch (when used outside stubs) and mypy tried to predict precisely which overload variants could be triggered by the dispatcher. There is longer runtime dispatch, but some of the old logic still persists. One of these days I (or somebody) should clean up the implementation of overloads.

    Picking just the first matching signature is not correct if one of the arguments has an Any type, as it can match anything. Also, consider this example (mypy doesn't like the overloaded function definition, actually):

    @overload
    def f(x: int) -> int: ...
    @overload
    def f(x: object) -> str: ...
    
    def g(o: object) -> None:
        a = f(o)  # can be int or str?
    

    There may be other tricky cases, but it's been while since I thought about overloads carefully.

  6. Michael0x2a commented on Jun 15, 2018

    @Michael0x2a
    Collaborator

    The original example appears to typecheck as expected now, most likely due to f61c2ba. I think we can close this; feel free to reopen if necessary.

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions