Do I always need to set PYTHONPATH to my project? - python

I was having trouble to import modules of own project to other files of the project. I have a directory structure that looks like this:
my-project/
|-main.py
|-test/
|__init__.py
|-test_service_class.py
|-services/
|__init__.py
|-service_class.py
I wanted to import service_class.py to test_service_class.py, so I coded:
from services import service_class
Then I got an error saying that services is not a module... I searched a lot about it and got two ways to fix this error.
The first was adding the following weird code on the top of the files, witch looks really wrong, but works:
import sys
sys.path.append('<path_to_module>')
And the other was adding my Project's path to my PYTHONPATH...
I'm actually using the PYTHONPATH option, that looks more "correct", still I think it's weird because for each Project I start, I'll have to include the path to PYTHONPATH...
So I wanted to know if is it the best way to fix this problem, if aren't there better options, because I never had to set my Project's directory on PYTHONPATH before.
Thank you, I'm looking forward for answers!

Related

ModuleNotFoundError - Python3

New to Python and getting errors when importing modules. I have the following structure (not sure if this is a good way to show folder structure):
ecommerce
customer
__init__.py
contact.py
shopping
__init__.py
sales.py
__init__.py
I want to import contact.py from customer into sales.py in shopping but get presented with: ModuleNotFoundError: No module named 'eccommerce'.
I'm using this:
from ecommerce.customer import contact at start of the sales.py file.
Any ideas?
VSCode, MacOS 10.14.6
One thing to pay attention to is where is your current working directory located. If you have the cwd set to be in ecommerce than you should be able to access the contact with the syntax you inputted.
I ran into this issue several times and in the python documentation this setup should technically work, init files being parsed by the python parser as individual packages which you can then access. It seems though that it won't work with the standard python interpreter and I haven't found the answer why. One way to get around this is to do as #Sory suggests, at the beginning of your package entry, add the path to the environment variable. This is a work around though and can lead to problems later on.
Another option is to use a separate python interpreter, i use for example the IPython interpreter from Jupyter which runs with this setup perfectly fine. This will give you another external dependency though.
Be sure though that the current working directory is set to be the root folder though as that is usually the first problem.
from ecommerce.customer import contact would work if 'customer' was a class in the ecommerce.py file, but in your case, those are different files so it doesn't work...
The correct syntax would be:
from customer import contact
but you need to adjust those files.
Another way around would be to import os, navigate to that ecommerce folder like so: os.getcwd('insert dir path here'), and then import customer.

What is the right way to create project structure in pycharm?

I'm new to python and I don't know how to organize the project structure in the right way, so all auto imports would work in pycharm.
That's my current structure.
In PublisherSubscriberTest pycharm generated this import
from Rabbit.RabbitReceiver import RabbitReceiver
from Rabbit.RabbitSender import RabbitSender
But it's not working. That's the output.
ImportError: No module named Rabbit.RabbitReceiver
What have I done wrong?
I'm more familiar with java. And for example in java I would just create package with some classes and then I would be able to import them anywhere in my project. AFAIK it's not the same with python somehow.
Could someone explain this to me?
EDIT1:
Yes, I know about sys.path.append. I used to do it that way, but It seemed strange to me and i want to be able to do it without it.
import sys, os.path
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from Rabbit.RabbitReceiver import RabbitReceiver
from Rabbit.RabbitSender import RabbitSender
If you don't want to modify sys.path, the only way is to add -m flag when you run it
python -m messaging_system.tests.PublisherSubscriberTest
see How to fix "Attempted relative import in non-package" even with __init__.py
edit
OK, finally I found an ultimate answer: Relative imports for the billionth time
I suggest you read that post carefully, from which I learned a lot.
In short, if you want to do this, you have to add path-to-Rabbit to sys.path.

Calling modules in python

