How to properly import modules in Python with __init__.py - python-3.x

I have a folder structure like
app
├── modules
│ └── __init__.py
| └── helper.py
|
├── tests
| └── __init__.py
| └── unittest.py
|
__init__.py
In the unittest.py I have a module imported like
from modules import helper
helper.do_something()
Unfortunately if I run unittest.py I get ImportError: cannot import name 'helper' from 'modules' (unknown location). I'd appreciate a hint.

I have a similar project structure (main module folder containing source code folder as well as tests folder) and this is how imports are used in my tests:
from app.modules import helper
You could also use relative imports:
from ..modules import helper
It really depends on your needs and tastes.

Related

Unable to import flask app folder in unittest folder of an repo

I am facing issues in writing unit test for my flask app. Exact issue is that test files in unit-test directory is not able to import files from app folder.
My directory structure:
.
├── Dockerfile
├── README.md
├── app
│ ├── __init__.py
│ ├── api.py
│ └── wsgi.py
├── docker
│ ├── docker-compose.yml
│ └── start.sh
├── requirements.txt
└── unit-test
├── __init__.py
└── test_api.py
Code in unit-test/test_api.py:
import unittest
from app import api
Absolute import throws this error:
from app import api
ModuleNotFoundError: No module named 'app'
I have tried the following after checking a few resources of absolute and relative imports, none of them worked.
from .. import app
error:
from .. import app
ImportError: attempted relative import with no known parent package
I checked a few questions on SO and someone recommended having _init_.py file in the unit-test folder as well but I already have a blank init.py file there.
I have reviewed numerous blogs and youtube tutorials and absolute imports work for them easily.
Please advise how to fix this error and run unit tests.
import sys
sys.path.append('/path/to/the/required/folder')
import name_of_file
if not an inbuilt package, Python only searches in the current directory when you try to import, thus we have to add this path, so that it looks inside this particular folder as well. After adding that, you can simply do the import.

ModuleNotFoundError when trying to import from a sub package in python

I have the following layout:
└── folder_1
└── __init__.py
└── level_1.py
└── folder_2
└── __init__.py
└── level_2.py
└── test
└── __init__.py
└── test_in.py
└── test_out.py
└── setup.py
And in my setup.py I specify packages=["folder_1", "test"]
In the test_out.py file I can import from level_1.py and level_2.py with no problem, but for some reason in the test_in.py file I can only import from level_1.py. If I try to import from level_2.py I get the error
ModuleNotFoundError: No module named 'folder_1.folder_2'
I also get errors if I try to do the import in the init.py from folder_1.
I'm running this on a jupyter lab and can't find a way to make this work. Is there a way to fix this without using the PYTHONPATH or things like that?
EDIT:
Just found out that if I add folder_1.folder_2 to the content of packages in setup.py it works, however I'm not sure if this is the correct way to fix this?

File hierarchy and local imports

I'm trying to figure out file hierarchy and local imports in python3. I've run into a problem with a file structure below:
└── project
├── run.py
└── scripts
├── __init__.py
├── misc.py
├── script1.py
└── script2.py
I use relative imports for all files in the "scripts" directory.
from misc import x, y, z
I use absolute imports in run.py.
from scripts.misc import a, b, c
from scripts.script1 import more_stuff
My goal is to have the python files independent and fully functional. However, when I attempt to execute run.py, I encounter an error.
from misc import x, y, z
ModuleNotFoundError: No module named 'misc'
I would expect relative paths to be relative to the original file and not adopt the path of the executed file. Can I fix this by modifying the imports or file structure?
It also appears I don't understand how __init__.py works. I want to re-use generic package names (like "scripts"). I had assumed that __init__.py files would be read immediately downstream relative to the executed file: if run.py is executed, only the scripts directory at the same level should be considered. I have found that a distant (unrelated?) "scripts" directory receives priority. Is this something that can be addressed with more careful absolute paths? Example below.
└── dir
└── project1
| ├── run.py
| └── scripts
| ├── __init__.py
| └── settings.py
└── subdir
└── project2
├── run.py
└── scripts
├── __init__.py
└── settings.py
Executing run.py from "project1" will attempt to import the "scripts" directory from project2.
cannot import name 'variable' from 'scripts.settings' (/Users/.../dir/subdir/project2/scripts/settings.py)
Removing __init__.py from project2/scripts no longer produces the error when executing run.py from "project1".
You are saying:
I use relative imports for all files in the "scripts" directory.
from misc import x, y, z
But this is not relative. For relative you need to have
from .misc import x, y, z
To understand why the unrelated scripts is taking precedence, look on your sys.path and verify if indeed it comes before your scripts package. I can assume the is some leftover for ide path manipulation.

