def exit(reason: str = "",
         returncode: Optional[int] = None,
         *,
         msg: Optional[str] = None) -> "NoReturn":
    """Exit testing process.

    :param reason:
        The message to show as the reason for exiting pytest.  reason has a default value
        only because `msg` is deprecated.

    :param returncode:
        Return code to be used when exiting pytest.

    :param msg:
        Same as ``reason``, but deprecated. Will be removed in a future version, use ``reason`` instead.
    """
    __tracebackhide__ = True
    from _pytest.config import UsageError

    if reason and msg:
        raise UsageError(
            "cannot pass reason and msg to exit(), `msg` is deprecated, use `reason`."
        )
    if not reason:
        if msg is None:
            raise UsageError("exit() requires a reason argument")
        warnings.warn(KEYWORD_MSG_ARG.format(func="exit"), stacklevel=2)
        reason = msg
    raise Exit(reason, returncode)
示例#2
0
def build_sosu_config(args: argparse.Namespace,
                      env: os._Environ) -> SosuConfig:
    username = args.sosu_username or env.get("SAUCE_USERNAME")
    access_key = args.sosu_access_key or env.get("SAUCE_ACCESS_KEY")

    if not username:
        raise UsageError("--sosu-username or SAUCE_USERNAME are not provided")

    if not access_key:
        raise UsageError(
            "--sosu-access-key or SAUCE_ACCESS_KEY are not provided")

    region = args.sosu_region or env.get("SAUCE_REGION")
    webdriver_url = args.sosu_webdriver_url or env.get("SAUCE_WEBDRIVER_URL")

    if not webdriver_url:
        region = "us-west-1"
        host = get_host_by_region(region)
        webdriver_url_data = WebDriverUrlData(host=host)
    else:
        try:
            webdriver_url_data = WebDriverUrlData.from_url(webdriver_url)
        except ValueError:
            raise UsageError("Invalid WebDriver URL") from None

    return SosuConfig(
        username=username,
        access_key=access_key,
        region=region,
        webdriver_url_data=webdriver_url_data,
    )
示例#3
0
def matchkeyword(colitem, keywordexpr):
    """Tries to match given keyword expression to given collector item.

    Will match on the name of colitem, including the names of its parents.
    Only matches names of items which are either a :class:`Class` or a
    :class:`Function`.
    Additionally, matches on names in the 'extra_keyword_matches' set of
    any item, as well as names directly assigned to test functions.
    """
    mapping = KeywordMapping.from_item(colitem)
    if " " not in keywordexpr:
        # special case to allow for simple "-k pass" and "-k 1.3"
        return mapping[keywordexpr]
    elif keywordexpr.startswith("not ") and " " not in keywordexpr[4:]:
        return not mapping[keywordexpr[4:]]
    for kwd in keywordexpr.split():
        if keyword.iskeyword(kwd) and kwd not in python_keywords_allowed_list:
            raise UsageError(
                "Python keyword '{}' not accepted in expressions passed to '-k'"
                .format(kwd))
    try:
        return eval(keywordexpr, {}, mapping)
    except Exception:
        raise UsageError(
            "Wrong expression passed to '-k': {}".format(keywordexpr))
示例#4
0
def pytest_collection_modifyitems(config, items):
    redis_uri = config.getoption("--redis")
    if redis_uri is None:
        skip_redis = pytest.mark.skip(
            reason="need --redis option with redis URI to run"
        )
        for item in items:
            if "redis" in item.keywords:
                item.add_marker(skip_redis)
        return

    redis_version = int(aioredis.__version__.split(".")[0])
    options = None
    if redis_version == 1:
        (host, port), options = aioredis.util.parse_url(redis_uri)
        options.update({'host': host, 'port': port})
    elif redis_version == 2:
        try:
            options = aioredis.connection.parse_url(redis_uri)
        except ValueError as e:
            raise UsageError(f"Invalid redis URI {redis_uri!r}: {e}")

    try:
        assert isinstance(options, dict), \
            "Only redis and rediss schemas are supported, eg redis://foo."
    except AssertionError as e:
        raise UsageError(f"Invalid redis URI {redis_uri!r}: {e}")