So Im a beginner to python/programming and came upon this code in a tutorial, which Im having trouble understanding.
from pythonds.basic.stack import Stack
What I did was , I went to the site-packages folder in my python directory (which holds all modules). There I could find the directory structure to be : -
pythonds/basic/stack.py
The file stack.py has a "class Stack" inside it.
So am I correct in interpreting/relating the import command to this directory structure ?
Also , whenever such a long chaining of modules happen in python, can it always be understood in such a manner.
In command line, you can do like this:
C:\Python27\Lib>pip intall pythonds
Then this module can work.
Not all the time.
It's probably better to not try and compare the directory structure with the module path, unless you have to debug modules or install them manually.
Sometimes, your PYTHONPATH will be extended to include subdirectories in site-packages, and then there'll be an extra subdirectory.
Other times, there can be an __init__.py file in the pythonds/basic/ directory (there likely is), that can contain
from .stack import Stack
in which case the import path could be
from pythonds.basic import Stack
Your understanding is right.
import pythonds.basic.stack
This will make all the classes in the module accessible by your script. Whereas,
from pythonds.basic.stack import Stack
will make only the Stack class accessible by your script.

Fail python import from another folder

I am experimenting with python, mostly troubleshooting other people's code. I am trying to get a program to run, "path\folderA\program.py".
I am running the program from path\folderA
I am getting an error:
ImportError: No module named fff.ggg.ppp
program.py contains an import:
from fff.ggg.ppp import mmm
In the folder "path\folderB" there are:
"path\folderB\fff\__init__.py"
"path\folderB\fff\ggg"
folder ggg also contains __init__.py, as well as program ppp.py
From reading other posts, like Python error "ImportError: No module named" I understand that having the __init__.py makes a folder a "package" which makes imports from it possible - but it doesn't work, since I am getting an error.
This has been working for other people that worked with these projects, so there is something wrong with my setup.
I read something about the directories having to be in the sys.path. Does that mean I have to add them to the environment variable path ? That would mean adding a lot of directories to the PATH though, so it can't be.
So I also found the following:
import sys
sys.path.append( <path to FolderB> )
But that means changing the code (which has not been necessary for other people) and hard-coding a path to what it is on my local machine - which I shouldn't have to, right ?
I can't visualize it - apparently I am not supposed to change the code and hard-code the physical path to the import module - so how can a program from folderA even know to look in folderB for an import ?
How does the magic of __init__.py work ?
I can't visualize it - apparently I am not supposed to change the code
and hard-code the physical path to the import module - so how can a
program from folderA even know to look in folderB for an import ?
You are correct. Somehow you have to tell python to look for imported modules in folderB. There is no __init__.py magic that lets you import from other folders on your hard drive.
Usually, if you've got various different python packages like that, they work by being installed into python's library. That way they can imported from anywhere. This is usually accomplished by a setup.py script. Check if folderB has one. Run it with python setup.py install.
If that doesn't work, we'll need more information about how this code is structured.
Folder B must be on the sys.path, so you would either need to move mmm to A, or modify sys.path from within A (not sure if that works). __init__.py tells python that the folder is a package, so you could have folders with __init__.py within folders with __init__.py and python treats the folders inside as parts of the parent folder. Check out sympy or almost any large python library and you will find such a structure. It can also contain code to be run on import, but can also be empty.

python import problem

although there are many posts on the internet as well as some posts on stack overflow, I still want to ask about this nasty python "import" problem.
OK. so, the open source code organization is usually like this:
project/src/model.py;
project/test/testmodel.py
if I put the famous __init__.py in project directory and also in src/ and test/ subdirectories,
and then put "from project.src import model" for the testmodel.py.
it does not work! keep telling me that the Module named "project.src" is not found!
how can I solve the problem without changing the code structure?
You shoud not add the project directory to your pythonpath but it's parent, e.g. imagine the setup
/home/user/develop/project/src/model
You'd add /home/user/develop to PYTHONPATH
If that still doesn't work, make sure you don't have a 'project.py' insite project/src/model.
Make sure you have the parent directory of project/ on your pythonpath, rather than the project directory. If you add the project path itself, imports like import project.src will look for project/project/src.
The directory where project is located is probably not in your python path.
You can use a relative import (assuming Python 2.5+) from testmodel.py, like:
from ..src import model
However, this does not work if you're running testmodel.py as the main module.

Categories