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

Calling built-in open() with **args #4302

Closed
warsaw opened this issue Nov 30, 2017 · 5 comments
Closed

Calling built-in open() with **args #4302

warsaw opened this issue Nov 30, 2017 · 5 comments

Comments

@warsaw
Copy link
Member

warsaw commented Nov 30, 2017

I have some code that does this:

        if encoding is None:
            args = dict(mode='rb')
        else:
            args = dict(mode='r', encoding=encoding, errors=errors)
        try:
            return open(full_path, **args)   # type: ignore

If I don't include the # type: ignore comment, mypy complains:

importlib_resources/_py3.py:71: error: Argument 2 to "open" has incompatible type "**Dict[str, str]"; expected "int"
importlib_resources/_py3.py:71: error: Argument 2 to "open" has incompatible type "**Dict[str, str]"; expected "bool"

I don't know what if anything can be done about this, short of adding the ignore. I can imagine it's not so easy to support **keywords.

@ilevkivskyi
Copy link
Member

Another possible workaround is to give an explicit type for args. For example adding this line somewhere at beginning seems to fix the problem:

args: Dict[str, Any]

maybe it is possible to give a more precise type using TypedDict. I think the problem is that mypy does not know what are the keys in args so it tries to substitute a str for every parameter of open.

@ethanhs
Copy link
Collaborator

ethanhs commented Nov 30, 2017

Here is a minimal repro.

def f(a: str, b: str = '', c: int = 5) -> int:
    ...
args = dict(mode='rb')
f('', **args)

If you change the last argument to be eg, c: str = '', the error is no longer reported.

Unfortunately, I'm not sure there is a better alternative than requiring an annotation of args or casting, unless we improve our knowledge of the key/value pair types.

@warsaw
Copy link
Member Author

warsaw commented Nov 30, 2017

Thanks. Unfortunately we also need to support Python 3.4 and 3.5 which don't have PEP 526.

I'm not sure changing that to

        if encoding is None:
            args = dict(mode='rb')                  # type: Dict[str, Any]
        else:
            args = dict(mode='r', encoding=encoding, errors=errors) # type: Dict[str, Any]

is better because it means we still have to import Dict and Any without actually using them, so then flake8 complains.

@ethanhs
Copy link
Collaborator

ethanhs commented Nov 30, 2017

You can do

from typing import Dict, Any  # noqa
...
        args = dict()  # Dict[str, Any]
        if encoding is None:
            args = dict(mode='rb')
        else:
            args = dict(mode='r', encoding=encoding, errors=errors)

@ethanhs
Copy link
Collaborator

ethanhs commented Dec 2, 2017

I believe mypy did the correct thing here, so I am going to close this. If you have further concerns @warsaw, feel free to comment and I'll reopen.

@ethanhs ethanhs closed this as completed Dec 2, 2017
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