Pytest fails with relative imports - python-3.x

I have the following project structure in Pycharm -
project/
src/
main.py
config/
__init__.py
settings.py
package1/
__init__.py
client.py # Imports settings from config using -> from ..config import settings
tests/
__init__.py
test.py
So here my client.py imports settings -
from ..config import settings
main.py imports client -
from package1.client import clientFunction # ClientFunction is the method defined inside client.py
I use pytest to run the tests. So now when i run the pytest configuration, in my test cases i import main. I dont see any errors in my code but when the tests run it says -
from ..config import settings
E ValueError: attempted relative import beyond top-level package
How can i fix this? Seems like pytest is taking a different path to execute the tests and hence the relative imports are going beyond the top level.

Related

How to import from a renamed submodule?

My project requires patching of another project's code. Seems simple enough:
project/
__init__.py
from .patched_project import fixed_project
my_project.py
patched_project.py
from .my_project import useful_function
import other_project as fixed_project
# use useful_function with fixed_project
In theory, I can now install this package and the fixed_project can be imported via from project import fixed_project (which works without issue).
However, user's have become accustom to performing from other_project import submodule in all their other projects. As such, they would expect to now use from project.fixed_project import submodule. But this results in ModuleNotFoundError. Why? Does python not run the __init__.py and see fixed_project? A solution like:
from project import fixed_project
submodule = fixed_project.submodule
works, but feels unpythonic. Normally, if one can do the above, I would expect that from project.fixed_project import submodule should work. What am I misunderstanding? Is it expected that __init__.py breaks submodule importing of renamed modules with __init__.py? Is there something that I was suppose to add to the __init__.py so that subpackage, subsubpackage, and subsubsubpackage importing could be performed?

pytest import a class from a parent directory result in a ValueError

I have my project directory like thisone:
README.md
athomcore.py
test
|_unit
|_test_one.py
|___init__.py
for my testing purposes i have to import a class into athomcore.py file and i do:
import pytest
import sys
sys.path.append("...")
from ...athomcore import StatusDevice
def test_initial_status():
mydev = StatusDevice(True)
assert mydev.status == True
but when i run pytest in my terminal i get:
ERROR test/unit/test_one.py - ValueError: attempted relative import beyond top-level package
How can i import class modules from my project for testing it?
so many thanks in advance
Couple of things wrong here. First off you should try to avoid using sys.path.append whenever possible. Secondly the path ... is not valid, perhaps you mean ..? In any case it is not needed here. If you run the tests from the root of the repository no path manipulation is needed. I replicated your repository structure and have the following set up.
├── athomcore.py
└── tests
├── __init__.py
└── unit
├── __init__.py
└── test_one.py
From the root of the repository, i.e the top level of the directory I run pytest /tests and the tests pass and run as expected for me.
================================== test session starts ===================================
platform darwin -- Python 3.9.1, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
rootdir: ***/stackoverflow
collected 1 item
tests/unit/test_one.py . [100%]
=================================== 1 passed in 0.03s ====================================
You can read more here about how pytest works with your path to set up tests.

Relative imports in python and pycharm

I have following project structure and i'm using PyCharm.
Project/
subproject1/
main.py
modules/
1.py
__init__.py
subproject2/
main.py
modules/
subproject3/
__init__.py
file.py
I need in Project/subproject/modules/1.py a class from Project/subproject3/file.py. I tried it with from ...subproject3.file import class1, but then i get the error ValueError: attempted relative import beyond top-level package. Next i tried the import from subproject3.file import class1, and that work's, but i don't know why. My working directory in PyCharm is in Project/ but i tried to create a Python application with pyinstaller and that worked also for me and a received no error message. Why does my file 1.py knows from subproject3 and i can import it that way?
Thank you!!

Visual Studio Code Unit Tests Environment

I have the following working directory with my source and tests folders as illustrated
root_folder:
tower_shell
init
read_files
files_processing
tests
init
test_read_json.py
I want to run the unit test test_read_json.py from my folder tests which need the following imports:
import unittest
import os
import sys
from tower_shell.read_files import read_json
from pathlib import Path
The problem is that the file read_files (contained in tower_shell) folder is also importing a module from tower_shell called files_processing: \
from files_processing import process_hub_sheet, process_tower_sheet
Since my working directory is one level up, it raises an error stating that the module can not be imported.
I tried to add PYTHONPATH variable but the test discovers is not functioning then.
Thanks

Importing custom module cleanly

I would like to import a class from my submodule without having to use the from submodule.submodule import Class syntax. Instead I would just like to do from submodule import Class like a normal Python3 module.
I feel this should have been answered a million times, and while there are several similarly named questions on SO, none of them provide a clear, simple solution with a bare-bones example.
I'm trying to get the simplest test working with this setup:
.
├── main.py
└── test
├── __init__.py
└── test.py
In my test module, I have the following contents:
test.py
class Test:
def __init__(self):
print('hello')
__init__.py
from test import Test
__all__ = ['Test']
In the upper-level main.py I have the following:
from test import Test
Test()
When I try to run main.py I get:
ImportError: cannot import name 'Test'
I know I could replace the import statement in main.py with from test.test import Test, but my understanding was that one of the points of __init__.py was to make submodules accessible at the package level (with __all__ allowing to import all with from test import *)
According to PEP 404:
In Python 3, implicit relative imports within packages are no longer
available - only absolute imports and explicit relative imports are
supported. In addition, star imports (e.g. from x import *) are only
permitted in module level code.
If you change __init__.py to:
from test.test import Test
__all__ = ['Test']
then your code works:
$ python3 main.py
hello
But now it works only on python3 (and your original code works only on python2).
To have code that works on both lines of python, we have to use explicit relative import:
from .test import Test
__all__ = ['Test']
Code execution:
$ python2 main.py
hello
$ python3 main.py
hello

Resources