bug or feature request: dealing with non-unique root for architecture
I have a strange behavior when using pytestarch on one of my projects, which is partly due of its unusual code layout, so I wanted to show it to you so that you can decide if is a bug or not, and if it should be fixed or not.
Given this file structure :
.
├── src
│ ├── package1
│ │ ├── __init__.py
│ │ └── module1.py
│ └── package2
│ ├── __init__.py
│ └── module2.py
└── tests
└── test_arch.py
and my modules contents :
# file: module1.py
import sys
from package2 import module2
if __name__ == "__main__":
print(sys.path)
module2.hello_world()
and
# file: module2.py
def hello_world():
print("hello world")
I can run the code fine with :
$ PYTHONPATH=src uvx python -m package1.module1
['/workspace/pytestarch_multiple_packages', '/workspace/pytestarch_multiple_packages/src', .....................]
hello world
Because I'm running python in python -m mode, it appends the current dir instead of the script dir in the PYTHONPATH. And before that, I have already added the src dir (sources root).
So for me, everything works fine (although forcing the PYTHONPATH in such a way is not recommended IMO).
But then comes pytestarch :
# file: test_arch.py
from pprint import pprint
from pathlib import Path
import pytestarch
ROOT_DIR = Path(__file__).parent.parent # pytestarch_multiple_packages/
SRC_DIR = ROOT_DIR / "src"
arch = pytestarch.get_evaluable_architecture(
root_path=str(SRC_DIR),
module_path=str(SRC_DIR),
# exclude_external_libraries=False,
)
pprint(sorted(arch.modules))
And when I run it :
$ uvx --with pytestarch python tests/test_arch.py
['src',
'src.package1',
'src.package1.__init__',
'src.package1.module1',
'src.package2',
'src.package2.__init__',
'src.package2.module2']
Here, all of my packages are prefixed by src.. It is my first problem. I was (wrongly ?) expecting them without the src module prefix, like so :
-['src',
+[
- 'src.package1',
+ 'package1',
- 'src.package1.__init__',
+ 'package1.__init__',
- 'src.package1.module1',
+ 'package1.module1',
- 'src.package2',
+ 'package2',
- 'src.package2.__init__',
+ 'package2.__init__',
- 'src.package2.module2']
+ 'package2.module2']
My second problem comes when I add the exclude_external_libraries=False, then I get :
['package2',
'src',
'src.__init__',
'src.package1',
'src.package1.__init__',
'src.package1.module1',
'src.package2',
'src.package2.__init__',
'src.package2.module2',
'sys']
The sys was expected, but not that there is now a package2, which is sort-of a duplicate but without the src prefix.
So I don't know what exactly I'm doing wrong. I'm not sure to really understand what the distinction is between root_path and module_path, and how it relates to the Python import system (which I know well).
Is this library intended to work only for repositories where the code is all located in a single top-level package ? It seems like it.
If I create a single top-level package, put the 2 packages inside it :
.
├── src
│ └── toplevel_package
│ ├── __init__.py
│ ├── package1
│ │ ├── ...
│ └── package2
│ ├── ...
# file: module1.py
-from package2 import module2
+from toplevel_package.package2 import module2
# file: test_arch.py
-ROOT_DIR = Path(__file__).parent.parent
-SRC_DIR = ROOT_DIR / "src"
+SRC_DIR = Path(__file__).parent.parent / "src"
+TOPLEVEL_PACKAGE_DIR = SRC_DIR / "toplevel_package"
arch = pytestarch.get_evaluable_architecture(
- root_path=str(SRC_DIR),
- module_path=str(SRC_DIR),
+ root_path=str(TOPLEVEL_PACKAGE_DIR),
+ module_path=str(TOPLEVEL_PACKAGE_DIR),
Then all is working fine :
-
$ PYTHONPATH=src uvx python -m toplevel_package.package1.module1lists the correctsys.paths and its import works -
uvx --with pytestarch python tests/test_arch.pygives the expected modules.