2

I've read about the workarounds (adding to sys.path or more robust solutions), but other libraries don't use such workarounds (for example, this file in tf). I don't expect I really have to either, I want to be able to import on a single line and run - I must be missing something!


To get specific, I have something like the following directory:

project/
  foo/
  src/
    __init__.py
    bar.py
    foo/
      __init__.py
      boo.py

I would expect that in bar.py I could simply write something like from foo import boo, however my IDE, PyCharm, sees this as an error.

So, trusting my IDE, I try from src.foo import boo but this results in an ImportError, as tested:

Traceback (most recent call last):
  File "bar.py", line 1, in <module>
    from src.foo import boo
ImportError: No module named 'src'

I verified that the src folder was at sys.path[0], however inserting __file__ to it did seem to resolve the issue - I still do not want to use this workaround, but will as a last resort.

I have tried a million other tricks to get this to work without success.

How can I import from a local module without using one of the workarounds?

shayaan
  • 1,482
  • 1
  • 15
  • 32
  • Is your example maybe incomplete? I couldn't see the issue in 2017.2.4 pro, it didn't report unresolved references and suggested the proper imports. At any rate, disabling the inspection seems like a somewhat extreme workaround to me. – bgse Nov 15 '17 at 14:37
  • I may have modified settings from years ago to cause this. I upgraded to community 2017.2.4 specifically to try and resolve this issue. I would have kept the inspection enabled if it had shown as a warning - which is what my settings have it set to - but it appears that another bug causes the inspection to show as an error. – shayaan Nov 15 '17 at 14:42
  • 1
    Ah ok, could be subtle differences in Community and Professional, or even some plugin or custom settings you have. I've got a fairly standard out-of-the-box configuration here. – bgse Nov 15 '17 at 14:48

2 Answers2

2

This problem is caused by a bug in PyCharm. The initial instinct to use from foo import bar was correct and will work as intended despite PyCharm's supposed error. The fact that it claimed src was a module should have set off alarms in my head.

The PyCharm warning can be safely ignored and the code can be run.

In order to stop PyCharm from misleading us in the future, we will have have to disable the 'Unresolved references' inspection. This can be done by searching for 'unresolved references' in Settings and disabling the Python inspection.

enter image description here

shayaan
  • 1,482
  • 1
  • 15
  • 32
  • If you see this answer, be sure to look at @Guy Gangemi's answer instead, it's more comprehensive and includes a way to disable the PyCharm warning for a single line only – shayaan Jul 18 '18 at 05:19
1

There's a couple of things going on here, so let's break it down.

The upper level foo directory obfuscates Pycharms resolution order. Lets try this structure:

project/
  foo_1.py
  src/
    __init__.py
    bar.py
    foo_2.py

Pycharm, by default, assumes project/ has precedence in the resolution order. In my example, if you start typing "import f" into bar.py, Pycharm's auto-complete will suggest foo_1 and not foo_2. So, when you import foo, Pycharm assumes it's the top level foo and boo IS unresolvable for it.

So why doesn't Pycharm assume foo_2?

Assume bar.py has this one line:

import foo_2

It will work if you run bar.py directly because Python adds the current working directory to Python Path. However, call it from anywhere else and your in trouble. Edit foo_1.py to have this one line:

import src.bar

Run foo_1.py directly (which makes CWD project/) and bar.py will fail to find foo_2. This is a serious issue for anybody who will be using your package and does not use project/src as the CWD, which will be everyone.

How to fix this

Standard practice is to name the source folder after the distribution. Assuming 'src' is the name of your distribution, bar.py should just do this:

import src.foo_2

Exception to the rule

I'm assuming your writing a package. If bar.py was a script and therefore likely to be called directly, then you can assume it will succeed every time and you should just disable the inspection for that line:

#noinspection PyUnresolvedRefrences
import foo
Guy Gangemi
  • 1,533
  • 1
  • 13
  • 25