python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.2k stars 2.78k forks source link

Importing unstubbed submodules of stubbed modules with silent imports gives inconsistent errors #1852

Open ddfisher opened 8 years ago

ddfisher commented 8 years ago

In this example, the boto package has a stub, but the boto.foo module does not:

$ python3 -m mypy --py2 --silent-imports -c 'import boto.foo'
# no error
$ python3 -m mypy --py2 --silent-imports -c 'from boto import foo'
<string>:1: error: Module has no attribute 'foo'
$ python3 -m mypy --py2 --silent-imports -c 'import boto.foo; boto.foo'
<string>:1: error: "module" has no attribute "foo"
# in real code, this error is on line where boto.foo is used

As you can see, the behavior here is inconsistent. import boto.foo gives no error, but attempting to use boto.foo later in the program does give an error.

I think the correct behavior here is for import x.y with --silent-imports to be an error when x has a stub but y does not, because this feels conceptually similar to other cases of incomplete stubs. Otherwise, you'd be in danger of importing nonexistent submodules from packages you have full stubs for, with no way to lock that down. The only downside to this approach is it means you have to use a type ignore when the stubs are incomplete, but that's already the case most of the time.

gvanrossum commented 8 years ago

There would still be an inconsistency: if instead of boto.foo we were talking about boto_foo, then import boto_foo; boto_foo would not generate any errors (and boto_foo.bar would not either, since boto_foo would have type Any).

Back to boto.foo, there might also be cases where boto/foo.py exists (though not listed on the command line) but there's no boto/foo.pyi -- then the intention of --silent-imports would be to suppress errors about any mention of boto.foo.

So there is some argument to be made that the problem here is actually that, even though the error on import boto.foo is suppressed, you still get an error about boto.foo. I suspect that error happens because while the failing import introduce a "tombstone" for boto.foo, it doesn't do anything about the foo variable in the boto namespace.

Note that --almost-silent does point out the error in the import itself.

JukkaL commented 8 years ago

It seems to me that if import boto.foo (and other similar examples) would produce errors when using --silent-imports, we should try to enforce in typeshed that all stubs for packages include stubs for all submodules. Otherwise the behavior of --silent-imports would feel inconsistent. This is generally difficult to do as new submodules can get added in new package releases, but on the other hand we already have this problem with new functions and other things added to existing module stubs, so we could perhaps live with that.

On the other hand, if we allow partial stubs for packages, then --silent-imports should probably not complain about import boto.foo and instead do what Guido suggested. If the module name has a typo, mypy wouldn't catch this issue but it would be the same as for top-level modules. Besides, typically just trying to run the code would highlight a module name typo, unless the import is within a function.

gnprice commented 8 years ago

Discussion needed on which behavior is a bug, but it seems clear at least one of them is.