示例#5
0
文件: main.py 项目: fabioz/pytest
 def _parsearg(self, arg: str) -> Tuple[py.path.local, List[str]]:
     """ return (fspath, names) tuple after checking the file exists. """
     strpath, *parts = str(arg).split("::")
     if self.config.option.pyargs:
         strpath = self._tryconvertpyarg(strpath)
     relpath = strpath.replace("/", os.sep)
     fspath = self.config.invocation_dir.join(relpath, abs=True)
     if not fspath.check():
         if self.config.option.pyargs:
             raise UsageError("file or package not found: " + arg +
                              " (missing __init__.py?)")
         raise UsageError("file not found: " + arg)
     return (fspath, parts)
 def _parsearg(self, arg):
     """ return (fspath, names) tuple after checking the file exists. """
     parts = str(arg).split("::")
     if self.config.option.pyargs:
         parts[0] = self._tryconvertpyarg(parts[0])
     relpath = parts[0].replace("/", os.sep)
     path = self.config.invocation_dir.join(relpath, abs=True)
     if not path.check():
         if self.config.option.pyargs:
             raise UsageError("file or package not found: " + arg +
                              " (missing __init__.py?)")
         raise UsageError("file not found: " + arg)
     parts[0] = path.realpath()
     return parts
示例#7
0
def resolve_collection_argument(
    invocation_path: Path, arg: str, *, as_pypath: bool = False
) -> Tuple[Path, List[str]]:
    """Parse path arguments optionally containing selection parts and return (fspath, names).

    Command-line arguments can point to files and/or directories, and optionally contain
    parts for specific tests selection, for example:

        "pkg/tests/test_foo.py::TestClass::test_foo"

    This function ensures the path exists, and returns a tuple:

        (Path("/full/path/to/pkg/tests/test_foo.py"), ["TestClass", "test_foo"])

    When as_pypath is True, expects that the command-line argument actually contains
    module paths instead of file-system paths:

        "pkg.tests.test_foo::TestClass::test_foo"

    In which case we search sys.path for a matching module, and then return the *path* to the
    found module.

    If the path doesn't exist, raise UsageError.
    If the path is a directory and selection parts are present, raise UsageError.
    """
    base, squacket, rest = str(arg).partition("[")
    strpath, *parts = base.split("::")
    if parts:
        parts[-1] = f"{parts[-1]}{squacket}{rest}"
    if as_pypath:
        strpath = search_pypath(strpath)
    fspath = invocation_path / strpath
    fspath = absolutepath(fspath)
    if not fspath.exists():
        msg = (
            "module or package not found: {arg} (missing __init__.py?)"
            if as_pypath
            else "file or directory not found: {arg}"
        )
        raise UsageError(msg.format(arg=arg))
    if parts and fspath.is_dir():
        msg = (
            "package argument cannot contain :: selection parts: {arg}"
            if as_pypath
            else "directory argument cannot contain :: selection parts: {arg}"
        )
        raise UsageError(msg.format(arg=arg))
    return fspath, parts
示例#8
0
def matchmark(colitem, markexpr):
    """Tries to match on any marker names, attached to the given colitem."""
    try:
        return eval(markexpr, {}, MarkMapping.from_item(colitem))
    except Exception:
        raise UsageError(
            "Wrong expression passed to '-m': {}".format(markexpr))
示例#9
0
 def _perform_collect(self, args, genitems):
     if args is None:
         args = self.config.args
     self.trace("perform_collect", self, args)
     self.trace.root.indent += 1
     self._notfound = []
     self._initialpaths = set()
     self._initialparts = []
     self.items = items = []
     for arg in args:
         parts = self._parsearg(arg)
         self._initialparts.append(parts)
         self._initialpaths.add(parts[0])
     rep = collect_one_node(self)
     self.ihook.pytest_collectreport(report=rep)
     self.trace.root.indent -= 1
     if self._notfound:
         errors = []
         for arg, exc in self._notfound:
             line = "(no name %r in any of %r)" % (arg, exc.args[0])
             errors.append("not found: %s\n%s" % (arg, line))
             # XXX: test this
         raise UsageError(*errors)
     if not genitems:
         return rep.result
     else:
         if rep.passed:
             for node in rep.result:
                 self.items.extend(self.genitems(node))
         return items