problems importing sub packages in python: how should I write the __init__.py files

I am new to building packages so bear with me. I am having a problem importing the subpackages of my latest python project.
My directory structure is the following:
├── package
│   ├── __init__.py
│   ├── subpackage_a
│   │   ├── __init__.py
│   │   └── functions_a.py
│   └── subpackage_b
│   ├── __init__.py
│   └── functions_b.py
└── setup.py
The files look as follows
setup.py
:
from setuptools import setup
setup(name='test_package',
version='0.3',
description='',
author='me',
packages=['package']
)
package/__init__.py: empty.
subpackage_a/__init__.py: from .functions_a import *
subpackage_b/__init__.py: from .functions_b import *
functions_a.py
contains
def hello_world_a():
print('hello its a')
and functions_b.py contains
def hello_world_b():
print('hello its b')
Now I open a virtualenv go to the setup.py's directory and I pip install .. I was expecting to access the functions contained in the subpackages a and b. But when I try to import the functions I get a module not found error.
from package.subpackage_a import hello_world_a
ModuleNotFoundError: No module named 'package.subpackage_a'
and the same thing holds for subpackage_b. But if I import package this is recognised. I have a feeling that this approach used to work, as I have some old packages written this way which don't work any longer.
Perhaps I have to change my init.py files ? What am I doing wrong ?
setuptools.setup doesn't know that subpackage_a and subpackage_b exist. You only specified the top-level package. So it won't include these subpackages in the installation. Instead you should also specify them:
setup(
...,
packages=['package', 'subpackage_a', 'subpackage_b']
)
This process can be automatized via find_packages():
from setuptools import find_packages
setup(
...,
packages=find_packages()
)

Jupyter ImportError: cannot import name

I have the following project structure:
path_to_dir/
│
├── a_notebook.ipynb
└── testCases_v2.py
In the .py file I have defined several functions.
I'm trying to import them in the notebook like this:
from testCases_v2 import layer_sizes_test_case
However, I am getting:
ImportError: cannot import name 'layer_sizes_test_case' from 'testCases_v2' (/path_to_dir/testCases_v2.py)
I even tried adding the directory to the system path:
import os
import sys
module_path = os.path.abspath(os.path.join('path_to_dir'))
if module_path not in sys.path:
sys.path.append(module_path)
But the problem persists.
How to solve it? (And, yes, I checked that the name of the function I am importing is spelled correctly)
Let's say you have this:
path_to_dir/
│
├── a_notebook.ipynb
└── tests
|
└── testCases_v2.py
And in testCases_v2 you have a class with the same name.
You have to manually import the modules you want Jupyter take into
account in sys.path In this case, the module is 'tests' and the path
you have to include is 'path_to_dir'
import sys
sys.path.insert(0, 'path/to/dir')
In the module where your py files are, add an empty __init__.py
path_to_dir/
│
├── a_notebook.ipynb
└── tests
|
├──testCases_v2.py
└── __init__.py
You should be able to import it now by doing:
from tests.testCases_v2 import testCases_v2
The python doc about modules might come in handy

Resources