Project structure, how to create subpackage that will work independently? - python

Python 3.6+, directory structure:
project/
main.py
subpackage/
submain.py
config.py
main.py:
from subpackage.submain import attribute1
if __name__ == "__main__":
print(attribute1)
submain.py:
from config import config_param
attribute1 = 1 + config_param
config.py:
config_param = 100
it throws error:
Traceback (most recent call last):
File "/projects/test/project/main.py", line 1, in <module>
from subpackage.subname import attribute1
File "/projects/test/project/subpackage/subname.py", line 1, in <module>
from config import config_param
ModuleNotFoundError: No module named 'config'
We use couple gitsubmodule in our project and for now it works with:
from .config import config_param
But I am sure that this is wrong solution because it is already require in some folder/folder/folder to create such relative import ...config or ../../../config.
I already spent a week to find how to do this so that subpackage could work independently(from config import config_param), any help, links appreciate, thanks

try to add __init__.py files in your dirs https://docs.python.org/3/tutorial/modules.html

One solution that should work :
Add __init__.py in the subpackage,
Add the subpackage directory in PYTHONPATH, you can also do it with :
sys.path.append(PATH_TO_THE_SUBPACKAGE) .
The package is now part of the PYTHONPATH, so you can import it like any other libraries with import config.

Related

Python import file from the same directory: ModuleNotFoundError: No module named

I have the following files. And I want to be able to run python web\file1.py in Mod1.
Mod1
web
__init__.py
file1.py
file2.py
__init__.py
and in file1.py:
import web.file2
However, when I run the following command in the directory mod1:
....\Mod1> python .\web\file1.py
Traceback (most recent call last):
File ".\web\file1.py", line 1, in <module>
import web.file2
ModuleNotFoundError: No module named 'web'
I tried to change the content of file1.py to
from . import file2
and the error become
ImportError: attempted relative import with no known parent package
As I understood what You want, You want to have file2.py imported in file1.py
If that is correct, all You need to do is type this in file1.py
import file2
Happy Coding!
It seem you are trying to import web/file1.
Since there is an init file at mod1, you should use this in Mod1
import .web.file1 as f1
Then this in file2
import .file1 as f1

Unable to import module from Python

I am trying to import
from app.idol.IP import CONTENT_IP_ADDRESS, CONTENT_PORT
I get the following error
Traceback (most recent call last):
File "testcontent.py", line 1, in <module>
from contentactions import get_dbs
File "C:\Code\Python\xxxxx\app\idol\content\contentactions.py", line 1, in <module>
from app.idol.IP import CONTENT_IP_ADDRESS, CONTENT_PORT
ModuleNotFoundError: No module named 'app'
See directory structure.
All imports are relative to the directory where you run Python. From your screenshot it is clear that you are running testcontent.py from app\idol\content rather than main.py at the source root, so it fails to find the subdirectory app within app\idol\content.
You can instead run Python from C:\Code\Python\K2Associates like this:
python app\idol\content\testcontent.py
__init__.py is imported using a directory. if you want to import it as app you should put __init__.py file in directory named app
another option is just to rename __init__.py to app.py

cannot find module in another directory

I have the project structure:
/hdfs-archiver
/logs
/qe
__init__.py
/tests
__init__.py
archiver.py
/utils
__init__.py
HdfsConnector.py
I am trying to run archiver.py but I am getting this error:
Traceback (most recent call last):
File "qe/tests/HdfsArchiver.py", line 8, in <module>
from qe.utils import HdfsConnector
ImportError: No module named qe.utils
I read around and it seemed like most people that come across this issue fixed it with __init__.py
when I pwd:
$ pwd
/Users/bli1/Development/QE/idea/hdfs-archiver
my PYTHONPATH in .bashrc
export PYTHONPATH=$PYTHONPATH:/Users/bli1/Development/QE/idea/hdfs-archiver
I also tried having my PYTHONPATH as
/Users/bli1/Development/QE/idea/hdfs-archiver/qe
You're trying to import HdfsConnector as a function or class. Include the HdfsConnector module as part of your absolute import:
from qe.utils.HdfsConnector import my_function
You can also import the module:
import qe.utils.HdfsConnector
# or
import qe.utils.HdfsConnector as HdfsConnector
Firstly, you could try a relative import such as
from ..utils import HdfsConnector
You'd also need to run the script as a module and not as a simple python script due to the __name__ being different. This wouldn't require you to modify the path.
You can find more info here.

