put config path finding and exceptions into own modules
This commit is contained in:
parent
c9df77cbd6
commit
1459cbe01f
|
@ -19,6 +19,8 @@ import _pytest.hookspec # the extension point definitions
|
||||||
import _pytest.assertion
|
import _pytest.assertion
|
||||||
from pluggy import PluginManager, HookimplMarker, HookspecMarker
|
from pluggy import PluginManager, HookimplMarker, HookspecMarker
|
||||||
from _pytest.compat import safe_str
|
from _pytest.compat import safe_str
|
||||||
|
from .exceptions import UsageError, PrintHelp
|
||||||
|
from .findpaths import determine_setup, exists
|
||||||
|
|
||||||
hookimpl = HookimplMarker("pytest")
|
hookimpl = HookimplMarker("pytest")
|
||||||
hookspec = HookspecMarker("pytest")
|
hookspec = HookspecMarker("pytest")
|
||||||
|
@ -74,16 +76,6 @@ class cmdline(object): # NOQA compatibility namespace
|
||||||
main = staticmethod(main)
|
main = staticmethod(main)
|
||||||
|
|
||||||
|
|
||||||
class UsageError(Exception):
|
|
||||||
""" error in pytest usage or invocation"""
|
|
||||||
|
|
||||||
|
|
||||||
class PrintHelp(Exception):
|
|
||||||
"""Raised when pytest should print it's help to skip the rest of the
|
|
||||||
argument parsing and validation."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def filename_arg(path, optname):
|
def filename_arg(path, optname):
|
||||||
""" Argparse type validator for filename arguments.
|
""" Argparse type validator for filename arguments.
|
||||||
|
|
||||||
|
@ -934,143 +926,6 @@ def _warn_about_missing_assertion(mode):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def exists(path, ignore=EnvironmentError):
|
|
||||||
try:
|
|
||||||
return path.check()
|
|
||||||
except ignore:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def getcfg(args, warnfunc=None):
|
|
||||||
"""
|
|
||||||
Search the list of arguments for a valid ini-file for pytest,
|
|
||||||
and return a tuple of (rootdir, inifile, cfg-dict).
|
|
||||||
|
|
||||||
note: warnfunc is an optional function used to warn
|
|
||||||
about ini-files that use deprecated features.
|
|
||||||
This parameter should be removed when pytest
|
|
||||||
adopts standard deprecation warnings (#1804).
|
|
||||||
"""
|
|
||||||
from _pytest.deprecated import CFG_PYTEST_SECTION
|
|
||||||
|
|
||||||
inibasenames = ["pytest.ini", "tox.ini", "setup.cfg"]
|
|
||||||
args = [x for x in args if not str(x).startswith("-")]
|
|
||||||
if not args:
|
|
||||||
args = [py.path.local()]
|
|
||||||
for arg in args:
|
|
||||||
arg = py.path.local(arg)
|
|
||||||
for base in arg.parts(reverse=True):
|
|
||||||
for inibasename in inibasenames:
|
|
||||||
p = base.join(inibasename)
|
|
||||||
if exists(p):
|
|
||||||
iniconfig = py.iniconfig.IniConfig(p)
|
|
||||||
if "pytest" in iniconfig.sections:
|
|
||||||
if inibasename == "setup.cfg" and warnfunc:
|
|
||||||
warnfunc(
|
|
||||||
"C1", CFG_PYTEST_SECTION.format(filename=inibasename)
|
|
||||||
)
|
|
||||||
return base, p, iniconfig["pytest"]
|
|
||||||
if (
|
|
||||||
inibasename == "setup.cfg"
|
|
||||||
and "tool:pytest" in iniconfig.sections
|
|
||||||
):
|
|
||||||
return base, p, iniconfig["tool:pytest"]
|
|
||||||
elif inibasename == "pytest.ini":
|
|
||||||
# allowed to be empty
|
|
||||||
return base, p, {}
|
|
||||||
return None, None, None
|
|
||||||
|
|
||||||
|
|
||||||
def get_common_ancestor(paths):
|
|
||||||
common_ancestor = None
|
|
||||||
for path in paths:
|
|
||||||
if not path.exists():
|
|
||||||
continue
|
|
||||||
if common_ancestor is None:
|
|
||||||
common_ancestor = path
|
|
||||||
else:
|
|
||||||
if path.relto(common_ancestor) or path == common_ancestor:
|
|
||||||
continue
|
|
||||||
elif common_ancestor.relto(path):
|
|
||||||
common_ancestor = path
|
|
||||||
else:
|
|
||||||
shared = path.common(common_ancestor)
|
|
||||||
if shared is not None:
|
|
||||||
common_ancestor = shared
|
|
||||||
if common_ancestor is None:
|
|
||||||
common_ancestor = py.path.local()
|
|
||||||
elif common_ancestor.isfile():
|
|
||||||
common_ancestor = common_ancestor.dirpath()
|
|
||||||
return common_ancestor
|
|
||||||
|
|
||||||
|
|
||||||
def get_dirs_from_args(args):
|
|
||||||
|
|
||||||
def is_option(x):
|
|
||||||
return str(x).startswith("-")
|
|
||||||
|
|
||||||
def get_file_part_from_node_id(x):
|
|
||||||
return str(x).split("::")[0]
|
|
||||||
|
|
||||||
def get_dir_from_path(path):
|
|
||||||
if path.isdir():
|
|
||||||
return path
|
|
||||||
return py.path.local(path.dirname)
|
|
||||||
|
|
||||||
# These look like paths but may not exist
|
|
||||||
possible_paths = (
|
|
||||||
py.path.local(get_file_part_from_node_id(arg))
|
|
||||||
for arg in args
|
|
||||||
if not is_option(arg)
|
|
||||||
)
|
|
||||||
|
|
||||||
return [get_dir_from_path(path) for path in possible_paths if path.exists()]
|
|
||||||
|
|
||||||
|
|
||||||
def determine_setup(inifile, args, warnfunc=None, rootdir_cmd_arg=None):
|
|
||||||
dirs = get_dirs_from_args(args)
|
|
||||||
if inifile:
|
|
||||||
iniconfig = py.iniconfig.IniConfig(inifile)
|
|
||||||
is_cfg_file = str(inifile).endswith(".cfg")
|
|
||||||
# TODO: [pytest] section in *.cfg files is depricated. Need refactoring.
|
|
||||||
sections = ["tool:pytest", "pytest"] if is_cfg_file else ["pytest"]
|
|
||||||
for section in sections:
|
|
||||||
try:
|
|
||||||
inicfg = iniconfig[section]
|
|
||||||
if is_cfg_file and section == "pytest" and warnfunc:
|
|
||||||
from _pytest.deprecated import CFG_PYTEST_SECTION
|
|
||||||
|
|
||||||
warnfunc("C1", CFG_PYTEST_SECTION.format(filename=str(inifile)))
|
|
||||||
break
|
|
||||||
except KeyError:
|
|
||||||
inicfg = None
|
|
||||||
rootdir = get_common_ancestor(dirs)
|
|
||||||
else:
|
|
||||||
ancestor = get_common_ancestor(dirs)
|
|
||||||
rootdir, inifile, inicfg = getcfg([ancestor], warnfunc=warnfunc)
|
|
||||||
if rootdir is None:
|
|
||||||
for rootdir in ancestor.parts(reverse=True):
|
|
||||||
if rootdir.join("setup.py").exists():
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc)
|
|
||||||
if rootdir is None:
|
|
||||||
rootdir = get_common_ancestor([py.path.local(), ancestor])
|
|
||||||
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(os.path.expandvars(rootdir_cmd_arg))
|
|
||||||
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 {}
|
|
||||||
|
|
||||||
|
|
||||||
def setns(obj, dic):
|
def setns(obj, dic):
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
class UsageError(Exception):
|
||||||
|
""" error in pytest usage or invocation"""
|
||||||
|
|
||||||
|
|
||||||
|
class PrintHelp(Exception):
|
||||||
|
"""Raised when pytest should print it's help to skip the rest of the
|
||||||
|
argument parsing and validation."""
|
||||||
|
pass
|
|
@ -0,0 +1,140 @@
|
||||||
|
import py
|
||||||
|
import os
|
||||||
|
from .exceptions import UsageError
|
||||||
|
|
||||||
|
|
||||||
|
def exists(path, ignore=EnvironmentError):
|
||||||
|
try:
|
||||||
|
return path.check()
|
||||||
|
except ignore:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def getcfg(args, warnfunc=None):
|
||||||
|
"""
|
||||||
|
Search the list of arguments for a valid ini-file for pytest,
|
||||||
|
and return a tuple of (rootdir, inifile, cfg-dict).
|
||||||
|
|
||||||
|
note: warnfunc is an optional function used to warn
|
||||||
|
about ini-files that use deprecated features.
|
||||||
|
This parameter should be removed when pytest
|
||||||
|
adopts standard deprecation warnings (#1804).
|
||||||
|
"""
|
||||||
|
from _pytest.deprecated import CFG_PYTEST_SECTION
|
||||||
|
|
||||||
|
inibasenames = ["pytest.ini", "tox.ini", "setup.cfg"]
|
||||||
|
args = [x for x in args if not str(x).startswith("-")]
|
||||||
|
if not args:
|
||||||
|
args = [py.path.local()]
|
||||||
|
for arg in args:
|
||||||
|
arg = py.path.local(arg)
|
||||||
|
for base in arg.parts(reverse=True):
|
||||||
|
for inibasename in inibasenames:
|
||||||
|
p = base.join(inibasename)
|
||||||
|
if exists(p):
|
||||||
|
iniconfig = py.iniconfig.IniConfig(p)
|
||||||
|
if "pytest" in iniconfig.sections:
|
||||||
|
if inibasename == "setup.cfg" and warnfunc:
|
||||||
|
warnfunc(
|
||||||
|
"C1", CFG_PYTEST_SECTION.format(filename=inibasename)
|
||||||
|
)
|
||||||
|
return base, p, iniconfig["pytest"]
|
||||||
|
if (
|
||||||
|
inibasename == "setup.cfg"
|
||||||
|
and "tool:pytest" in iniconfig.sections
|
||||||
|
):
|
||||||
|
return base, p, iniconfig["tool:pytest"]
|
||||||
|
elif inibasename == "pytest.ini":
|
||||||
|
# allowed to be empty
|
||||||
|
return base, p, {}
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
|
|
||||||
|
def get_common_ancestor(paths):
|
||||||
|
common_ancestor = None
|
||||||
|
for path in paths:
|
||||||
|
if not path.exists():
|
||||||
|
continue
|
||||||
|
if common_ancestor is None:
|
||||||
|
common_ancestor = path
|
||||||
|
else:
|
||||||
|
if path.relto(common_ancestor) or path == common_ancestor:
|
||||||
|
continue
|
||||||
|
elif common_ancestor.relto(path):
|
||||||
|
common_ancestor = path
|
||||||
|
else:
|
||||||
|
shared = path.common(common_ancestor)
|
||||||
|
if shared is not None:
|
||||||
|
common_ancestor = shared
|
||||||
|
if common_ancestor is None:
|
||||||
|
common_ancestor = py.path.local()
|
||||||
|
elif common_ancestor.isfile():
|
||||||
|
common_ancestor = common_ancestor.dirpath()
|
||||||
|
return common_ancestor
|
||||||
|
|
||||||
|
|
||||||
|
def get_dirs_from_args(args):
|
||||||
|
|
||||||
|
def is_option(x):
|
||||||
|
return str(x).startswith("-")
|
||||||
|
|
||||||
|
def get_file_part_from_node_id(x):
|
||||||
|
return str(x).split("::")[0]
|
||||||
|
|
||||||
|
def get_dir_from_path(path):
|
||||||
|
if path.isdir():
|
||||||
|
return path
|
||||||
|
return py.path.local(path.dirname)
|
||||||
|
|
||||||
|
# These look like paths but may not exist
|
||||||
|
possible_paths = (
|
||||||
|
py.path.local(get_file_part_from_node_id(arg))
|
||||||
|
for arg in args
|
||||||
|
if not is_option(arg)
|
||||||
|
)
|
||||||
|
|
||||||
|
return [get_dir_from_path(path) for path in possible_paths if path.exists()]
|
||||||
|
|
||||||
|
|
||||||
|
def determine_setup(inifile, args, warnfunc=None, rootdir_cmd_arg=None):
|
||||||
|
dirs = get_dirs_from_args(args)
|
||||||
|
if inifile:
|
||||||
|
iniconfig = py.iniconfig.IniConfig(inifile)
|
||||||
|
is_cfg_file = str(inifile).endswith(".cfg")
|
||||||
|
# TODO: [pytest] section in *.cfg files is depricated. Need refactoring.
|
||||||
|
sections = ["tool:pytest", "pytest"] if is_cfg_file else ["pytest"]
|
||||||
|
for section in sections:
|
||||||
|
try:
|
||||||
|
inicfg = iniconfig[section]
|
||||||
|
if is_cfg_file and section == "pytest" and warnfunc:
|
||||||
|
from _pytest.deprecated import CFG_PYTEST_SECTION
|
||||||
|
|
||||||
|
warnfunc("C1", CFG_PYTEST_SECTION.format(filename=str(inifile)))
|
||||||
|
break
|
||||||
|
except KeyError:
|
||||||
|
inicfg = None
|
||||||
|
rootdir = get_common_ancestor(dirs)
|
||||||
|
else:
|
||||||
|
ancestor = get_common_ancestor(dirs)
|
||||||
|
rootdir, inifile, inicfg = getcfg([ancestor], warnfunc=warnfunc)
|
||||||
|
if rootdir is None:
|
||||||
|
for rootdir in ancestor.parts(reverse=True):
|
||||||
|
if rootdir.join("setup.py").exists():
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc)
|
||||||
|
if rootdir is None:
|
||||||
|
rootdir = get_common_ancestor([py.path.local(), ancestor])
|
||||||
|
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(os.path.expandvars(rootdir_cmd_arg))
|
||||||
|
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 {}
|
Loading…
Reference in New Issue