def _resolve_msg_to_reason(func_name: str,
                           reason: str,
                           msg: Optional[str] = None) -> str:
    """
    Handles converting the deprecated msg parameter if provided into
    reason, raising a deprecation warning.  This function will be removed
    when the optional msg argument is removed from here in future.

    :param str func_name:
        The name of the offending function, this is formatted into the deprecation message.

    :param str reason:
        The reason= passed into either pytest.fail() or pytest.skip()

    :param str msg:
        The msg= passed into either pytest.fail() or pytest.skip().  This will
        be converted into reason if it is provided to allow pytest.skip(msg=) or
        pytest.fail(msg=) to continue working in the interim period.

    :returns:
        The value to use as reason.

    """
    __tracebackhide__ = True
    if msg is not None:

        if reason:
            from pytest import UsageError

            raise UsageError(
                f"Passing both ``reason`` and ``msg`` to pytest.{func_name}(...) is not permitted."
            )
        warnings.warn(KEYWORD_MSG_ARG.format(func=func_name), stacklevel=3)
        reason = msg
    return reason
示例#11
0
def matchmark(colitem, markexpr: str) -> bool:
    """Tries to match on any marker names, attached to the given colitem."""
    try:
        return evaluate(markexpr, MarkMatcher.from_item(colitem))
    except ParseError as e:
        raise UsageError("Wrong expression passed to '-m': {}: {}".format(
            markexpr, e)) from None
示例#12
0
文件: main.py 项目: fabioz/pytest
 def _perform_collect(  # noqa: F811
     self, args: Optional[Sequence[str]], genitems: bool) -> Union[
         List[Union[nodes.Item]], List[Union[nodes.Item, nodes.Collector]]]:
     if args is None:
         args = self.config.args
     self.trace("perform_collect", self, args)
     self.trace.root.indent += 1
     self._notfound = []  # type: List[Tuple[str, NoMatch]]
     initialpaths = []  # type: List[py.path.local]
     self._initial_parts = []  # type: List[Tuple[py.path.local, List[str]]]
     self.items = items = []  # type: List[nodes.Item]
     for arg in args:
         fspath, parts = self._parsearg(arg)
         self._initial_parts.append((fspath, parts))
         initialpaths.append(fspath)
     self._initialpaths = frozenset(initialpaths)
     rep = collect_one_node(self)
     self.ihook.pytest_collectreport(report=rep)
     self.trace.root.indent -= 1
     if self._notfound:
         errors = []
         for arg, exc in self._notfound:
             line = "(no name {!r} in any of {!r})".format(arg, exc.args[0])
             errors.append("not found: {}\n{}".format(arg, line))
         raise UsageError(*errors)
     if not genitems:
         return rep.result
     else:
         if rep.passed:
             for node in rep.result:
                 self.items.extend(self.genitems(node))
         return items
示例#13
0
def redis_options(request):
    redis_uri = request.config.getoption("--redis")
    if redis_uri is None:
        pytest.skip("need --redis option with redis URI to run")
        return

    redis_version = int(aioredis.__version__.split(".")[0])
    if redis_version == 1:
        (host, port), options = aioredis.util.parse_url(redis_uri)
        options.update({'host': host, 'port': port})
        return options

    if redis_version == 2:
        try:
            return aioredis.connection.parse_url(redis_uri)
        except ValueError as e:
            raise UsageError(f"Invalid redis URI {redis_uri!r}: {e}")

    raise UsageError("Unsupported aioredis version")
示例#14
0
def matchkeyword(colitem, keywordexpr):
    """Tries to match given keyword expression to given collector item.

    Will match on the name of colitem, including the names of its parents.
    Only matches names of items which are either a :class:`Class` or a
    :class:`Function`.
    Additionally, matches on names in the 'extra_keyword_matches' set of
    any item, as well as names directly assigned to test functions.
    """
    mapped_names = set()

    # Add the names of the current item and any parent items
    import pytest
    for item in colitem.listchain():
        if not isinstance(item, pytest.Instance):
            mapped_names.add(item.name)

    # Add the names added as extra keywords to current or parent items
    for name in colitem.listextrakeywords():
        mapped_names.add(name)

    # Add the names attached to the current function through direct assignment
    if hasattr(colitem, 'function'):
        for name in colitem.function.__dict__:
            mapped_names.add(name)

    mapping = KeywordMapping(mapped_names)
    if " " not in keywordexpr:
        # special case to allow for simple "-k pass" and "-k 1.3"
        return mapping[keywordexpr]
    elif keywordexpr.startswith("not ") and " " not in keywordexpr[4:]:
        return not mapping[keywordexpr[4:]]
    for kwd in keywordexpr.split():
        if keyword.iskeyword(kwd) and kwd not in python_keywords_allowed_list:
            raise UsageError(
                "Python keyword '{}' not accepted in expressions passed to '-k'"
                .format(kwd))
    try:
        return eval(keywordexpr, {}, mapping)
    except SyntaxError:
        raise UsageError(
            "Wrong expression passed to '-k': {}".format(keywordexpr))
