Reedinationer
Reedinationer

Reputation: 5774

How PyCharm imports differently than system command prompt (Windows)

I am having a problem running my script in a cmd prompt despite it working in PyCharm. I have a folder structure as such:

MyCode # PyCharm project folder
  /UsefulFunctions
    /Messaging
      /Texter.py
  /DiscordBot
    /DiscordBot.py

Within DiscordBot.py I have an import

from UsefulFunctions.Messaging import Texter

This works when I run it from PyCharm without a problem. However when I try to run from a command prompt located at the DiscordBot level it errors with:

ImportError: No module named 'UsefulFunctions'

So naturally I thought it meant that the UsefulFunctions folder was not on my path. Therefore, I went into my environment variables and added it to my PATH variable (as well as the MyCode folder for good measure). Still it encountered this error. I browsed some posts on here regarding imports (mainly Importing files from different folder) and they recommend doing something like:

import sys
sys.path.insert(0, '/path/to/application/app/folder')
import file

Or adding __init__.py files to each folder in order to get them to register as packages. I went ahead and added __init__ files to each folder and subfolder I was trying to import from, but still could not run from the command prompt...I ommitted the sys.path.insert() solution because I see no benefit from this after already explicitly adding it to my PATH variable. Another solution was to add "." before the import because supposedly otherwise it is only searching python's PATH. I attempted this as:

from .UsefulFunctions.Messaging import Texter

ImportError: attempted relative import with no known parent package

And this error shows on PyCharm now as well... I don't get why my initial script would work without a hitch on PyCharm, but the same program cannot seem to find my import when run from a prompt. Can somebody please explain the difference between PyCharm running the program and my prompt? Why will this not work despite having __init__.py files and having added MyCode and UsefulFunctions to my PATH variable on Windows?

Upvotes: 12

Views: 1940

Answers (4)

CristiFati
CristiFati

Reputation: 41137

From [Python.Docs]: Command line and environment - PYTHONPATH:

Augment the default search path for module files. The format is the same as the shell’s PATH: one or more directory pathnames separated by os.pathsep (e.g. colons on Unix or semicolons on Windows). Non-existent directories are silently ignored.

You can also find more details on [SO]: Strange error while using Pycharm to debug PyQt gui (@CristiFati's answer).

So, in order for Python to be able to load a module (package) without specifying its path, the path must be present in %PYTHONPATH% environment variable.

You mentioned %PATH% several times in the question but it's %PYTHONPATH% (MyCode must be added to it).

PyCharm does that because of (any of) the 2 checkboxes in the image below (dialog can be triggered from the menu: Run -> Edit Configurations...):

Img0

If you want to get things working from CmdLine, yo have to do the same thing there as well:

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q054955891\DiscordBot]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###

[prompt]> set py
Environment variable py not defined

[prompt]> "e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" DiscordBot.py
Traceback (most recent call last):
  File "DiscordBot.py", line 1, in <module>
    from UsefulFunctions.Messaging import Texter
ModuleNotFoundError: No module named 'UsefulFunctions'

[prompt]> set PYTHONPATH=e:\Work\Dev\StackOverflow\q054955891

[prompt]> set py
PYTHONPATH=e:\Work\Dev\StackOverflow\q054955891

[prompt]> "e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" DiscordBot.py
e:\Work\Dev\StackOverflow\q054955891\UsefulFunctions\Messaging\Texter.py imported

Conversely, in PyCharm (with the content roots related checkbox from above, checked), more content roots can be added like in the image below (menu: File -> Settings..., select Project Structure then Add Content Root):

Img1

This is useful when some required modules are located deeper in the project tree (and some dirs aren't valid Python package names).


So, when dealing with this type of situation, checking [Python.Docs]: sys.path, [Python.Docs]: os.getcwd() and module path, can save lots of wasted time and headaches:

import os
import sys

print(sys.path)
print(os.getcwd())

import some_module
print(some_module)

As a side note, I personally hate names starting with My (e.g. MyCode). Such a name tells me that the purpose of whatever entity "wears" it, was not clear to the person who wrote the code. Try finding a more useful name (e.g. TestBotProject, or smth similar) :).

[SO]: PyCharm doesn't recognize installed module (@CristiFati's answer) might also contain some useful info.

Upvotes: 7

Jin Thakur
Jin Thakur

Reputation: 2773

Set your Python path in System variables,So that you can run python -help from any where in directory then navigate to project folder

c:\nnnn..\mmm..\MyCode 
run python  c:\nnnn..\mmm..\MyCode\DiscordBot
    \DiscordBot.py

or

C:\Python27\python.exe "C:\Users\Username\MyCode\DiscordBot
    \DiscordBot.py" or 
C:\Python27\python.exe C:\Users\Username\MyCode\DiscordBot
    \DiscordBot.py

Try quotes if path has space

Upvotes: 0

Obaid Ur Rehman
Obaid Ur Rehman

Reputation: 323

Check your Interpreter. It is different than your command prompt Interpreter, located in Appdata, whereas the interpreter for PyCharm is in the Workspace folder.

Upvotes: 3

edd
edd

Reputation: 1417

Python uses the system variable PYTHONPATH, among other things, to decide what to import.
From the docs:

When a module named spam is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path. sys.path is initialized from these locations:

  • The directory containing the input script (or the current directory when no file is specified).
  • PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
  • The installation-dependent default.

The reason PyCharm magically imports the module when you run the script is because of the Project Structure -> Content Root value. It points to your project directory, by default.

Upvotes: 3

Related Questions