Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change pytest rootdir

Tags:

import

pytest

I am stuck with this incredibly silly error. I am trying to run pytest on a Raspberry Pi using bluepy.

pi@pi:~/bluepy/bluepy $ pytest test_asdf.py
============================= test session starts       ==============================
platform linux2 -- Python 2.7.9, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: /home/pi/bluepy, inifile:
collected 0 items / 1 errors

==================================== ERRORS ====================================
 ______________ ERROR collecting bluepy/test_bluetoothutility.py _______________
ImportError while importing test module '/home/pi/bluepy/bluepy/test_asdf.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
test_asdf:4: in <module>
    from asdf import AsDf
asdf.py:2: in <module>
    from bluepy.btle import *
E       ImportError: No module named btle
!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!
=========================== 1 error in 0.65 seconds ============================

I realised that my problem could be that rootdir is showing incorrect path. It should be

/home/pi/bluepy/bluepy

I've been reading pytest docs but I just do not get it how to change the rootdir.

like image 905
Gabriele Avatar asked Mar 24 '17 09:03

Gabriele


2 Answers

Your problem is nothing to do with Pytest's rootdir.

The rootdir in Pytest has no connection to how test package names are constructed and rootdir is not added to sys.path, as you can see from the problem you were experiencing. (Beware: the directory that is considered rootdir may be added to the path for other reasons, such as it also being the current working directory when you run python -m pytest.)

The problem here, as others have described, is that the top-level bluepy/ is not in sys.path. The easiest way to handle this if you just want to get something running interactively for yourself is as per Cecil Curry's answer: cd to the top-level bluepy and run Pytest as python -m pytest bluepy/test_asdf.py (or just python -m pytest if you want it to discover all test_* files in or under the current directory and run them). But I think you will need to use python -m pytest, not just pytest, in order to make sure that the current working directory is in the path.

If you're looking to set up a test framework that others can easily run without mysterious failures like this, you'll want to set up a test script that sets the current working directory or PYTHONPATH or whatever appropriately. Or use tox. Or just make this a Python package using standard tools that can run the tests for you. (All that goes way beyond the scope of this question.)

By the way, I concur with Cecil's opinion of Mackie Messer's answer; messing around with conftest.py like that is overly difficult and fragile; there are better solutions for almost any circumstance.

Appendix: Use of rootdir

There are only two things, as far as I'm aware, for which rootdir is used:

  1. The .pytest_cache/ directory is stored in the rootdir unless otherwise specified (with the cache_dir configuration option).
  2. If rootdir contains a conftest.py, it will always be loaded, even if no test files are loaded from in or under the rootdir.

The documentation claims that the rootdir also used to generate nodeids, but adding a conftest.py containing

def pytest_runtest_logstart(nodeid, location):
    print("logstart nodeid={} location={}".format(nodeid, location))            

and running pytest --rootdir=/somewhere/way/outside/the/tree shows that to be incorrect (though node locations are relative to the rootdir).

like image 60
cjs Avatar answered Sep 17 '22 12:09

cjs


Actually, py.test is correctly discovering the rootdir for your project to be /home/pi/bluepy. That's good.

Tragically, you are erroneously attempting to run py.test within your project's package subdirectory (i.e., /home/pi/bluepy/bluepy) rather than within your project's rootdir (i.e., /home/pi/bluepy). That's bad.

Let's break this down a little. From within the:

  • /home/pi/bluepy directory, there is a bluepy.btle submodule. (Good.)
  • /home/pi/bluepy/bluepy subdirectory, there is no bluepy.btle submodule. (Bad.) Unless you awkwardly attempt to manually inject the parent directory of this subdirectory (i.e., /home/pi/bluepy) onto sys.path as Makie Messer perhaps inadvisably advises, Python has no means of inferring that the package bluepy actually refers to the current directory coincidentally also named bluepy. To avoid ambiguity issues of this sort, Python is typically only run outside rather than inside of a project's package subdirectory.

Since you ran py.test from the latter rather than the former directory, Python is unable to find the bluepy.btle submodule on the current sys.path. For this and similar reasons, py.test should typically only ever be run from your project's top-level rootdir (i.e., /home/pi/bluepy):

pi@pi:~/ $ cd ~/bluepy pi@pi:~/bluepy $ py.test bluepy/test_asdf.py

Lastly, note that it's typically preferable to defer test discovery to py.test. Rather than explicitly listing all test script filenames on the command line, consider instead letting py.test implicitly find and run all tests containing some substring via the -k option. For example, to run all tests whose function names are prefixed by test_asdf (regardless of the test script they reside in):

pi@pi:~/ $ cd ~/bluepy pi@pi:~/bluepy $ py.test -k test_asdf .

The suffixing . is optional, but often useful. It instructs py.test to set its rootdir property to the current directory (i.e., /home/pi/bluepy). py.test is usually capable of finding your project's rootdir and setting this property on its own, but it can't hurt to specify it manually. (Especially as you're having... issues.)

For further details on rootdir discovery, see Initialization: determining rootdir and inifile in the official py.test documentation.

like image 45
Cecil Curry Avatar answered Sep 21 '22 12:09

Cecil Curry