Skip to content

Bug: not properly parsing native namespace package imports, reporting "incompatible type" #9341

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
jamesbraza opened this issue Aug 23, 2020 · 4 comments

Comments

@jamesbraza
Copy link
Contributor

I am reporting a bug where mypy doesn't seem to be able to understand native namespace packages.

The current behavior is mypy seems to confuse import paths:

  • namespace.package.spam.ham.Key
  • package.spam.ham.Key

#8944 is a related issue, but in this case, mypy reports an arg-type error, saying incompatible type (not Source file found twice). Please see my repro below for more details.

The expected behavior I would like is for mypy not to raise an error.


Repro

The package follows the native namespace package folder structure from this Python packaging guide.

Folder structure as output by tree:

.
├── namespace
│   └── package
│       ├── __init__.py
│       ├── foo
│       │   ├── __init__.py
│       │   └── bar.py
│       └── spam
│           ├── __init__.py
│           └── ham.py
├── setup.cfg
└── setup.py

setup.cfg

mypy is invoked from . in the above folder structure, via simply entering mypy (thanks to files)

[mypy]

# Specifies the Python version used to parse and check the target program.
python_version = 3.8

# Shows error codes in error messages.
show_error_codes = True

# Comma-separated list of paths which should be checked by mypy if none are
# given on the command line.
files = namespace

# Enables PEP 420 style namespace packages.
namespace_packages = True

door.py

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from typing import Optional

    from namespace.package.spam.keys import Key


class DoorWithKeyhole:
    def __init__(self):
        self.key: "Optional[Key]" = None

    def specify_key(self, key: "Key") -> None:
        self.key = key


if __name__ == "__main__":
    print("This module actually runs.")

keys.py

from abc import ABC
from typing import Sequence

from namespace.package.foo.door import DoorWithKeyhole


class Key(ABC):
    def __init__(self, compatible_doors: Sequence[DoorWithKeyhole]):
        for door in compatible_doors:
            door.specify_key(self)


if __name__ == "__main__":
    print("This module also actually runs.")

mypy output:

namespace/package/spam/ham.py:10: error: Argument 1 to "add_key" of "DoorWithKeyhole" has incompatible type "package.spam.ham.Key"; expected "namespace.package.spam.ham.Key"  [arg-type]

My temporary workaround is a type: ignore[arg-type] comment.


Versions

Python==3.8.5
mypy==0.782

(also current master of 0.790+dev.2b704df25ca299e6936927be8d41d2ab945cee2a)

@gvanrossum
Copy link
Member

Seems to be because you pass a directory for the ‘files’ argument. Mypy looks inside the directory for files and it doesn’t treat it as a namespace package at that point — the PEP 420 support only works for imports.

@jamesbraza
Copy link
Contributor Author

Ah, that sounds like it could be the problem.

Invoking mypy via: mypy namespace seems to raise the same error message. How should mypy be invoked in this case?

@gvanrossum
Copy link
Member

Use -p.

@jamesbraza
Copy link
Contributor Author

Using mypy -p namespace -m setup outputs: Success: no issues found in 7 source files.

Case closed, thank you @gvanrossum !! :)

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

2 participants