8

My imports don't work when I try to run the code from Linux terminal. Specifically, imports from other packages in the same project. I know this is a PYTHONPATH issue, but I don't know how to diagnose it further or solve it. The code runs fine inside the IDE (eclipse).

I am interested in a permanent solution, guessing it will involve editing .bashrc. I simply want to invoke scripts from command line, like

python my_script.py

os.environ["PYTHONPATH"] gives a key error in ipython terminal.

I tried

print os.getcwd()
print sys.path

Inside IDE

/home/myname/workspace/project2/main

['/home/myname/workspace/project2/main', '/home/myname/workspacep/problem2', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_6
4-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/p
ython2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pytho
n2.7/dist-packages/ubuntu-sso-client', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/lib-old']

Inside terminal

/home/myname/workspace/project2/main

['/home/myname/workspace/project2/main', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client']
Baron Yugovich
  • 3,843
  • 12
  • 48
  • 76
  • 2
    It's most likely due to you executing the script on a different path. Try to have a script that prints `os.getcwd()` and `sys.path`, and then run this individually on your IDE and the same location you're executing the script. You will see a difference. You can try `sys.path.append()` the absolute path to your IDE's `os.getcwd()`. – r.ook Jan 30 '18 at 23:34
  • I added details according to your instructions. What would be a permanent solution, can you please tell me step-by-step? I don't know what you exactly mean by sys.path.append(), and I doubt it is a permanent solution. I want to be able to invoke python scripts from command line with python my_script.py – Baron Yugovich Jan 30 '18 at 23:42
  • A permanent solution IMO would be convert your modules into a package and install it with your pip, that'll ensure your code could work on any path on any computer once the package is installed. But that's a lot more work then necessary. The next best solution would be @JohnH's answer to add to the PATH environment, you can read more [here](https://stackoverflow.com/questions/18247333/python-pythonpath-in-linux). `append()` is a temporary solution but depending on your project size that might be all you need. – r.ook Jan 31 '18 at 03:01

4 Answers4

1

my problem was the name of the python file that I was using, It was the same name as the package that I was importing and made a circular loop

MH. Abdi
  • 298
  • 5
  • 22
0

The difference between executing your script in Pycharm Eclipse vs a bash shell is the value of the environment variable $PYTHONPATH.

In Pycharm, go to preferences, then project interpreter settings and hover over the package that you're not finding in terminal. The path where that package is located should present itself. Eclipse, figure out where your project's environment variables are stored, or find the path of the modules in question.

Add that path to $PYTHONPATH in your shell with

PYTHONPATH=$PYTHONPATH:your/path/here

You can add that line to your .bashrc or .bash_profile file, you can add it to your bash script, or you can just type it every time.

Update in response to OP comment:

Use the path that points to the directory where the python modules you’re not locating are installed.

Try

python -v

in your IDE console. That should give you a list of modules and their directories.

Use the same command in your shell and the differences will show you what is missing where.

John R
  • 1,505
  • 10
  • 18
0

As mentioned, to illustrate the difference in the paths used during your IDE execution and terminal execution, run the below script in both IDE and the terminal:

import os
import sys
print(os.getcwd())
for i in sys.path:
    print(i)

Comparing the your results, when executing from the terminal, these folders are missing as compared to running in IDE:

'/home/myname/workspacep/problem2' 
'/usr/lib/pymodules/python2.7'

A thing to note is that the current working directory and sys.paths will change in terminal depending on where you run it from and where the file resides. But the key is sys.paths because they tell python where to look for modules.

I'm willing to bet the modules you are attempting to import are from one of these folders, most likely under the /home/myname/workspacep/problem2. This introduces issues as your modules are neither stored in a centralized access location (say, /usr/lib/python2.7/my_modules) nor a subfolder under your project structure.

To illustrate, I have a mock project folder set up as follows:

pi@box:~/project $ tree
.
├── main.py
├── mod1.py
└── subfolder
    ├── __init__.py
    ├── main.py
    └── mod2.py

It's a good idea to have an empty __init__.py under subfolders, see here for more details. My main.py looks like this:

import os
import sys

print(f'cwd = {os.getcwd()}')
print(f'path0 = {sys.path[0]}')

try:
    import mod1
    mod1.hello()
except Exception as e:
    print(f'import mod1 failed: {e}')

try:
    from subfolder import mod2
    mod2.hello()
except Exception as e:
    print(f'from subfolder import mod2 failed: {e}')

try:
    import mod2 as mod2copy
    mod2copy.hello()
except Exception as e:
    print(f'import mod2copy failed: {e}')

Below are my execution results when attempting to run main.py under project and project/subfolder in terminal:

pi@box:~/project $ python3 main.py

cwd = /home/pi/project
path0 = /home/pi/project
Module 1 reporting in!
Module 2 reporting in!
import mod2copy failed: No module named 'mod2'

pi@box:~/project $ python3 ./subfolder/main.py

cwd = /home/pi/project
path0 = /home/pi/project/subfolder
import mod1 failed: No module named 'mod1'
from subfolder import mod2 failed: No module named 'subfolder'
Module 2 reporting in!

pi@box:~/project $ cd subfolder
pi@box:~/project/subfolder $ python3 main.py

cwd = /home/pi/project/subfolder
path0 = /home/pi/project/subfolder
import mod1 failed: No module named 'mod1'
from subfolder import mod2 failed: No module named 'subfolder'
Module 2 reporting in!

pi@box:~/project/subfolder $ python3 ../main.py

cwd = /home/pi/project/subfolder
path0 = /home/pi/project
Module 1 reporting in!
Module 2 reporting in!
import mod2copy failed: No module named 'mod2'

You can see that between cwd and sys.path, it is sys.path that directly affects my imports, which is determined by where your main.py is stored. When running main.py under the project root, I was able to import both mod1 from root and mod2 from subfolder as expected. mod2copy is supposed to fail because there is no mod2 in root. However when executing main.py stored in the subfolder, mod1 has failed to import because python doesn't know where mod1 is stored, due to missing sys.path. If I however added this following line before importing:

sys.path.append('/home/pi/project')

The result of the main.py under subfolder will become:

pi@rpirpirpi:~/project/subfolder $ python3 main.py

cwd = /home/pi/project/subfolder
path0 = /home/pi/project/subfolder
Module 1 reporting in!
Module 2 reporting in!
Module 2 reporting in!

You'll note all 3 imports are successful. Python is able to locate mod1 and /subfolder/mod2 because the root path is now added to the script's sys.path. And mod2copy is still successful because the subfolder is already part of the sys.path list before the append.

All that said, it gets messy when you have a module that references another module inside the substructure. Say, /subfolder/module3 tries to import mod2 and you're executing from /project/main.py, the line import mod2 when your script execute from subfolder import mod3 will return a ModuleNotFoundError just as before because sys.path doesn't contain /project/subfolder, so you'll need some finesse in all these imports between modules. Another thing to consider is relative path - if you start moving files around, all these sys.path will need to be maintained.

To summarize - if you are expecting to import modules that are neither in the Python library nor nested under your project root, you're in for a bad time.

The above was a quick and easy remedy for small ad-hoc projects, say, for temporary testing before you finalize the modules. But if your intention is to reuse these modules for future projects, consider storing them in a centralized path and add to your PYTHONPATH. This thread have some more information,, for example if you want to store your modules under /home/myname/modules:

add the below line to your ~/.bashrc:

export PYTHONPATH="${PYTHONPATH}:/home/myname/modules"

... and then add an empty file named __init__.py in each folder created under modules (including modules itself) to avoid import issues.

If you are up for the extra work, as mentioned, you can always look into converting the modules into a package and install it via pip. This way you don't have to worry about PATH handling at all.

r.ook
  • 13,466
  • 2
  • 22
  • 39
  • So in your example, what can I use instead of /home/myname/modules? Is it the path to workspace, or I need to do the project itself, as in project2? I don't want to do it for each project separately, if I can get away with that. – Baron Yugovich Jan 31 '18 at 17:11
  • You *can* add the path `/home/myname/workspace/problem2` to your PYTHONPATH if you want, but what happens with problem3? problem4? You'd end up with a bunch of PYTHONPATH that contaminates your environment. Thus why if it's temporary, I'd properly set up the folder structure, or failing that, use `sys.path.append`. Otherwise, the best thing you can do is structure your modules under a main folder as suggested. There's no easy solution, the root cause lies in the project structure. – r.ook Jan 31 '18 at 17:14
0

The reason for the difference between the executions from terminal and from an IDE might be the virtual environment which maybe configured for the IDE but not for the actual environment where you run your code by the terminal. You can check it by running the command: path_of_virt_env your_command. 'path_of_virt_env' is the first argument your IDE display as output on console when running your code form IDE. Now, to solve it, pip install all imported libraries in your terminal.

barper
  • 99
  • 7