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

List comprehension in __all__ definition hides module members #289

Closed
Achillx opened this issue Aug 27, 2020 · 4 comments
Closed

List comprehension in __all__ definition hides module members #289

Achillx opened this issue Aug 27, 2020 · 4 comments
Labels
dynamic behavior needs decision Do we want this enhancement?

Comments

@Achillx
Copy link

Achillx commented Aug 27, 2020

Environment data

  • Language Server version: 2020.8.2
  • OS and version: macOS Mojave 10.14.6
  • Python version: Python 3.7.6 | packaged by conda-forge

Expected behaviour

Importing a function from a sub-package using from package import foo Pylance is able to find the definition.

Actual behaviour

Importing a function from a sub-package using from package import foo and hovering on the function, Pylance displays
(import) foo: Any.

Screenshot 2020-08-27 at 13 27 12

and when right-clicking and "Go to Definition" displays "No definition found for foo"

Screenshot 2020-08-27 at 13 28 42

If the function is imported using from package.sub_package import foo it finds it

Screenshot 2020-08-27 at 13 27 22

Code Snippet / Additional information

The folder structure is:

main.py
package
└─ __init__.py
└─ package_file.py
└─ sub_package
   └─ __init__.py
   └─ sub_package_file.py

Files content for those who don't want to download the zip file
pylance_test.zip

main.py

from package import dog
from package.sub_package import cat
from package import cow

print(dog(4))
print(cat(2))
print(cow(8))

package init

from .sub_package import *
from .package_file import *

__all__ = [name for name in dir() if not name.startswith('_')]

sub_package init

from .sub_package_file import *

__all__ = [name for name in dir() if not name.startswith('_')]

sub_package_file.py

__all__ = [
	'cat',
	'dog'
]

def cat(t):
	""" 
	Make the cat meow

	Parameters
	----------
	t : int
		How many times to meow

	Returns
	-------
	string
	"""

	return "Cat says:" + " meow" * t

def dog(t):
	""" 
	Make the dog bark

	Parameters
	----------
	t : int
		How many times to bark

	Returns
	-------
	string
	"""

	return "Dog says:" + " woof" * t + "!!"

if __name__ == "__main__":
	print(cat(1))
	print(dog(3))

package_file.py

__all__ = [
	'cow'
]

def cow(t):
	""" 
	Make the cow moo

	Parameters
	----------
	t : int
		How many times to moo

	Returns
	-------
	string
	"""

	return "Cow says: m" + "oo" * t + "!!"

if __name__ == "__main__":
	print(cow(8))
@erictraut
Copy link
Contributor

The problem is that you are using wildcard imports with a value of __all__ that is defined with a complex dynamic expression. Pylance is based on Pyright, which is a static type analyzer. It is able to evaluate expressions like __all__ = ['cow'], but it cannot evaluate something as dynamic as __all__ = [name for name in dir() if not name.startswith('_')].

If you comment out two dynamic __all__ expressions within your example above, Pyright is able to see the imported symbol dog.

If you want your package to work correctly with static type checkers, you should either avoid using wildcard imports or replace dynamic __all__ expressions with static expressions like __all__ = ['cat', 'dog'].

@jakebailey jakebailey added the waiting for user response Requires more information from user label Aug 27, 2020
@github-actions github-actions bot removed the triage label Aug 27, 2020
@Achillx
Copy link
Author

Achillx commented Aug 30, 2020

Thanks for the info!
Since I'm not the main developer of the package in question (not the one with the cat and dog!) , I'll point them to your suggestion.

@judej
Copy link
Contributor

judej commented Apr 19, 2022

Closing old issue. If this is still a problem, please reopen with the information requested. thanks

@judej judej closed this as completed Apr 19, 2022
@debonte
Copy link
Contributor

debonte commented Apr 19, 2022

Here are the forms of all that type checkers have agreed to support: https://github.com/microsoft/pyright/blob/main/docs/typed-libraries.md#library-interface

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dynamic behavior needs decision Do we want this enhancement?
Projects
None yet
Development

No branches or pull requests

5 participants