示例#15
0
def pytest_configure(config: Config) -> None:
    config._store[old_mark_config_key] = MARK_GEN._config
    MARK_GEN._config = config

    empty_parameterset = config.getini(EMPTY_PARAMETERSET_OPTION)

    if empty_parameterset not in ("skip", "xfail", "fail_at_collect", None,
                                  ""):
        raise UsageError("{!s} must be one of skip, xfail or fail_at_collect"
                         " but it is {!r}".format(EMPTY_PARAMETERSET_OPTION,
                                                  empty_parameterset))
示例#16
0
def pytest_configure(config):
    config._old_mark_config = MARK_GEN._config
    if config.option.strict:
        MARK_GEN._config = config

    empty_parameterset = config.getini(EMPTY_PARAMETERSET_OPTION)

    if empty_parameterset not in ('skip', 'xfail', None, ''):
        raise UsageError("{!s} must be one of skip and xfail,"
                         " but it is {!r}".format(EMPTY_PARAMETERSET_OPTION,
                                                  empty_parameterset))
示例#17
0
def pytest_collection_modifyitems(config):
    diva_path = config.getoption('--divadir')
    if diva_path:
        os.environ['PATH'] += os.pathsep + os.path.abspath(diva_path)

    try:
        subprocess.check_call(['diva', '--version'])
    except (subprocess.CalledProcessError, OSError):
        msg = "Can't find diva on PATH"
        if diva_path is None:
            msg += " and --divadir not provided"
        else:
            msg += " or in {} (provided with --divadir)".format(diva_path)
        raise UsageError(msg)
示例#18
0
def matchkeyword(colitem, keywordexpr: str) -> bool:
    """Tries to match given keyword expression to given collector item.

    Will match on the name of colitem, including the names of its parents.
    Only matches names of items which are either a :class:`Class` or a
    :class:`Function`.
    Additionally, matches on names in the 'extra_keyword_matches' set of
    any item, as well as names directly assigned to test functions.
    """
    try:
        return evaluate(keywordexpr, KeywordMatcher.from_item(colitem))
    except ParseError as e:
        raise UsageError("Wrong expression passed to '-k': {}: {}".format(
            keywordexpr, e)) from None
示例#19
0
def deselect_by_mark(items: "List[Item]", config: Config) -> None:
    matchexpr = config.option.markexpr
    if not matchexpr:
        return

    try:
        expression = Expression.compile(matchexpr)
    except ParseError as e:
        raise UsageError(f"Wrong expression passed to '-m': {matchexpr}: {e}") from None

    remaining = []
    deselected = []
    for item in items:
        if expression.evaluate(MarkMatcher.from_item(item)):
            remaining.append(item)
        else:
            deselected.append(item)

    if deselected:
        config.hook.pytest_deselected(items=deselected)
        items[:] = remaining
示例#20
0
def get_log_level_for_setting(config: Config,
                              *setting_names: str) -> Optional[int]:
    for setting_name in setting_names:
        log_level = config.getoption(setting_name)
        if log_level is None:
            log_level = config.getini(setting_name)
        if log_level:
            break
    else:
        return None

    if isinstance(log_level, str):
        log_level = log_level.upper()
    try:
        return int(getattr(logging, log_level, log_level))
    except ValueError as e:
        # Python logging does not recognise this as a logging level
        raise UsageError("'{}' is not recognized as a logging level name for "
                         "'{}'. Please consider passing the "
                         "logging level num instead.".format(
                             log_level, setting_name)) from e
示例#21
0
def deselect_by_keyword(items: "List[Item]", config: Config) -> None:
    keywordexpr = config.option.keyword.lstrip()
    if not keywordexpr:
        return

    if keywordexpr.startswith("-"):
        # To be removed in pytest 7.0.0.
        # Uncomment this after 6.0 release (#7361)
        # warnings.warn(MINUS_K_DASH, stacklevel=2)
        keywordexpr = "not " + keywordexpr[1:]
    selectuntil = False
    if keywordexpr[-1:] == ":":
        # To be removed in pytest 7.0.0.
        # Uncomment this after 6.0 release (#7361)
        # warnings.warn(MINUS_K_COLON, stacklevel=2)
        selectuntil = True
        keywordexpr = keywordexpr[:-1]

    try:
        expression = Expression.compile(keywordexpr)
    except ParseError as e:
        raise UsageError("Wrong expression passed to '-k': {}: {}".format(
            keywordexpr, e)) from None

    remaining = []
    deselected = []
    for colitem in items:
        if keywordexpr and not expression.evaluate(
                KeywordMatcher.from_item(colitem)):
            deselected.append(colitem)
        else:
            if selectuntil:
                keywordexpr = None
            remaining.append(colitem)

    if deselected:
        config.hook.pytest_deselected(items=deselected)
        items[:] = remaining
