Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1642 add rootdir option #3127

Merged
merged 15 commits into from
Feb 7, 2018
Merged
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ Ned Batchelder
Neven Mundar
Nicolas Delaby
Oleg Pidsadnyi
Oleg Sushchenko
Oliver Bestwalter
Omar Kohl
Omer Hadari
Expand Down
12 changes: 10 additions & 2 deletions _pytest/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -990,11 +990,14 @@ def pytest_load_initial_conftests(self, early_config):

def _initini(self, args):
ns, unknown_args = self._parser.parse_known_and_unknown_args(args, namespace=self.option.copy())
r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args, warnfunc=self.warn)
rootdir = ns.rootdir if ns.rootdir else None
r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args, warnfunc=self.warn, rootdir_cmd_arg=rootdir)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be written as:

r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args, warnfunc=self.warn, rootdir_cmd_arg=ns.rootdir or None)

Besides shorter, this doesn't left a rootdir local variable to be used by the unaware. 😁

self.rootdir, self.inifile, self.inicfg = r
self._parser.extra_info['rootdir'] = self.rootdir
self._parser.extra_info['inifile'] = self.inifile
self.invocation_dir = py.path.local()
if ns.rootdir:
self.invocation_dir = self.rootdir
Copy link
Member

@nicoddemus nicoddemus Jan 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for this change?

I'm not sure we should be changing the invocation_dir, it is supposed to contain the directory where pytest was invoked from, regardless of the rootdir.

self._parser.addini('addopts', 'extra command line options', 'args')
self._parser.addini('minversion', 'minimally required pytest version')
self._override_ini = ns.override_ini or ()
Expand Down Expand Up @@ -1323,7 +1326,7 @@ def get_dir_from_path(path):
]


def determine_setup(inifile, args, warnfunc=None):
def determine_setup(inifile, args, warnfunc=None, rootdir_cmd_arg=None):
dirs = get_dirs_from_args(args)
if inifile:
iniconfig = py.iniconfig.IniConfig(inifile)
Expand All @@ -1346,6 +1349,11 @@ def determine_setup(inifile, args, warnfunc=None):
is_fs_root = os.path.splitdrive(str(rootdir))[1] == '/'
if is_fs_root:
rootdir = ancestor
if rootdir_cmd_arg:
rootdir_abs_path = py.path.local(rootdir_cmd_arg)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should call os.path.expandvars(rootdir_cmd_arg) here, not in the test; we want to make sure the functionality is available to users after all. 😉

if not os.path.isdir(str(rootdir_abs_path)):
raise UsageError("Directory '{}' not found. Check your '--rootdir' option.".format(rootdir_abs_path))
rootdir = rootdir_abs_path
return rootdir, inifile, inicfg or {}


Expand Down
6 changes: 6 additions & 0 deletions _pytest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ def pytest_addoption(parser):
group._addoption("--continue-on-collection-errors", action="store_true",
default=False, dest="continue_on_collection_errors",
help="Force test execution even if collection errors occur.")
group._addoption("--rootdir", action="store",
dest="rootdir",
help="Define root directory for tests. Can be relative path: 'root_dir', './root_dir', "
"'root_dir/another_dir/'; absolute path: '/home/user/root_dir'; path with variables: "
"'$HOME/root_dir'.")

group = parser.getgroup("collect", "collection")
group.addoption('--collectonly', '--collect-only', action="store_true",
Expand Down Expand Up @@ -283,6 +288,7 @@ def __init__(self, config):
self.trace = config.trace.root.get("collection")
self._norecursepatterns = config.getini("norecursedirs")
self.startdir = py.path.local()

self.config.pluginmanager.register(self, name="session")

def _makeid(self):
Expand Down
1 change: 1 addition & 0 deletions changelog/1642.trivial
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add ``--rootdir`` command-line option to override the rules for discovering the root directory. See `customize <https://docs.pytest.org/en/latest/customize.html>`_ in the documentation for details.
6 changes: 6 additions & 0 deletions doc/en/customize.rst
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,9 @@ Builtin configuration file options
# content of pytest.ini
[pytest]
console_output_style = classic

.. confval:: rootdir
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that this is not really a configuration variable (e.g goes into a pytest.ini file) but a command line option.

I think it makes more sense to add a paragraph to the Initialization: determining rootdir and inifile section in this same file instead.


Sets a :ref:`rootdir <rootdir>` directory. Directory may be relative or absolute path.
Additionally path may contain environment variables, that will be expanded.
For more information about rootdir please refer to :ref:`rootdir <rootdir>`.
25 changes: 25 additions & 0 deletions testing/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,28 @@ def pytest_sessionfinish():
""")
res = testdir.runpytest("--collect-only")
assert res.ret == EXIT_NOTESTSCOLLECTED


def test_rootdir_option_arg(testdir):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add tests for absolute and paths containing environment variables.

Copy link
Contributor Author

@feuillemorte feuillemorte Jan 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests on absolute path added (not commites yet)

paths containing environment variables not working in tests, but working when I test locally :(

tests:

testdir.runpytest("--rootdir=$HOME")

ERROR: Directory '/tmp/pytest-of-feuillemorte/pytest-31/test_rootdir_option_arg2/$HOME/root' not found. Check your '--rootdir' option.

locally directory changed:

pytest tests --rootdir=$HOME/root

ERROR: Directory '/home/username/root' not found. Check your '--rootdir' option.

Please, help))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to explicitly call os.path.expandvars to deal with variable expansion.

When you say "locally" I suppose you mean the command line? In that case is your shell doing the expansion, not pytest. 😉

rootdir = testdir.mkdir("root")
rootdir.mkdir("tests")
testdir.makepyfile("""
import os
def test_one():
assert os.path.isdir('.cache')
""")

result = testdir.runpytest()
result.stdout.fnmatch_lines(["*AssertionError*"])

result = testdir.runpytest("--rootdir=root")
result.stdout.fnmatch_lines(["*1 passed*"])


def test_rootdir_wrong_option_arg(testdir):
rootdir = testdir.mkdir("root")
testsdir = rootdir.mkdir("tests")
testsdir.join("test_one.py").write("def test_one():\n assert 1")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be written as:

testdir.makepyfile("""
    def test_one():
        assert 1
""")

Which is more readable IMO. This call will create a file test_rootdir_wrong_option_arg.py in the testdir directory (same name as the test), which is not really relevant for his this test.

Actually I don't even think the file or the directories is relevant for the test at all, so we can remove this preparation from this test.

Copy link
Contributor Author

@feuillemorte feuillemorte Jan 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that I can't create file in root/tests folder by this code. It will created in the testdir folder. But tests run fine, so, fixed =)


result = testdir.runpytest("--rootdir=wrong_dir")
result.stderr.fnmatch_lines(["*Directory *wrong_dir* not found. Check your '--rootdir' option.*"])