0

I am working in a Pycharm environment with the following organization:

main.py
foo/
 - __init__.py
 - bar.py
 - egg.py
 - foo.py

egg.py contains only one method:

def spam():
    print("spam")

from bar.py, I can import egg.py, like so:

import egg
egg.spam()

and it works fine, except Pycharm underlines "egg" from import egg as an error

No module named egg less... (Ctrl+F1) Inspection info: This inspection detects names that should resolve but don't. Due to dynamic dispatch and duck typing, this is possible in a limited but useful number of cases. Top-level and class-level items are supported better than instance items.

This "error" doesn't stop it from correctly executing egg.spam, though.

Is this a problem with Pycharm? If not, what would be the correct way to do that?

As a sidenote, if I try importing from foo instead of egg Pycharm does not notice any error, but I suspect it is mistaking the module foo.py with the package foo.


I also tried marking the main directory as "Sources Root" but it doesn't help: asking for

import foo.egg

in bar.py raises:

ModuleNotFoundError: No module named 'foo.egg'; 'foo' is not a package

Just to be extra clear I am not doing anything fancy here: I just select bar.py, right-click on it and select "run". I want this to work for any module without having to change settings every time I run a different module.

Anne Aunyme
  • 506
  • 4
  • 14
  • This is complicated to explain. See the **first rule** in [6.1.2. The Module Search Path](https://docs.python.org/3/tutorial/modules.html#the-module-search-path). If you try to execute inside inside the package (`C:\dir\foo`) you have the 3 modules in `sys.path` that's why `import egg` works! But if you execute outside the package (`C:\dir\ `) you'll have the package on `sys.path` so you'll have to write `from . import egg` or `import foo.egg`. (Strange isn't it? That depending from where you execute you have to write the imports differently...?!) – bad_coder Jun 23 '21 at 03:47
  • The way to circumvent the above problem is to install the package. (See [this post](https://stackoverflow.com/q/62498127) for an example.) This corresponds to the **second rule** in [6.1.2. The Module Search Path](https://docs.python.org/3/tutorial/modules.html#the-module-search-path). Where basically you create a `venv`, activate it, install the package, and it becomes part of your PYTHONPATH. – bad_coder Jun 23 '21 at 03:55
  • The IDE warning you are getting can't be fully answered without knowing how your entire project is configured and how you choose the interpreter. But if you create a Project, and choose an interpreter, and the package you are showing is inside a directory that is configured as sources root, then the warning should not show. (The thread linked as a duplicate target tries to explain that part). So there are 2 overlapping issues to your question and each, by itself, can be confusing. – bad_coder Jun 23 '21 at 03:58
  • @bad_coder so basically what you are telling me is that there is no way to have reliable imports if my project uses packages without installing them? It doesn't look normal at all. Just to be sure I sat the directory where "main.py" is as source root. This times Pycharm is ok with me writing "import foo.egg" (but not with "import egg"), but it actually can't import it: > ModuleNotFoundError: No module named 'foo.egg'; 'foo' is not a package – Anne Aunyme Jun 23 '21 at 12:19
  • This time your import is 100% correct (the trick is that you have to execute from outside the package - because the package, not the individual modules, needs to be on `sys.path`)!! So then, internally, (this is how basically everyone is doing it today) all your imports should be written using the ["fully qualified names"](https://stackoverflow.com/a/17403972) and if you write your code respecting this rule you'll never get [cyclic import errors](https://stackoverflow.com/questions/744373) which is the next difficulty you'll find when writing complex packages. – bad_coder Jun 23 '21 at 12:40
  • You made a mistake in your last comment. Now you have to execute from `C:\outside_path\ ` (NOT FROM inside `C:\outside_path\foo\ ` !!) – bad_coder Jun 23 '21 at 12:44
  • @bad_coder Afaik, "import foo.egg" is already using fully qualified names. Still it raises ModuleNotFoundError. – Anne Aunyme Jun 23 '21 at 12:45
  • Because you are making a mistake in your last comment. Now you have to execute from `C:\outside_path\python -m foo.egg ` (NOT FROM inside `C:\outside_path\foo\python -m foo.egg ` !!) The way to execute the modules individually is to call them also with fully qualified names. If you want short aliases you have to expose them as such in the `__init__.py` – bad_coder Jun 23 '21 at 12:45
  • @bad_coder to be more clear: I want to be able to directly execute any of those files (main.py, foo.py...) without having to change my settings between two executions – Anne Aunyme Jun 23 '21 at 13:04
  • There's a reason why you use a package. One of the reasons is to define a rigid internal structure of dependencies (afterwards you can't -shouldn't- take modules in isolation out of the package context). The rules are that if you want to "call" something from a package you should define [an entry point](https://setuptools.readthedocs.io/en/latest/userguide/entry_point.html#entry-points) and that is not without reason. – bad_coder Jun 23 '21 at 13:18
  • @bad_coder and that is why i don't import from main.py to any of foo.py, bar.py nor egg.py. I don't get how wanting to be able to run bar.py is unreasonable. – Anne Aunyme Jun 23 '21 at 13:26
  • Yes, the issue is wanting to import in the context of a package and then wanting to execute ignoring that context :) – bad_coder Jun 23 '21 at 13:32
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/234116/discussion-between-anne-aunyme-and-bad-coder). – Anne Aunyme Jun 23 '21 at 13:56

0 Answers0