Hi I am getting import errors for a very basic pro...
# general
c
Hi I am getting import errors for a very basic project. Feels like I am making a silly mistake. here are the logs
Copy code
➜ ./pants roots                                                     
src/python
test/python

➜ ./pants filedeps --transitive test/python/tunein/test_samplelib.py 
src/python/tunein/BUILD
src/python/tunein/samplelib.py
test/python/tunein/BUILD
test/python/tunein/test_samplelib.py

➜ ./pants test test/python/tunein/test_samplelib.py
00:07:33.40 [INFO] Initializing scheduler...
00:07:33.63 [INFO] Scheduler initialized.
00:07:35.62 [ERROR] Completed: Run Pytest - test/python/tunein/test_samplelib.py:tests failed (exit code 2).
============================= test session starts ==============================
platform darwin -- Python 3.7.10, pytest-7.0.1, pluggy-1.0.0
rootdir: /private/var/folders/0t/dmh8ynt13pbc2y2stvb0by6c0000gn/T/process-execution34eEWG
plugins: cov-3.0.0
collected 0 items / 1 error

==================================== ERRORS ====================================
____________ ERROR collecting test/python/tunein/test_samplelib.py _____________
ImportError while importing test module '/private/var/folders/0t/dmh8ynt13pbc2y2stvb0by6c0000gn/T/process-execution34eEWG/test/python/tunein/test_samplelib.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/Users/vishwakarma/.pyenv/versions/3.7.10/lib/python3.7/importlib/__init__.py:127: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
test/python/tunein/test_samplelib.py:1: in <module>
    from tunein.samplelib import sample_func
E   ModuleNotFoundError: No module named 'tunein.samplelib'
- generated xml file: /private/var/folders/0t/dmh8ynt13pbc2y2stvb0by6c0000gn/T/process-execution34eEWG/test.python.tunein.test_samplelib.py.tests.xml -
=========================== short test summary info ============================
ERROR test/python/tunein/test_samplelib.py
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
=============================== 1 error in 0.11s ===============================
r
If one of your source roots is
test/python
, then inside
test/python
, your import shouldn’t start with
test.python
~
https://www.pantsbuild.org/docs/source-roots Never mind, I read it wrongly. You are using correct import statement
Can you share your BUILD files please?
I also think you are missing
___init___.py
e
I think the opposite actually. @crooked-country-1937 I'm willing to bet you have something like this:
Copy code
$ tree src/ test/
src/
└── python
    └── tunein
        ├── BUILD
        ├── __init__.py
        └── samplelib.py
test/
└── python
    └── tunein
        ├── BUILD
        ├── __init__.py
        └── test_samplelib.py

2 directories, 3 files
If so, you have a problem beyond Pants:
Copy code
$ python -mvenv pytest.venv
$ pytest.venv/bin/pip -q install -U pip
$ pytest.venv/bin/pip -q install pytest
$ PYTHONPATH=src/python:tests/python pytest.venv/bin/pytest test/python/tunein/test_samplelib.py 
============================================================================================================================== test session starts ==============================================================================================================================
platform linux -- Python 3.10.5, pytest-7.1.2, pluggy-1.0.0
rootdir: /tmp/test
collected 0 items / 1 error                                                                                                                                                                                                                                                     

==================================================================================================================================== ERRORS =====================================================================================================================================
_____________________________________________________________________________________________________________ ERROR collecting test/python/tunein/test_samplelib.py _____________________________________________________________________________________________________________
ImportError while importing test module '/tmp/test/test/python/tunein/test_samplelib.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/lib/python3.10/importlib/__init__.py:126: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
test/python/tunein/test_samplelib.py:1: in <module>
    from tunein import samplelib
E   ImportError: cannot import name 'samplelib' from 'tunein' (/tmp/test/test/python/tunein/__init__.py)
============================================================================================================================ short test summary info ============================================================================================================================
ERROR test/python/tunein/test_samplelib.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
=============================================================================================================================== 1 error in 0.03s ================================================================================================================================
If you delete your
__init__.py
though, all good:
Copy code
$ find src/ test/ -name __init__.py -delete
$ PYTHONPATH=src/python:tests/python pytest.venv/bin/pytest test/python/tunein/test_samplelib.py 
============================================================================================================================== test session starts ==============================================================================================================================
platform linux -- Python 3.10.5, pytest-7.1.2, pluggy-1.0.0
rootdir: /tmp/test
collected 1 item                                                                                                                                                                                                                                                                

test/python/tunein/test_samplelib.py .                                                                                                                                                                                                                                    [100%]

=============================================================================================================================== 1 passed in 0.00s ===============================================================================================================================
And so is Pants:
Copy code
$ rm -rf pytest.venv/
$ ./pants test test/python/tunein/test_samplelib.py
04:31:53.18 [INFO] Completed: Run Pytest - test/python/tunein/test_samplelib.py:tests succeeded.

✓ test/python/tunein/test_samplelib.py:tests succeeded in 0.14s.
Which is all to say, namespace packages are a thing and they are confusing. See here for more information on them in all their historical forms: https://packaging.python.org/en/latest/guides/packaging-namespace-packages/#creating-a-namespace-package
c
@enough-analyst-54434 Thanks! removing the
_init_.py
got it working. I think I added that when I put
conftest.py
in there.
(Still don’t understand why it was an issue though 😅)
e
You really should read the full page I linked. This is an important Python gotcha to master. Until Python 3.3 / PEP-420 you had to use an
__init__.py
to create a package. When doing so, you cannot* split the package across multiple
sys.path
entries (you were doing this, the
tunein
package lived both in ,
src/python/tunein
and
test/python/tunein
) *You actually can split a package across multiple
sys.path
entries while using an
__init__.py
but it is non-trivial! All such
__init__.py
must be identical and they must contain a special incantation to let Python importing know to look in multiple paths. There is this style incantataion: https://packaging.python.org/en/latest/guides/packaging-namespace-packages/#pkgutil-style-namespace-packages And this one: https://packaging.python.org/en/latest/guides/packaging-namespace-packages/#pkg-resources-style-namespace-packages It's just alot easier to use Python 3.3+ implicit namespace packages which means drop the
__init__.py
.
👍 1