0

I'm having trouble running pytest on my package. I have the following structure...

 tree -f
.
├── [   0 Jan  4 22:04]  ./__init__.py
├── [ 34K Jan 12 11:37]  ./LICENSE
├── [1.4K Jan  6 07:43]  ./README.md
├── [1.1K Jan 12 11:42]  ./setup.cfg
├── [  79 Jan  6 08:22]  ./setup.py
├── [4.0K Jan 12 11:49]  ./tcx2gpx
│   ├── [ 701 Jan  6 23:13]  ./tcx2gpx/__init__.py
│   ├── [4.0K Jan 12 12:13]  ./tcx2gpx/__pycache__
│   │   ├── [ 683 Jan 12 12:13]  ./tcx2gpx/__pycache__/__init__.cpython-36.pyc
│   │   └── [3.0K Jan  6 21:00]  ./tcx2gpx/__pycache__/tcx2gpx.cpython-36.pyc
│   └── [3.1K Jan 12 11:49]  ./tcx2gpx/tcx2gpx.py
├── [4.0K Jan  4 21:52]  ./tests
│   ├── [4.0K Jan  6 06:32]  ./tests/resources
│   │   ├── [288K Jan  6 21:07]  ./tests/resources/2019-10-20 12:51:21.0.gpx
│   │   └── [816K Jan  4 22:03]  ./tests/resources/2019-10-20 12:51:21.0.tcx
│   └── [4.0K Jan 12 12:24]  ./tests/tcx2gpx
│       ├── [ 386 Jan 12 12:17]  ./tests/tcx2gpx/conftest.py
│       ├── [   0 Jan 12 11:48]  ./tests/tcx2gpx/__init__.py
│       └── [1.3K Jan 12 12:24]  ./tests/tcx2gpx/test_tcx2gpx.py
└── [4.0K Jan  6 06:21]  ./tmp
    ├── [288K Jan  6 06:21]  ./tmp/2019-10-20 12:51:21.0.gpx
    └── [ 415 Jan  5 08:38]  ./tmp/test.py

And my conftest.py has the follwoing...

"""
Fixtures for test_tcx2gpx
"""
from pathlib import Path
import pytest

from tcx2gpx.tcx2gpx import TCX2GPX

TCX_DIR = Path(__file__).resolve().parents[1]
TCX_FILE = TCX_DIR / 'resources' / '2019-10-20 12:51:21.0.tcx'
GPX_FILE = TCX_DIR / 'resources' / '2019-10-20 12:51:21.0.gpx'


@pytest.fixture
def tcx_file():
    """
    Fixture of TCX file
    """
    return TCX2GPX(TCX_FILE)

On running pytest from the top-level I'm informed...

____________________________________________________ ERROR collecting test session ____________________________________________________
/home/neil/.virtualenvs/default/lib/python3.6/site-packages/_pytest/config/__init__.py:458: in _importconftest
    return self._conftestpath2mod[key]
E   KeyError: PosixPath('/mnt/work/python/tcx2gpx/tests/tcx2gpx/conftest.py')

During handling of the above exception, another exception occurred:
/home/neil/.virtualenvs/default/lib/python3.6/site-packages/_pytest/config/__init__.py:464: in _importconftest
    mod = conftestpath.pyimport()
/home/neil/.virtualenvs/default/lib/python3.6/site-packages/py/_path/local.py:701: in pyimport
    __import__(modname)
/home/neil/.virtualenvs/default/lib/python3.6/site-packages/_pytest/assertion/rewrite.py:143: in exec_module
    exec(co, module.__dict__)
tests/tcx2gpx/conftest.py:7: in <module>
    from tcx2gpx.tcx2gpx import TCX2GPX
E   ModuleNotFoundError: No module named 'tcx2gpx.tcx2gpx'

Reading around I found a few threads on this (e.g. here) and because I'm working on CI on GitLab I decided to try modifying the PYTHONPATH (as I can put these as part of the script that is executed on GitLab CI execution)...

export PYTHONPATH="$PYTHONPATH:."
python -c "import sys;print(sys.path)"
['', '/mnt/work/python/tcx2gpx', '/home/neil/.virtualenvs/default/lib64/python
36.zip', '/home/neil/.virtualenvs/default/lib64/python3.6', '/home/neil/.virtualenvs/default/lib64/python3.6/lib
-dynload', '/usr/lib64/python3.6', '/usr/lib/python3.6', '/home/neil/.virtualenvs/default/lib/python3.6/site-pac
kages', '/mnt/work/python/python-tcxparser']
pytest

But I get the same error, even though /mnt/work/python/tcx2gpx where the above directory structure is located, is in the PYTHONPATH.

I have also tried using python -m pytest because, as stated here doing so should automatically include the current directory in syspath. I get the same result though, ModuleNotFoundError.

I also found this article which describes conflicts between a system installed pytest and that within a virtual environment, but firstly I can not uninstall it at the system level because its a required dependency of other packages I have installed in the system, and secondly I get the same error when trying to run the tests in GitLab CI where I don't think there is any other version of pytest installed (I have to explicitly install it as part of the testing stage).

Really stumped on why this isn't working any suggestions or pointers would be very much appreciated.

slackline
  • 2,295
  • 4
  • 28
  • 43

1 Answers1

0

you shouldn't have an __init__.py file at the top of your project -- this is causing pytest to assume that the parent directory is the root of your project

deleting that fixes it for me

(disclaimer: I'm a pytest core dev)

anthony sottile
  • 61,815
  • 15
  • 148
  • 207
  • Also incorrect import statement `from tcx2gpx.tcx2gpx import TCX2GPX ` needs to be changed. – wim Jan 12 '20 at 16:32
  • @wim from the filestructure that looks fine, there's `tcx2gpx/tcx2gpx.py` (it's a little confusing because OP used `tree -f` instead of normal `tree`) – anthony sottile Jan 12 '20 at 17:29
  • Ah, you're right. My bad. Seems like one-too-many levels of namespaces than necessary though. And a `tcx2gpx` package under tests is confusing things more. – wim Jan 12 '20 at 17:34
  • Thanks, I removed the top level `__init__.py` but that didn't make any difference. Removing the `__init__.py` that was within the `tests/tcx2gpx` directory and running `python -m "pytest"` solved it. Thanks for the pointer. I'm still confused about the need for `__init__.py` as I thought it was a [hangover from Python <3.3*](https://stackoverflow.com/a/448279/1444043) but perhaps I don't have namespaces working properly, something to read up on! – slackline Jan 12 '20 at 19:09
  • Annoyingly removing `__init__.py` from the test folder introduces a `F0010` on linting but I can work on eliminating that. – slackline Jan 12 '20 at 19:23
  • yeah they are optional, however pytest still uses them to figure out project roots -- if you add `__init__.py` all the way up your tree (not at the root) that'll solve that too -- another option is to move your tests outside of your package and then you only need `tests/__init__.py` – anthony sottile Jan 12 '20 at 20:35