示例#22
0
文件: main.py 项目: ssbarnea/pytest
def resolve_collection_argument(
    invocation_dir: py.path.local, arg: str, *, as_pypath: bool = False
) -> Tuple[py.path.local, List[str]]:
    """Parse path arguments optionally containing selection parts and return (fspath, names).

    Command-line arguments can point to files and/or directories, and optionally contain
    parts for specific tests selection, for example:

        "pkg/tests/test_foo.py::TestClass::test_foo"

    This function ensures the path exists, and returns a tuple:

        (py.path.path("/full/path/to/pkg/tests/test_foo.py"), ["TestClass", "test_foo"])

    When as_pypath is True, expects that the command-line argument actually contains
    module paths instead of file-system paths:

        "pkg.tests.test_foo::TestClass::test_foo"

    In which case we search sys.path for a matching module, and then return the *path* to the
    found module.

    If the path doesn't exist, raise UsageError.
    """
    strpath, *parts = str(arg).split("::")
    if as_pypath:
        strpath = search_pypath(strpath)
    fspath = Path(str(invocation_dir), strpath)
    fspath = absolutepath(fspath)
    if not fspath.exists():
        msg = (
            "module or package not found: {arg} (missing __init__.py?)"
            if as_pypath
            else "file or directory not found: {arg}"
        )
        raise UsageError(msg.format(arg=arg))
    return py.path.local(str(fspath)), parts
示例#23
0
    def perform_collect(
        self, args: Optional[Sequence[str]] = None, genitems: bool = True
    ) -> Sequence[Union[nodes.Item, nodes.Collector]]:
        """Perform the collection phase for this session.

        This is called by the default
        :func:`pytest_collection <_pytest.hookspec.pytest_collection>` hook
        implementation; see the documentation of this hook for more details.
        For testing purposes, it may also be called directly on a fresh
        ``Session``.

        This function normally recursively expands any collectors collected
        from the session to their items, and only items are returned. For
        testing purposes, this may be suppressed by passing ``genitems=False``,
        in which case the return value contains these collectors unexpanded,
        and ``session.items`` is empty.
        """
        if args is None:
            args = self.config.args

        self.trace("perform_collect", self, args)
        self.trace.root.indent += 1

        self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = []
        self._initial_parts: List[Tuple[Path, List[str]]] = []
        self.items: List[nodes.Item] = []

        hook = self.config.hook

        items: Sequence[Union[nodes.Item, nodes.Collector]] = self.items
        try:
            initialpaths: List[Path] = []
            for arg in args:
                fspath, parts = resolve_collection_argument(
                    self.config.invocation_params.dir,
                    arg,
                    as_pypath=self.config.option.pyargs,
                )
                self._initial_parts.append((fspath, parts))
                initialpaths.append(fspath)
            self._initialpaths = frozenset(initialpaths)
            rep = collect_one_node(self)
            self.ihook.pytest_collectreport(report=rep)
            self.trace.root.indent -= 1
            if self._notfound:
                errors = []
                for arg, cols in self._notfound:
                    line = f"(no name {arg!r} in any of {cols!r})"
                    errors.append(f"not found: {arg}\n{line}")
                raise UsageError(*errors)
            if not genitems:
                items = rep.result
            else:
                if rep.passed:
                    for node in rep.result:
                        self.items.extend(self.genitems(node))

            self.config.pluginmanager.check_pending()
            hook.pytest_collection_modifyitems(
                session=self, config=self.config, items=items
            )
        finally:
            hook.pytest_collection_finish(session=self)

        self.testscollected = len(items)
        return items
示例#24
0
def _parse_expression(expr: str, exc_message: str) -> Expression:
    try:
        return Expression.compile(expr)
    except ParseError as e:
        raise UsageError(f"{exc_message}: {expr}: {e}") from None