Using custom module import error on python3 version - python

I've created a custom module called config which have the following structure:
config/
__init__.py
config.py
util.py
Each file is defined like:
config.py
CONTROL_VAR = "A"
util.py
from config import CONTROL_VAR
if CONTROL_VAR == "A":
VAR_ONE = "A1"
else:
VAR_ONE = "B1"
I've setup my workspace like the following:
workspace_folder
config/
my_script.py
In order tu run my script I invoke it directly by running:
python my_script.py
my_script.py has the following code:
from config.config import CONTROL_VAR
from config.util import VAR_ONE
if __name__ == "__main__":
print (CONTROL_VAR)
print (VAR_ONE)
I am able to run the code with python 2.7 but not with 3.8, at first I thought i was having a circular dependency issue but now it seems like I have something wrong with my import syntax.
Can I make this work for both python2 and python3?

When you perform from config import CONTROL_VAR inside config/util.py that module (util.py) doesn't know that it's located inside the config package and hence the resolution will start from my_script.py's directory. That means even the import happens inside a module which is located inside config, it attempts to resolve that import from the perspective outside of config.
In order to change that behavior, you can prefix config with a . which tells Python that the config.py module is expected to be in the same directory as the util.py module:
from .config import CONTROL_VAR
The from .foo import bar and from ..foo import bar syntax instructs Python so resolve imports relative to the importing module. A plain from foo import bar on the other hand resolves foo as a "global" module (i.e. not relative to anything).

Related

ModuleNotFoundError: Even with __init__.py file

I have 3 python file :
test.py
modules(folder) and in modules there 3 to files : module1.py module2.py init.py
test.py
./test.py
./modules
./modules/module1.py
./modules/module2.py
./modules/__init__.py
module1.py:
from module2 import temp
def print_temp():
print(temp)
if __name__=='__main__':
print_temp()
module2.py
temp =1
test.py
from modules.module1 import print_temp
print_temp()
When I run python test.py I got ModuleNotFoundError: No module named 'module2'
How can I fix that please?
When you import a module in Python, it searches the PYTHONPATH for a module / package with that name. But it doesn't search inside directories so you have to specify.
If you want to be able to run modules.module1 directly (as well as import it) then you must use the full path:
from modules.module2 import temp
But if you just want to be able to import the module and not run it directly it is better to use a relative import as it will still work even if the name of the package is changed:
from .module2 import temp

Understanding how Python imports modules from a subdirectory while using VS-Code

Consider the following directory structure with the following contents:
my-project
├── main.py
├── lib
│ ├── __init__.py
│ ├── foo.py
│ └── bar.py
main.py
import sys
sys.path.append("./lib")
from foo import hello_world
if __name__ == "__main__":
hello_world()
foo.py
from lib.bar import name
def hello_world():
print(f"Hello {name}")
if __name__ == "__main__":
hello_world()
bar.py
name = "Grogu"
When I run main.py, I run into no errors and I get what I expect: Hello Grogu. However, when I run lib/foo.py, I get an error:
Traceback (most recent call last):
File "my-project/lib/foo.py", line 1, in <module>
from lib.bar import name
ModuleNotFoundError: No module named 'lib'
If I change lib.bar into bar, it works as expected, but I don't understand why VSCode doesn't seem to know what the lib folder is.
I'm using VSCode and I think there's something I'm doing wrong. My friend who uses pyCharm is able to run lib/foo.py just fine. It might have to be how VSCode and Pycharm interpret the source. Does anyone have any tips?
Basically I'm trying to import functions from a subdirectory and also preserve the ability to run individual files within the subdirectory, but I can't seem to find the proper way to do this in VScode.
When you execute a Python script, the specific directory where the script is located is added to the path, but not its parent's directory.
So, when you run python foo.py from inside lib the path will contain .../my-project/lib but not .../my-project, and therefore Python cannot find the module lib. However, it works with bar because the file does exist in .../my-project/lib.
To be able to run from both the root dir and lib, you can insert/append the parent directory (i.e. the root dir) to the path in the lib __init__.py:
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
Then, change main.py:
from lib.foo import hello_world
if __name__ == "__main__":
hello_world()
And foo.py:
from bar import name
def hello_world():
print(f"Hello {name}")
if __name__ == "__main__":
hello_world()
Just import bar directly:
foo and bar are both the modules that at the same level, there's no need to back to lib, then to search bar. We can directly run from bar import name.
More detailed information please refer to Python Docs - The import System

How to run a Python code inside a custom package?

I'm using Visual Studio Code.
Suppose my folder looks like:
├── main.py
└── package
├──__init__.py
├──utils.py
└──method.py
In my method.py, I import the utils.py, which is in the same directory, so I put the dot before the name:
from .utils import *
then I can run the script in main.py like:
from package import method
This will work. But the question is, how I can run the script in method.py at its directory instead of importing it in main.py? If I run the script method.py directly, an error will occur:
ModuleNotFoundError: No module named '__main__.modules'; '__main__' is not a package
What can I do to run the script in method.py without removing the dot as from utils import *?
To make your code work, change the import statement in method.py from
from .utils import *
to
import __main__, os
if os.path.dirname(__main__.__file__) == os.path.dirname(__file__):
# executed script in this folder
from utils import *
else:
# executed script from elsewhere
from .utils import *
When method.py runs, it checks the folder that the executed python script is in, and if it's the same folder as itself, it will import utils, rather than .utils.
You can achieve a similar thing using
if __name__=='__main__':
as your check. However, if method.py is imported by anther file inside the package folder, then method.py will try to import .utils, and won't be able to find it.

Relative import in Python 3.6

I want to use relative import in Python 3.
My project:
main_folder
- __init__.py
- run.py
- tools.py
I want to have in run.py (MyClass declared in __init__.py):
from . import MyClass
And in run.py:
from .tools import my_func
An ImportError is raise.
Alternatively, with absolute import, debugging in PyCharm does not work and the library takes from installed packages, not my directory.
I know one way, but it is terrible:
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
How to use this import in my project?
When you use PyCharm, it automatically makes the current module main, so relative statements like from . import <module> will not work. read more here.
to fix your problem, put the __init__.py and tools.py files in a sub-directory
main_directory/
run.py
sub_directory/
__init__.py
tools.py
in your run.py file, write the following as your import statements
from sub_directory import tools
from sub_directory.__init__ import MyClass
Edit: as #9000 mentioned, you can write from sub_directory import MyClass and achieve the same thing.

Python unittest failing to resolve import statements

I have a file structure that looks like the following
project
src
__init__.py
main.py
module.py
secondary.py
test
test_module.py
module.py
import secondary
x = False
secondary.py
pass
test_module.py
from unittest import TestCase
from src import module
class ModuleTest(TestCase):
def test_module(self):
self.assertTrue(module.x)
Invoking python3 -m unittest discover in /project/ gives an error:
File "/Users/Me/Code/project/test/test_module.py", line 6, in <module>
from src import module
File "/Users/Me/Code/project/src/module.py", line 1, in <module>
import secondary
ImportError: No module named 'secondary'
What can I do so that secondary.py is imported without error?
In Python 3 (and Python 2 with from __future__ import absolute_import), you must be explicit about what module you want when importing another module from the same package. The syntax you're using in module.py (import secondary) only works if secondary is a top-level module in a folder in the Python module search path.
To explicitly request a relative import from your own package, use from . import secondary instead. Or, make an absolute import, using the name of the package as well as the module (from src import secondary, or import src.secondary and use src.secondary elsewhere the module instead of just secondary).
Try adding this to the top of the test file
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
Note: Depending on the project structure we have to specify the root folder

Categories