Skip to content

def f() -> AnyStr fails if f returns a str #7180

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

Closed
andymwood opened this issue Jul 9, 2019 · 5 comments
Closed

def f() -> AnyStr fails if f returns a str #7180

andymwood opened this issue Jul 9, 2019 · 5 comments

Comments

@andymwood
Copy link

I expect mypy to allow the following code to pass:

from typing import AnyStr

def f() -> AnyStr:
    return "abc"

Instead, I get this:

mypy anystr.py
anystr.py:5: error: Incompatible return value type (got "str", expected "bytes")

I'm using Python 3.6 and mypy 0.711

@JelleZijlstra
Copy link
Member

Did you mean to use def f() -> Union[str, bytes]:? What you write doesn't really make sense because there's nothing to constrain the value of the TypeVar.

@andymwood
Copy link
Author

Thanks for that. It seems I'd misunderstood something. However, there's another possible bug which might have misled me into using AnyStr.

The following is closer to what I was originally trying to do:

import os
from typing import Dict, Iterable


def get_files() -> Iterable[os.DirEntry]:
    for f in os.scandir():
        yield f


def get_dict() -> Dict[str, str]:
    return {"a": "b"}


files = get_files()
x = get_dict()
for key in map(os.path.realpath, files):
    val = x.get(key)
    print(key, val)

mypy returns this error:

anystr.py:17: error: Argument 1 to "get" of "Mapping" has incompatible type "AnyStr"; expected "str"

The error goes away if I change map(os.realpath, files) to a list or generator comprehension, or call os.path.realpath inside the loop like so:

for f in files:
    key = os.path.realpath(f)

@JelleZijlstra
Copy link
Member

I think this is because you're missing a type argument on os.DirEntry; if you can mypy with --disallow-any-generics (a very useful option), mypy would likely tell you that. Try making get_files() return "Iterator[os.DirEntry[str]]" (you need the quotes because DirEntry is not generic at runtime).

@andymwood
Copy link
Author

Following your advice, I get this:

mypy --disallow-any-generics anystr.py
anystr.py:16: error: Argument 1 to "map" has incompatible type overloaded function; expected "Callable[[DirEntry[str]], AnyStr]"
anystr.py:17: error: Argument 1 to "get" of "Mapping" has incompatible type "AnyStr"; expected "str"

@ilevkivskyi
Copy link
Member

The original problem is not a bug, as Jelle explained. The second issue is a duplicate of #1317, passing one generic function (os.path.realpath in this case) as an argument to another generic function (map in this case) doesn't really work unfortunately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants