Transform a python folder into a package: `ModuleNotFoundError` - python

Suppose that in a folder my_package, i have three files :
__init__.py, blanck
file1.py, containing a functon function1
file2.py, containing the import statement : from file1 import function1
Then, from another directory, when I use import my_package.file2 as file2, I have a ModuleNotFoundError coming from the line of the statement from file1 import function1.
Obviously, i did something wrong somewhere. But where ? The MWE i gave is small, but i append to have a lot of python files in my_package folder, some of them importing each other. I'm trying to change this directory into a package that i can import from elsewhere, that's why i added the __init__.py blanck file, but it does not seem to work that way.

Check this tree structure.
my_package
|
'----- __init__.py
'----- file1.py
'----- file2.py
Script (somewhere in your system)
|
'--- test.py
when you import my_package (import my_package.file2 as file2) in the another directory say in test.py, it looks for the directory named my_package in its current path.. (i.e. inside Script folder )
as my_package is not present inside the Script folder you will get the error ModuleNotFoundError.
so in test.py write the code as shown below
import sys
sys.path.append("/home/MyFiles/my_package") # absolute path of the my_package folder
import file2
# Now use file2 and work on it
# all other modules/files in my_package folder can also be imported.

I suppose i found the solution myself : I added a setup.py file with propper content to the folder and then i ran pip -m my_package, allowing me to import it from everywhere..

Related

Import .py file from parent directory

I wanted to import a file from another folder into another file in the same root folder.
Directory list:
ROOT/
resource/
console_log/
__init__.py (empty)
file1.py
libs/
__init.py__ (empty)
function.py
__init__.py (empty)
I tried using this code in resource/console_log/file1.py:
from resource.libs.function import function_name
It just doesn't work. Returns this error:
No module named 'resource'
If I use this code instead
from ..libs.function import function_name
It gives me this:
attempted relative import with no known parent package
How can I solve?
Is there any way to fix it without using the sys?
EDIT:
I "fixed" the problem by moving all the files directly to the libs folder thus removing the resource folder. Except that if from libs/file1.py I want to import a function present in the main.py file I get the same error
New folder structure:
ROOT/
libs/
__init__.py
file1.py
file2.py
function.py
logs/
debug.log
__init__.py
main.py
If I use this code in the libs/file1.py file, it works correctly (only if I start it from the main.py file)
# file1.py
from libs.function import function_name
But if in libs/file2.py I want to recall a variable present in the main.py file, it returns me an error
# file2.py
from main import data
# ERROR
No module named 'main'
If he doesn't give me this error he gives me another one
attempted relative import with no known parent package
I think your PYTHONPATH isn't set correctly. You can either export it or run your program with it set as expected for the single command. The following will set the PYTHONPATH for the single command execution:
PYTHONPATH=./:$PYTHONPATH python resource/console_log/file1.py

Importing module from different folder using relative path and __init__.py files

I'm on Windows 10, using Python 3.8.3. Here is my simple folder structure:
root_project_folder\
__init__.py # Empty file
project_1_folder\
__init__.py # Empty file
foo.py
project_2_folder\
__init__.py # Empty file
bar.py
Within foo.py I have the following code:
from ..project_2_folder.bar import Test
Test.test_method()
Within bar.py I have the following code:
class Test:
#staticmethod
def test_method():
print("Test successful")
When I run foo.py, I receive the following error:
ImportError: attempted relative import with no known parent package
I've read a few threads about importing using relative paths. Here are the threads for reference:
Python3 relative imports failing in package
Importing files from different folder
What is init.py for?
I did not append any directories to sys.path. I also did not modify PYTHONPATH either, such as adding directories as an environment variable. From what I have read, I don't need to do any of that. Would I have to add something to one of the __init__.py files?
Any help would be appreciated.

'ModuleNotFoundError' when trying to import module from imported package

This is my directory structure:
man/
Mans/
man1.py
MansTest/
SoftLib/
Soft/
SoftWork/
manModules.py
Unittests/
man1test.py
man1.py contains the following import statement, which I do not want to change:
from Soft.SoftWork.manModules import *
man1test.py contains the following import statements:
from ...MansTest.SoftLib import Soft
from ...Mans import man1
I need the second import in man1test.py because man1test.py needs access to a function in man1.py.
My rationale behind the first import (Soft) was to facilitate the aforementioned import statement in man1.py.
Contrary to my expectation, however, the import statement in man1.py gives rise to:
ModuleNotFoundError: No module named 'Soft'
when I run
python3 -m man.MansTest.Unittests.man1test
from a directory above man/.
Is there any way to resolve this error without changing the import statement in man1.py and without adding anything to sys.path?
Edit: python3 -m man.ManTest.Unittests.man1test from the original version of the question changed to python3 -m man.MansTest.Unittests.man1test
FIRST, if you want to be able to access man1.py from man1test.py AND manModules.py from man1.py, you need to properly setup your files as packages and modules.
Packages are a way of structuring Python’s module namespace by using
“dotted module names”. For example, the module name A.B designates a
submodule named B in a package named A.
...
When importing the package, Python searches through the directories on
sys.path looking for the package subdirectory.
The __init__.py files are required to make Python treat the
directories as containing packages; this is done to prevent
directories with a common name, such as string, from unintentionally
hiding valid modules that occur later on the module search path.
You need to set it up to something like this:
man
|- __init__.py
|- Mans
|- __init__.py
|- man1.py
|- MansTest
|- __init.__.py
|- SoftLib
|- Soft
|- __init__.py
|- SoftWork
|- __init__.py
|- manModules.py
|- Unittests
|- __init__.py
|- man1test.py
SECOND, for the "ModuleNotFoundError: No module named 'Soft'" error caused by from ...Mans import man1 in man1test.py, the documented solution to that is to add man1.py to sys.path since Mans is outside the MansTest package. See The Module Search Path from the Python documentation. But if you don't want to modify sys.path directly, you can also modify PYTHONPATH:
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.
THIRD, for from ...MansTest.SoftLib import Soft which you said "was to facilitate the aforementioned import statement in man1.py", that's now how imports work. If you want to import Soft.SoftLib in man1.py, you have to setup man1.py to find Soft.SoftLib and import it there directly.
With that said, here's how I got it to work.
man1.py:
from Soft.SoftWork.manModules import *
# no change to import statement but need to add Soft to PYTHONPATH
def foo():
print("called foo in man1.py")
print("foo call module1 from manModules: " + module1())
man1test.py
# no need for "from ...MansTest.SoftLib import Soft" to facilitate importing..
from ...Mans import man1
man1.foo()
manModules.py
def module1():
return "module1 in manModules"
Terminal output:
$ python3 -m man.MansTest.Unittests.man1test
Traceback (most recent call last):
...
from ...Mans import man1
File "/temp/man/Mans/man1.py", line 2, in <module>
from Soft.SoftWork.manModules import *
ModuleNotFoundError: No module named 'Soft'
$ PYTHONPATH=$PYTHONPATH:/temp/man/MansTest/SoftLib
$ export PYTHONPATH
$ echo $PYTHONPATH
:/temp/man/MansTest/SoftLib
$ python3 -m man.MansTest.Unittests.man1test
called foo in man1.py
foo called module1 from manModules: module1 in manModules
As a suggestion, maybe re-think the purpose of those SoftLib files. Is it some sort of "bridge" between man1.py and man1test.py? The way your files are setup right now, I don't think it's going to work as you expect it to be. Also, it's a bit confusing for the code-under-test (man1.py) to be importing stuff from under the test folder (MansTest).
I had a similar problem, although not the same.
My folders and files had the structure (GUI_ML is the main folder):
GUI_ML
\ Views \ login.py
\ Views \ __ init __.py
\ Controllers \ Control_login.py
\ Controllers \ __ init __.py
I needed to import Control_login.py from login.py. The following code solved my problem:
import sys
import os
myDir = os.getcwd()
sys.path.append(myDir)
from pathlib import Path
path = Path(myDir)
a=str(path.parent.absolute())
sys.path.append(a)
from Controllers.Control_login import Control_login
For me when I created a file and saved it as python file, I was getting this error during importing.
I had to create a filename with the type ".py" , like filename.py and then save it as a python file.
post trying to import the file worked for me.
some package name and module name might be the same. this conflict is also responded with this error.
I was having a similar issue where I forgot to put a __init__.py in the module and spend a lot of time wasting trying to understand what's wrong.
Another solution depends on where you run this code from.
Assuming the OP's directory structure:
man/
Mans/
man1.py
MansTest/
SoftLib/
Soft/
SoftWork/
manModules.py
Unittests/
man1test.py
If you try running python Mans/man1.py (from the man directory), you would have to do the following two things for this to work:
Change the import line in man1.py to from ManTest.SoftLib.Soft.SoftWork.manModules import *
If not already there, add to your system environment variable. Key PYTHONPATH, value .

how to import nested module from nested module

Simple question, but could not find the answer.
I've following structure:
./lib1:
main.py
./lib2:
__init__.py utils.py
From the root diretory, I'm running:
python lib1/main.py
and in main.py I want to import lib2/utils.py.
adding import lib2/utils.py fails.
One solution I found is to add:
~/tmp/root$ cat lib1/main.py
import sys,os
sys.path.append(os.getcwd())
import lib2.utils
lib2.utils.foo()
which is good, but I wander if there is other solution. Thanks.
Are lib1 and lib2 separate modules? If yes, the comment by #BrenBarn applies: You need to add the top directory (containing lib1 and lib2 to the Python path (e.g using PYTHONPATH environment variable or appending to sys.path).
If both lib1 and lib2 are part of one module (i.e. there is a __init__.py file in the top directory) you can use relative imports (https://docs.python.org/2.5/whatsnew/pep-328.html).
Your problem is caused by using the wrong directory structure. The main.py script should be in the same top-level directory as the package that it needs to import. So the structure should look like this:
project /
lib2 /
__init__.py
utils.py
other.py
main.py
The directory of the main script will always be added to the start of sys.path, so this will guarantee that any packages in that directory can be always be directly imported, no matter where the script is executed from.
To import the utils module into main.py (or other.py), you should do:
from lib2 import utils

Import modules from subfolders

I have following arrangement of files:
python
|---- main.py
|---- files
|---- folder1
|---- a.py, a1.py, ...
|---- folder2
|---- b.py, b1.py, ...
I wanted to import my modules a.py and b.py to main.py. For this I used the following commands in main.py:
a = 'C:/python/files/folder1'
sys.path.insert(0, a)
from files.folder1 import *
However, I am unable to import modules from folder1 (similarly for folder2).
I get an error:
No module named files.folder1
I cannot use import command as there are many Python files in folder1, folder2, ...
What am I missing here?
Add a file __init__.py (can be blank) to folders files, folder1 and folder2. Then you got a package files with sub-packages folder1 and folder2. After this you can import from the main.py like this:
from files.folder1 import *
When I do this in Python 2.7 I use:
import sys
sys.path.append('C:/python/files/folder1')
import a
import a1
Here's a hack I built to import all modules in a directory into a dictionary:
import os
import sys
dir_of_interest = 'C:/python/files/folder1'
modules = {}
sys.path.append(dir_of_interest)
for module in os.listdir(dir_of_interest):
if '.py' in module and '.pyc' not in module:
current = module.replace('.py', '')
modules[current] = __import__(current)
I just built it and it's extremely hacky but it might be more like something you want. So, to access the module you want, instead of saying module_name.thing you would say modules["module_name"].thing
I cannot use import command as there are many Python files in folder1, folder2, ...
What am I missing here?
I believe the part you are missing is the __init__.py file in each of the folders. That file should include an __all__ variable that lists all the submodules that will imported by: from somepackage.subpackage import *.
This is all elegantly explained in the Python Tutorial section on Packages.
If you add folder1 to the path, that doesn't mean you can import folder1 as a module. It means you can import the files inside folder1. So you could do:
import a
import a1
If you want to have folder1 be a package of which a and a1 are modules, you need to put an __init__.py in folder1 and then do import folder1. If you further want to be able to do from folder1 import * and have that import a and a1, you need to put code in your __init__.py that imports a and a1.
If you have a lot of files in a folder that you want to be able to import in a structured way, you should make that folder into a package.
Looking at the folder structure , what you could do is , Simply
from files.folder1 import a , a1
from files.folder2 import b , b1
and this should help
.
Extras :
I recently thought of a problem , of importing pip packages without actually installing them ,
then what i did was ...
i pip installed the package in a virtual environment and copied only folder of the package name
eg. if the package name is qwikidata , then i went to /Lib folder and copied only the qwikidata folder and pasted it in the root of my project , in your case , where the main.py file is and pip uninstalled the package , to avoid the errors
And now i was able to import the package without actually pip installing it since the package was in my root folder of the project
If the project is not so complicated , then it should be fine , but I wouldn't recommend this way of installing packages .
It helps when you want to run your project on some other machine and You dont have an Internet connection .

Categories