Python imports with __init__.py

No matter how I structure the imports in the code files and in the __init__.py files, I can't seem to get it right for executing the program and running the tests using pytest. How do I need to write the imports when my project structure looks like this:
src/
__init__.py
VocableFileWriter.py
WordListHelper.py
WordListReader.py
XLDAttributeValueAdder.py
exceptions/
__init__.py
XMLInvalidException.py
XMLParseException.py
gui/
__init__.py
GTKSignal.py
XLDAttributeValueAdderWindow.py
test/
__init__.py
test_XLDAttributeValueAdder.py
xmlparser/
__init__.py
XMLParser.py
Currently I have them like this:
In the __init__.py files I have the imports like this (src/__init__.py):
from src import *
from src.exceptions import *
from src.xmlparser import *
and in a subpackage (src/xmlparser/__init__.py):
from src.xmlparser import *
So I guess those are project-absolute paths to the modules.
In the code files themselves I import like this:
import os
import sys
from VocableFileWriter import VocableFileWriter
from XLDAttributeValueAdder import XLDAttributeValueAdder
However, when I execute the code from the directory above src using:
./src/main.py
It tells me that:
Traceback (most recent call last):
File "./src/main.py", line 6, in <module>
from VocableFileWriter import VocableFileWriter
File "/home/xiaolong/Development/PycharmProjects/xld-attribute-value-adder/src/VocableFileWriter.py", line 2, in <module>
from XMLInvalidException import XMLInvalidException
ImportError: No module named 'XMLInvalidException'
It used to be a PyCharm project, but I couldn't get it to run with the imports structure PyCharm used when not using PyCharm but running it from the terminal, so I decided I wanted to take the whole import stuff into my own hands. So don't get confused by it being in a PyCharm directory.
I also want to be able to execute the tests using for example:
py.test src/test/test_XLDAttributeValueAdder.py
How do I solve this mess?
Edit#1:
I had the program running once, but then the test complained about missing modules, probably because it's in another subdirectory and I tried so many configurations, that I don't know how I had the program running anymore. If possible please add some explanation why a certain structure is correct and works for both, tests and the program itself.
EDIT#2:
I've managed to get the tests running now, but now the program doesn't run anymore.
I emptied all the __init__.py files and used only project-absolute paths in the code files like this (src/test/test_XLDAttributeValueAdder.py):
from src.VocableFileWriter import VocableFileWriter
from src.WordListHelper import WordListHelper
from src.WordListReader import WordListReader
from src.XLDAttributeValueAdder import XLDAttributeValueAdder
from src.exceptions.XMLInvalidException import XMLInvalidException
from src.exceptions.XMLParseException import XMLParserException
from src.xmlparser.XMLParser import XMLParser
from src.test.path_helper import go_up
from src.test.path_helper import go_in
and in the main.py:
from src.VocableFileWriter import VocableFileWriter
from src.XLDAttributeValueAdder import XLDAttributeValueAdder
the output of ./src/main.py:
./src/main.py
Traceback (most recent call last):
File "./src/main.py", line 6, in <module>
from src.VocableFileWriter import VocableFileWriter
ImportError: No module named 'src'
EDIT#3:
I've tried the relative import way like this:
main.py moved one directory up
The structure now looks like this:
main.py
src/
__init__.py
VocableFileWriter.py
WordListHelper.py
WordListReader.py
XLDAttributeValueAdder.py
exceptions/
__init__.py
XMLInvalidException.py
XMLParseException.py
gui/
__init__.py
GTKSignal.py
XLDAttributeValueAdderWindow.py
test/
__init__.py
test_XLDAttributeValueAdder.py
xmlparser/
__init__.py
XMLParser.py
__init__.py files empty
main.py file gets relative
Imports look like this:
import os
import sys
from .src.VocableFileWriter import VocableFileWriter
from .src.XLDAttributeValueAdder import XLDAttributeValueAdder
When I try to run the main.py file:
Traceback (most recent call last):
File "main.py", line 6, in <module>
from .src.VocableFileWriter import VocableFileWriter
SystemError: Parent module '' not loaded, cannot perform relative import
However, there is a __init__.py file in the same directory as the main.py file, also empty.
You'd better use relative imports.
When doing from src import * in src/__init__.py you'll only import anything you've defined before calling the import. Most likely that's just nothing. If you've defined the __all__ variable, you'll get the submodule from it, but maybe also an AttributeError if a variable hasn't been defined yet.
So instead import the modules you need explicitly where you need them like
from .VocableFileWriter import VocableFileWriter
from .exceptions.XMLInvalidException import XMLInvalidException
or lets say within src/gui/GTKSignal.py
from ..exceptions.XMLInvalidException import XMLInvalidException
Also you could use project-absolute paths like mentioned in your Edit#2.
Furthermore you've a problem with your path when calling ./src/main.py. In this case the directory containing src is not in the path. Instead ./src/ is in the path. Therefore python doesn't consider it a package anymore and since there's no other package with that name available, the import fails.
Instead put your main.py module in the same directory like the src package or call it as a module with python -m src.main. Doing so you could also rename it to src/main.py and call the package instad with python -m src.
When using the first approach, main should use an absolute import structure. Just think of it as a module you put anywhere on your computer, while your src package is somewhere else, where it can be found by Python, like any other module or package installed by the system. It's not different, when it's located besides the package itself, since the current directory is in sys.path.
main.py
import os
import sys
from src.VocableFileWriter import VocableFileWriter
from src.XLDAttributeValueAdder import XLDAttributeValueAdder

Running Python script calling packages in terminal

I have a Pycharm project with the following tree:
-- Sources
|--__init__.py
|--Calculators
|--__init__.py
|--Filters.py
|--Controllers
|--__init__.py
|--FiltersController.py
|--Viewers
|--__init__.py
|--DataVisualization.py
|--Models
|--__init__.py
|--Data
Where my Filters.py calls:
import Sources.Models.Data as Dt
My FilterController.py calls:
import Sources.Calculators.Filters as Fs
import Sources.Models.Data as Dt
And so on.
First, my __init__.py is actually my main. Its imports look like this:
import Calculators.Filters as Fs
import Controllers.FiltersController as Fc
import Models.Data as Dt
import Viewers.DataVisualization as Dv
I don't think that my __init__.py working as my main is correct, but it was the way I could do __Filters.py__ and __FilterController.py__ find Sources. When I run this with Pycharm it works great. However, when I run __init__.py in terminal, I got a bunch of errors like this one:
Traceback (most recent call last):
File "__init__.py", line 10, in <module>
import Calculators.Filters as Fs
File "/Users/paulaceccon/PycharmProjects/UncertaintyQuantificationOfFilters/Sources/Calculators/Filters.py", line 6, in <module>
import Sources.Models.Data as Dt
ImportError: No module named Sources.Models.Data
I am wondering how I could do this properly, in order to have the correct Python way to use packages and to be able to run it in terminal without Pycharm.
Thank you in advance.
You hava an typo. In the folders, you named it as "Model". But when importing, you named it as "Models". In addition, you need to add the directory to Python's searching paths:
package = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(package)
You should add these lines in the outest init.py

Categories