Esempio n. 1
0
    def __exit__(self, *exc_info):
        super(WarningsChecker, self).__exit__(*exc_info)

        __tracebackhide__ = True

        # only check if we're not currently handling an exception
        if all(a is None for a in exc_info):
            if self.expected_warning is not None:
                if not any(issubclass(r.category, self.expected_warning) for r in self):
                    __tracebackhide__ = True
                    fail(
                        "DID NOT WARN. No warnings of type {} was emitted. "
                        "The list of emitted warnings is: {}.".format(
                            self.expected_warning, [each.message for each in self]
                        )
                    )
                elif self.match_expr is not None:
                    for r in self:
                        if issubclass(r.category, self.expected_warning):
                            if re.compile(self.match_expr).search(str(r.message)):
                                break
                    else:
                        fail(
                            "DID NOT WARN. No warnings of type {} matching"
                            " ('{}') was emitted. The list of emitted warnings"
                            " is: {}.".format(
                                self.expected_warning,
                                self.match_expr,
                                [each.message for each in self],
                            )
                        )
Esempio n. 2
0
    def _resolve_arg_value_types(self, argnames, indirect):
        """Resolves if each parametrized argument must be considered a parameter to a fixture or a "funcarg"
        to the function, based on the ``indirect`` parameter of the parametrized() call.

        :param List[str] argnames: list of argument names passed to ``parametrize()``.
        :param indirect: same ``indirect`` parameter of ``parametrize()``.
        :rtype: Dict[str, str]
            A dict mapping each arg name to either:
            * "params" if the argname should be the parameter of a fixture of the same name.
            * "funcargs" if the argname should be a parameter to the parametrized test function.
        """
        valtypes = {}
        if indirect is True:
            valtypes = dict.fromkeys(argnames, "params")
        elif indirect is False:
            valtypes = dict.fromkeys(argnames, "funcargs")
        elif isinstance(indirect, (tuple, list)):
            valtypes = dict.fromkeys(argnames, "funcargs")
            for arg in indirect:
                if arg not in argnames:
                    fail(
                        "In {}: indirect fixture '{}' doesn't exist".format(
                            self.function.__name__, arg
                        ),
                        pytrace=False,
                    )
                valtypes[arg] = "params"
        return valtypes
Esempio n. 3
0
 def _istrue(self):
     if hasattr(self, 'result'):
         return self.result
     if self.holder:
         if self.holder.args or 'condition' in self.holder.kwargs:
             self.result = False
             # "holder" might be a MarkInfo or a MarkDecorator; only
             # MarkInfo keeps track of all parameters it received in an
             # _arglist attribute
             marks = getattr(self.holder, '_marks', None) \
                 or [self.holder.mark]
             for _, args, kwargs in marks:
                 if 'condition' in kwargs:
                     args = (kwargs['condition'],)
                 for expr in args:
                     self.expr = expr
                     if isinstance(expr, py.builtin._basestring):
                         d = self._getglobals()
                         result = cached_eval(self.item.config, expr, d)
                     else:
                         if "reason" not in kwargs:
                             # XXX better be checked at collection time
                             msg = "you need to specify reason=STRING " \
                                   "when using booleans as conditions."
                             fail(msg)
                         result = bool(expr)
                     if result:
                         self.result = True
                         self.reason = kwargs.get('reason', None)
                         self.expr = expr
                         return self.result
         else:
             self.result = True
     return getattr(self, 'result', False)
Esempio n. 4
0
    def addcall(self, funcargs=None, id=NOTSET, param=NOTSET):
        """ (deprecated, use parametrize) Add a new call to the underlying
        test function during the collection phase of a test run.  Note that
        request.addcall() is called during the test collection phase prior and
        independently to actual test execution.  You should only use addcall()
        if you need to specify multiple arguments of a test function.

        :arg funcargs: argument keyword dictionary used when invoking
            the test function.

        :arg id: used for reporting and identification purposes.  If you
            don't supply an `id` an automatic unique id will be generated.

        :arg param: a parameter which will be exposed to a later fixture function
            invocation through the ``request.param`` attribute.
        """
        assert funcargs is None or isinstance(funcargs, dict)
        if funcargs is not None:
            for name in funcargs:
                if name not in self.fixturenames:
                    fail("funcarg %r not used in this function." % name)
        else:
            funcargs = {}
        if id is None:
            raise ValueError("id=None not allowed")
        if id is NOTSET:
            id = len(self._calls)
        id = str(id)
        if id in self._ids:
            raise ValueError("duplicate id %r" % id)
        self._ids.add(id)

        cs = CallSpec2(self)
        cs.setall(funcargs, id, param)
        self._calls.append(cs)
Esempio n. 5
0
 def _addexcinfo(self, rawexcinfo):
     # unwrap potential exception info (see twisted trial support below)
     rawexcinfo = getattr(rawexcinfo, "_rawexcinfo", rawexcinfo)
     try:
         excinfo = _pytest._code.ExceptionInfo(rawexcinfo)
     except TypeError:
         try:
             try:
                 values = traceback.format_exception(*rawexcinfo)
                 values.insert(
                     0,
                     "NOTE: Incompatible Exception Representation, "
                     "displaying natively:\n\n",
                 )
                 fail("".join(values), pytrace=False)
             except (fail.Exception, KeyboardInterrupt):
                 raise
             except:  # noqa
                 fail(
                     "ERROR: Unknown Incompatible Exception "
                     "representation:\n%r" % (rawexcinfo,),
                     pytrace=False,
                 )
         except KeyboardInterrupt:
             raise
         except fail.Exception:
             excinfo = _pytest._code.ExceptionInfo()
     self.__dict__.setdefault("_excinfo", []).append(excinfo)
Esempio n. 6
0
    def __getattr__(self, name):
        if name[0] == "_":
            raise AttributeError("Marker name must NOT start with underscore")

        if self._config is not None:
            # We store a set of markers as a performance optimisation - if a mark
            # name is in the set we definitely know it, but a mark may be known and
            # not in the set.  We therefore start by updating the set!
            if name not in self._markers:
                for line in self._config.getini("markers"):
                    # example lines: "skipif(condition): skip the given test if..."
                    # or "hypothesis: tests which use Hypothesis", so to get the
                    # marker name we split on both `:` and `(`.
                    marker = line.split(":")[0].split("(")[0].strip()
                    self._markers.add(marker)

            # If the name is not in the set of known marks after updating,
            # then it really is time to issue a warning or an error.
            if name not in self._markers:
                if self._config.option.strict_markers:
                    fail(
                        "{!r} not found in `markers` configuration option".format(name),
                        pytrace=False,
                    )
                else:
                    warnings.warn(
                        "Unknown pytest.mark.%s - is this a typo?  You can register "
                        "custom marks to avoid this warning - for details, see "
                        "https://docs.pytest.org/en/latest/mark.html" % name,
                        PytestUnknownMarkWarning,
                    )

        return MarkDecorator(Mark(name, (), {}))
Esempio n. 7
0
    def _for_parametrize(cls, argnames, argvalues, func, config, function_definition):
        argnames, force_tuple = cls._parse_parametrize_args(argnames, argvalues)
        parameters = cls._parse_parametrize_parameters(argvalues, force_tuple)
        del argvalues

        if parameters:
            # check all parameter sets have the correct number of values
            for param in parameters:
                if len(param.values) != len(argnames):
                    msg = (
                        '{nodeid}: in "parametrize" the number of names ({names_len}):\n'
                        "  {names}\n"
                        "must be equal to the number of values ({values_len}):\n"
                        "  {values}"
                    )
                    fail(
                        msg.format(
                            nodeid=function_definition.nodeid,
                            values=param.values,
                            names=argnames,
                            names_len=len(argnames),
                            values_len=len(param.values),
                        ),
                        pytrace=False,
                    )
        else:
            # empty parameter set (likely computed at runtime): create a single
            # parameter set with NOTSET values, with the "empty parameter set" mark applied to it
            mark = get_empty_parameterset_mark(config, argnames, func)
            parameters.append(
                ParameterSet(values=(NOTSET,) * len(argnames), marks=[mark], id=None)
            )
        return argnames, parameters
Esempio n. 8
0
    def _validate_if_using_arg_names(self, argnames, indirect):
        """
        Check if all argnames are being used, by default values, or directly/indirectly.

        :param List[str] argnames: list of argument names passed to ``parametrize()``.
        :param indirect: same ``indirect`` parameter of ``parametrize()``.
        :raise ValueError: if validation fails.
        """
        default_arg_names = set(get_default_arg_names(self.function))
        func_name = self.function.__name__
        for arg in argnames:
            if arg not in self.fixturenames:
                if arg in default_arg_names:
                    fail(
                        "In {}: function already takes an argument '{}' with a default value".format(
                            func_name, arg
                        ),
                        pytrace=False,
                    )
                else:
                    if isinstance(indirect, (tuple, list)):
                        name = "fixture" if arg in indirect else "argument"
                    else:
                        name = "fixture" if indirect else "argument"
                    fail(
                        "In {}: function uses no {} '{}'".format(func_name, name, arg),
                        pytrace=False,
                    )
Esempio n. 9
0
    def _resolve_arg_ids(self, argnames, ids, parameters, item):
        """Resolves the actual ids for the given argnames, based on the ``ids`` parameter given
        to ``parametrize``.

        :param List[str] argnames: list of argument names passed to ``parametrize()``.
        :param ids: the ids parameter of the parametrized call (see docs).
        :param List[ParameterSet] parameters: the list of parameter values, same size as ``argnames``.
        :param Item item: the item that generated this parametrized call.
        :rtype: List[str]
        :return: the list of ids for each argname given
        """
        from py.io import saferepr

        idfn = None
        if callable(ids):
            idfn = ids
            ids = None
        if ids:
            func_name = self.function.__name__
            if len(ids) != len(parameters):
                msg = "In {}: {} parameter sets specified, with different number of ids: {}"
                fail(msg.format(func_name, len(parameters), len(ids)), pytrace=False)
            for id_value in ids:
                if id_value is not None and not isinstance(id_value, six.string_types):
                    msg = "In {}: ids must be list of strings, found: {} (type: {!r})"
                    fail(
                        msg.format(func_name, saferepr(id_value), type(id_value)),
                        pytrace=False,
                    )
        ids = idmaker(argnames, parameters, idfn, ids, self.config, item=item)
        return ids
Esempio n. 10
0
def pytest_generate_tests(metafunc):
    # those alternative spellings are common - raise a specific error to alert
    # the user
    alt_spellings = ["parameterize", "parametrise", "parameterise"]
    for mark_name in alt_spellings:
        if metafunc.definition.get_closest_marker(mark_name):
            msg = "{0} has '{1}' mark, spelling should be 'parametrize'"
            fail(msg.format(metafunc.function.__name__, mark_name), pytrace=False)
    for marker in metafunc.definition.iter_markers(name="parametrize"):
        metafunc.parametrize(*marker.args, **marker.kwargs)
Esempio n. 11
0
def check_strict_xfail(pyfuncitem):
    """check xfail(strict=True) for the given PASSING test"""
    evalxfail = pyfuncitem._evalxfail
    if evalxfail.istrue():
        strict_default = pyfuncitem.config.getini("xfail_strict")
        is_strict_xfail = evalxfail.get("strict", strict_default)
        if is_strict_xfail:
            del pyfuncitem._evalxfail
            explanation = evalxfail.getexplanation()
            fail("[XPASS(strict)] " + explanation, pytrace=False)
Esempio n. 12
0
    def _getfixturevalue(self, fixturedef):
        # prepare a subrequest object before calling fixture function
        # (latter managed by fixturedef)
        argname = fixturedef.argname
        funcitem = self._pyfuncitem
        scope = fixturedef.scope
        try:
            param = funcitem.callspec.getparam(argname)
        except (AttributeError, ValueError):
            param = NOTSET
            param_index = 0
            if fixturedef.params is not None:
                frame = inspect.stack()[3]
                frameinfo = inspect.getframeinfo(frame[0])
                source_path = frameinfo.filename
                source_lineno = frameinfo.lineno
                source_path = py.path.local(source_path)
                if source_path.relto(funcitem.config.rootdir):
                    source_path = source_path.relto(funcitem.config.rootdir)
                msg = (
                    "The requested fixture has no parameter defined for the "
                    "current test.\n\nRequested fixture '{0}' defined in:\n{1}"
                    "\n\nRequested here:\n{2}:{3}".format(
                        fixturedef.argname,
                        getlocation(fixturedef.func, funcitem.config.rootdir),
                        source_path,
                        source_lineno,
                    )
                )
                fail(msg)
        else:
            # indices might not be set if old-style metafunc.addcall() was used
            param_index = funcitem.callspec.indices.get(argname, 0)
            # if a parametrize invocation set a scope it will override
            # the static scope defined with the fixture function
            paramscopenum = funcitem.callspec._arg2scopenum.get(argname)
            if paramscopenum is not None:
                scope = scopes[paramscopenum]

        subrequest = SubRequest(self, scope, param, param_index, fixturedef)

        # check if a higher-level scoped fixture accesses a lower level one
        subrequest._check_scope(argname, self.scope, scope)

        # clear sys.exc_info before invoking the fixture (python bug?)
        # if its not explicitly cleared it will leak into the call
        exc_clear()
        try:
            # call the fixture function
            val = fixturedef.execute(request=subrequest)
        finally:
            # if fixture function failed it might have registered finalizers
            self.session._setupstate.addfinalizer(fixturedef.finish,
                                                  subrequest.node)
        return val
Esempio n. 13
0
def getfuncargnames(function: Callable[..., Any],
                    *,
                    name: str = "",
                    is_method: bool = False,
                    cls: Optional[type] = None) -> Tuple[str, ...]:
    """Return the names of a function's mandatory arguments.

    Should return the names of all function arguments that:
    * Aren't bound to an instance or type as in instance or class methods.
    * Don't have default values.
    * Aren't bound with functools.partial.
    * Aren't replaced with mocks.

    The is_method and cls arguments indicate that the function should
    be treated as a bound method even though it's not unless, only in
    the case of cls, the function is a static method.

    The name parameter should be the original name in which the function was collected.
    """
    # TODO(RonnyPfannschmidt): This function should be refactored when we
    # revisit fixtures. The fixture mechanism should ask the node for
    # the fixture names, and not try to obtain directly from the
    # function object well after collection has occurred.

    # The parameters attribute of a Signature object contains an
    # ordered mapping of parameter names to Parameter instances.  This
    # creates a tuple of the names of the parameters that don't have
    # defaults.
    try:
        parameters = signature(function).parameters
    except (ValueError, TypeError) as e:
        fail(
            "Could not determine arguments of {!r}: {}".format(function, e),
            pytrace=False,
        )

    arg_names = tuple(p.name for p in parameters.values() if (
        # TODO: Remove type ignore after https://github.com/python/typeshed/pull/4383
        p.kind is Parameter.POSITIONAL_OR_KEYWORD  # type: ignore[unreachable]
        or p.kind is Parameter.KEYWORD_ONLY  # type: ignore[unreachable]
    ) and p.default is Parameter.empty)
    if not name:
        name = function.__name__

    # If this function should be treated as a bound method even though
    # it's passed as an unbound method or function, remove the first
    # parameter name.
    if is_method or (cls and not isinstance(cls.__dict__.get(name, None),
                                            staticmethod)):
        arg_names = arg_names[1:]
    # Remove any names that will be replaced with mocks.
    if hasattr(function, "__wrapped__"):
        arg_names = arg_names[num_mock_patch_args(function):]
    return arg_names
Esempio n. 14
0
 def _check_scope(self, argname, invoking_scope, requested_scope):
     if argname == "request":
         return
     if scopemismatch(invoking_scope, requested_scope):
         # try to report something helpful
         lines = self._factorytraceback()
         fail("ScopeMismatch: You tried to access the %r scoped "
              "fixture %r with a %r scoped request object, "
              "involved factories\n%s" % (
                  (requested_scope, argname, invoking_scope, "\n".join(lines))),
              pytrace=False)
Esempio n. 15
0
 def __exit__(self, *tp):
     __tracebackhide__ = True
     if tp[0] is None:
         fail(self.message)
     self.excinfo.__init__(tp)
     suppress_exception = issubclass(self.excinfo.type, self.expected_exception)
     if sys.version_info[0] == 2 and suppress_exception:
         sys.exc_clear()
     if self.match_expr and suppress_exception:
         self.excinfo.match(self.match_expr)
     return suppress_exception
Esempio n. 16
0
def _fail_on_non_top_pytest_plugins(conftestpath, confcutdir):
    msg = (
        "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported:\n"
        "It affects the entire test suite instead of just below the conftest as expected.\n"
        "  {}\n"
        "Please move it to a top level conftest file at the rootdir:\n"
        "  {}\n"
        "For more information, visit:\n"
        "  https://docs.pytest.org/en/latest/deprecations.html#pytest-plugins-in-non-top-level-conftest-files"
    )
    fail(msg.format(conftestpath, confcutdir), pytrace=False)
Esempio n. 17
0
 def inner(**kwargs):
     gen = func(**kwargs)
     future = event_loop.run_in_executor(None, lambda: next(gen))
     run_until_complete(event_loop, future)
     on_shutdown()
     try:
         next(gen)
     except StopIteration:
         return
     fail(
         'launch tests using a generator function must stop iteration after yielding once',
         pytrace=False)
Esempio n. 18
0
 def shutdown():
     nonlocal gen
     if gen is None:
         skip('shutdown test skipped because the test failed before')
     on_shutdown()
     try:
         next(gen)
     except StopIteration:
         return
     fail(
         'launch tests using a generator function must stop iteration after yielding once',
         pytrace=False)
Esempio n. 19
0
def scope2index(scope, descr, where=None):
    """Look up the index of ``scope`` and raise a descriptive value error
    if not defined.
    """
    try:
        return scopes.index(scope)
    except ValueError:
        fail(
            "{} {}got an unexpected scope value '{}'".format(
                descr, "from {} ".format(where) if where else "", scope),
            pytrace=False,
        )
Esempio n. 20
0
 def _check_scope(self, argname, invoking_scope, requested_scope):
     if argname == "request":
         return
     if scopemismatch(invoking_scope, requested_scope):
         # try to report something helpful
         lines = self._factorytraceback()
         fail(
             "ScopeMismatch: You tried to access the %r scoped "
             "fixtures %r with a %r scoped request object, "
             "involved factories\n%s" %
             ((requested_scope, argname, invoking_scope, "\n".join(lines))),
             pytrace=False)
Esempio n. 21
0
 def __exit__(self, *tp):
     __tracebackhide__ = True
     if tp[0] is None:
         fail(self.message)
     self.excinfo.__init__(tp)
     suppress_exception = issubclass(self.excinfo.type,
                                     self.expected_exception)
     if sys.version_info[0] == 2 and suppress_exception:
         sys.exc_clear()
     if self.match_expr and suppress_exception:
         self.excinfo.match(self.match_expr)
     return suppress_exception
Esempio n. 22
0
def load_config_dict_from_file(
    filepath: Path, ) -> Optional[Dict[str, Union[str, List[str]]]]:
    """Load pytest configuration from the given file path, if supported.

    Return None if the file does not contain valid pytest configuration.
    """

    # Configuration from ini files are obtained from the [pytest] section, if present.
    if filepath.suffix == ".ini":
        iniconfig = _parse_ini_config(filepath)

        if "pytest" in iniconfig:
            return dict(iniconfig["pytest"].items())
        else:
            # "pytest.ini" files are always the source of configuration, even if empty.
            if filepath.name == "pytest.ini":
                return {}

    # '.cfg' files are considered if they contain a "[tool:pytest]" section.
    elif filepath.suffix == ".cfg":
        iniconfig = _parse_ini_config(filepath)

        if "tool:pytest" in iniconfig.sections:
            return dict(iniconfig["tool:pytest"].items())
        elif "pytest" in iniconfig.sections:
            # If a setup.cfg contains a "[pytest]" section, we raise a failure to indicate users that
            # plain "[pytest]" sections in setup.cfg files is no longer supported (#3086).
            fail(CFG_PYTEST_SECTION.format(filename="setup.cfg"),
                 pytrace=False)

    # '.toml' files are considered if they contain a [tool.pytest.ini_options] table.
    elif filepath.suffix == ".toml":
        import tomli

        toml_text = filepath.read_text(encoding="utf-8")
        try:
            config = tomli.loads(toml_text)
        except tomli.TOMLDecodeError as exc:
            raise UsageError(str(exc)) from exc

        result = config.get("tool", {}).get("pytest",
                                            {}).get("ini_options", None)
        if result is not None:
            # TOML supports richer data types than ini files (strings, arrays, floats, ints, etc),
            # however we need to convert all scalar values to str for compatibility with the rest
            # of the configuration system, which expects strings only.
            def make_scalar(v: object) -> Union[str, List[str]]:
                return v if isinstance(v, list) else str(v)

            return {k: make_scalar(v) for k, v in result.items()}

    return None
Esempio n. 23
0
def determine_setup(
    inifile: str,
    args: List[str],
    rootdir_cmd_arg: Optional[str] = None,
    config: Optional["Config"] = None,
):
    dirs = get_dirs_from_args(args)
    if inifile:
        iniconfig = py.iniconfig.IniConfig(inifile)
        is_cfg_file = str(inifile).endswith(".cfg")
        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 config is not None:
                    fail(
                        CFG_PYTEST_SECTION.format(filename=str(inifile)), pytrace=False
                    )
                break
            except KeyError:
                inicfg = None
        if rootdir_cmd_arg is None:
            rootdir = get_common_ancestor(dirs)
    else:
        ancestor = get_common_ancestor(dirs)
        rootdir, inifile, inicfg = getcfg([ancestor], config=config)
        if rootdir is None and rootdir_cmd_arg is None:
            for possible_rootdir in ancestor.parts(reverse=True):
                if possible_rootdir.join("setup.py").exists():
                    rootdir = possible_rootdir
                    break
            else:
                if dirs != [ancestor]:
                    rootdir, inifile, inicfg = getcfg(dirs, config=config)
                if rootdir is None:
                    if config is not None:
                        cwd = config.invocation_dir
                    else:
                        cwd = py.path.local()
                    rootdir = get_common_ancestor([cwd, ancestor])
                    is_fs_root = os.path.splitdrive(str(rootdir))[1] == "/"
                    if is_fs_root:
                        rootdir = ancestor
    if rootdir_cmd_arg:
        rootdir = py.path.local(os.path.expandvars(rootdir_cmd_arg))
        if not rootdir.isdir():
            raise UsageError(
                "Directory '{}' not found. Check your '--rootdir' option.".format(
                    rootdir
                )
            )
    return rootdir, inifile, inicfg or {}
Esempio n. 24
0
def scope2index(scope, descr, where=None):
    """Look up the index of ``scope`` and raise a descriptive value error
    if not defined.
    """
    try:
        return scopes.index(scope)
    except ValueError:
        fail(
            "{} {}got an unexpected scope value '{}'".format(
                descr, "from {} ".format(where) if where else "", scope
            ),
            pytrace=False,
        )
Esempio n. 25
0
    def __exit__(self, *exc_info):
        super(WarningsChecker, self).__exit__(*exc_info)

        # only check if we're not currently handling an exception
        if all(a is None for a in exc_info):
            if self.expected_warning is not None:
                if not any(issubclass(r.category, self.expected_warning)
                           for r in self):
                    __tracebackhide__ = True
                    fail("DID NOT WARN. No warnings of type {0} was emitted. "
                         "The list of emitted warnings is: {1}.".format(
                             self.expected_warning,
                             [each.message for each in self]))
Esempio n. 26
0
 def _check_non_top_pytest_plugins(self, mod, conftestpath):
     if (hasattr(mod, "pytest_plugins") and self._configured
             and not self._using_pyargs):
         msg = (
             "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported:\n"
             "It affects the entire test suite instead of just below the conftest as expected.\n"
             "  {}\n"
             "Please move it to a top level conftest file at the rootdir:\n"
             "  {}\n"
             "For more information, visit:\n"
             "  https://docs.pytest.org/en/latest/deprecations.html#pytest-plugins-in-non-top-level-conftest-files"
         )
         fail(msg.format(conftestpath, self._confcutdir), pytrace=False)
Esempio n. 27
0
 def addUnexpectedSuccess(
     self,
     testcase: "unittest.TestCase",
     reason: Optional["twisted.trial.unittest.Todo"] = None,
 ) -> None:
     msg = "Unexpected success"
     if reason:
         msg += f": {reason.reason}"
     # Preserve unittest behaviour - fail the test. Explicitly not an XPASS.
     try:
         fail(msg, pytrace=False)
     except fail.Exception:
         self._addexcinfo(sys.exc_info())
Esempio n. 28
0
def getfuncargnames(function, is_method=False, cls=None):
    """Returns the names of a function's mandatory arguments.

    This should return the names of all function arguments that:
        * Aren't bound to an instance or type as in instance or class methods.
        * Don't have default values.
        * Aren't bound with functools.partial.
        * Aren't replaced with mocks.

    The is_method and cls arguments indicate that the function should
    be treated as a bound method even though it's not unless, only in
    the case of cls, the function is a static method.

    @RonnyPfannschmidt: This function should be refactored when we
    revisit fixtures. The fixture mechanism should ask the node for
    the fixture names, and not try to obtain directly from the
    function object well after collection has occurred.

    """
    # The parameters attribute of a Signature object contains an
    # ordered mapping of parameter names to Parameter instances.  This
    # creates a tuple of the names of the parameters that don't have
    # defaults.
    try:
        parameters = signature(function).parameters
    except (ValueError, TypeError) as e:
        fail(
            "Could not determine arguments of {!r}: {}".format(function, e),
            pytrace=False,
        )

    arg_names = tuple(
        p.name
        for p in parameters.values()
        if (
            p.kind is Parameter.POSITIONAL_OR_KEYWORD
            or p.kind is Parameter.KEYWORD_ONLY
        )
        and p.default is Parameter.empty
    )
    # If this function should be treated as a bound method even though
    # it's passed as an unbound method or function, remove the first
    # parameter name.
    if is_method or (
        cls and not isinstance(cls.__dict__.get(function.__name__, None), staticmethod)
    ):
        arg_names = arg_names[1:]
    # Remove any names that will be replaced with mocks.
    if hasattr(function, "__wrapped__"):
        arg_names = arg_names[num_mock_patch_args(function) :]
    return arg_names
Esempio n. 29
0
def getfuncargnames(function, is_method=False, cls=None):
    """Returns the names of a function's mandatory arguments.

    This should return the names of all function arguments that:
        * Aren't bound to an instance or type as in instance or class methods.
        * Don't have default values.
        * Aren't bound with functools.partial.
        * Aren't replaced with mocks.

    The is_method and cls arguments indicate that the function should
    be treated as a bound method even though it's not unless, only in
    the case of cls, the function is a static method.

    @RonnyPfannschmidt: This function should be refactored when we
    revisit fixtures. The fixture mechanism should ask the node for
    the fixture names, and not try to obtain directly from the
    function object well after collection has occurred.

    """
    # The parameters attribute of a Signature object contains an
    # ordered mapping of parameter names to Parameter instances.  This
    # creates a tuple of the names of the parameters that don't have
    # defaults.
    try:
        parameters = signature(function).parameters
    except (ValueError, TypeError) as e:
        fail(
            "Could not determine arguments of {!r}: {}".format(function, e),
            pytrace=False,
        )

    arg_names = tuple(
        p.name
        for p in parameters.values()
        if (
            p.kind is Parameter.POSITIONAL_OR_KEYWORD
            or p.kind is Parameter.KEYWORD_ONLY
        )
        and p.default is Parameter.empty
    )
    # If this function should be treated as a bound method even though
    # it's passed as an unbound method or function, remove the first
    # parameter name.
    if is_method or (
        cls and not isinstance(cls.__dict__.get(function.__name__, None), staticmethod)
    ):
        arg_names = arg_names[1:]
    # Remove any names that will be replaced with mocks.
    if hasattr(function, "__wrapped__"):
        arg_names = arg_names[num_mock_patch_args(function) :]
    return arg_names
Esempio n. 30
0
 def shutdown(**kwargs):
     nonlocal agen
     if agen is None:
         skip('shutdown test skipped because the test failed before')
     on_shutdown()
     try:
         coro = agen.__anext__()
         task = asyncio.ensure_future(coro, loop=event_loop)
         run_until_complete(event_loop, task)
     except StopAsyncIteration:
         return
     fail(
         'launch tests using an async gen function must stop iteration after yielding once',
         pytrace=False)
Esempio n. 31
0
 def _check(self, name):
     try:
         if name in self._markers:
             return
     except AttributeError:
         pass
     self._markers = values = set()
     for line in self._config.getini("markers"):
         marker = line.split(":", 1)[0]
         marker = marker.rstrip()
         x = marker.split("(", 1)[0]
         values.add(x)
     if name not in self._markers:
         fail("{!r} not a registered marker".format(name), pytrace=False)
Esempio n. 32
0
 def _check(self, name):
     try:
         if name in self._markers:
             return
     except AttributeError:
         pass
     self._markers = values = set()
     for line in self._config.getini("markers"):
         marker = line.split(":", 1)[0]
         marker = marker.rstrip()
         x = marker.split("(", 1)[0]
         values.add(x)
     if name not in self._markers:
         fail("{!r} not a registered marker".format(name), pytrace=False)
Esempio n. 33
0
def determine_setup(inifile, args, rootdir_cmd_arg=None, config=None):
    dirs = get_dirs_from_args(args)
    if inifile:
        iniconfig = py.iniconfig.IniConfig(inifile)
        is_cfg_file = str(inifile).endswith(".cfg")
        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 config is not None:
                    from _pytest.deprecated import CFG_PYTEST_SECTION

                    fail(
                        CFG_PYTEST_SECTION.format(filename=str(inifile)), pytrace=False
                    )
                break
            except KeyError:
                inicfg = None
        if rootdir_cmd_arg is None:
            rootdir = get_common_ancestor(dirs)
    else:
        ancestor = get_common_ancestor(dirs)
        rootdir, inifile, inicfg = getcfg([ancestor], config=config)
        if rootdir is None and rootdir_cmd_arg is None:
            for possible_rootdir in ancestor.parts(reverse=True):
                if possible_rootdir.join("setup.py").exists():
                    rootdir = possible_rootdir
                    break
            else:
                if dirs != [ancestor]:
                    rootdir, inifile, inicfg = getcfg(dirs, config=config)
                if rootdir is None:
                    if config is not None:
                        cwd = config.invocation_dir
                    else:
                        cwd = py.path.local()
                    rootdir = get_common_ancestor([cwd, ancestor])
                    is_fs_root = os.path.splitdrive(str(rootdir))[1] == "/"
                    if is_fs_root:
                        rootdir = ancestor
    if rootdir_cmd_arg:
        rootdir = py.path.local(os.path.expandvars(rootdir_cmd_arg))
        if not rootdir.isdir():
            raise UsageError(
                "Directory '{}' not found. Check your '--rootdir' option.".format(
                    rootdir
                )
            )
    return rootdir, inifile, inicfg or {}
Esempio n. 34
0
 def istrue(self):
     try:
         return self._istrue()
     except TEST_OUTCOME:
         self.exc = sys.exc_info()
         if isinstance(self.exc[1], SyntaxError):
             msg = [" " * (self.exc[1].offset + 4) + "^", ]
             msg.append("SyntaxError: invalid syntax")
         else:
             msg = traceback.format_exception_only(*self.exc[:2])
         fail("Error evaluating %r expression\n"
              "    %s\n"
              "%s"
              % (self.name, self.expr, "\n".join(msg)),
              pytrace=False)
Esempio n. 35
0
 def inner(**kwargs):
     agen = func(**kwargs)
     coro = agen.__anext__()
     task = asyncio.ensure_future(coro, loop=event_loop)
     run_until_complete(event_loop, task)
     on_shutdown()
     try:
         coro = agen.__anext__()
         task = asyncio.ensure_future(coro, loop=event_loop)
         run_until_complete(event_loop, task)
     except StopAsyncIteration:
         return
     fail(
         'launch tests using an async gen function must stop iteration after yielding once',
         pytrace=False)
Esempio n. 36
0
    def __getattr__(self, name: str) -> MarkDecorator:
        """Generate a new :class:`MarkDecorator` with the given name."""
        if name[0] == "_":
            raise AttributeError("Marker name must NOT start with underscore")

        if self._config is not None:
            # We store a set of markers as a performance optimisation - if a mark
            # name is in the set we definitely know it, but a mark may be known and
            # not in the set.  We therefore start by updating the set!
            if name not in self._markers:
                for line in self._config.getini("markers"):
                    # example lines: "skipif(condition): skip the given test if..."
                    # or "hypothesis: tests which use Hypothesis", so to get the
                    # marker name we split on both `:` and `(`.
                    if line == "ya:external":
                        marker = line
                    else:
                        marker = line.split(":")[0].split("(")[0].strip()
                    self._markers.add(marker)

            # If the name is not in the set of known marks after updating,
            # then it really is time to issue a warning or an error.
            if name not in self._markers:
                if self._config.option.strict_markers or self._config.option.strict:
                    fail(
                        f"{name!r} not found in `markers` configuration option",
                        pytrace=False,
                    )

                # Raise a specific error for common misspellings of "parametrize".
                if name in ["parameterize", "parametrise", "parameterise"]:
                    __tracebackhide__ = True
                    fail(f"Unknown '{name}' mark, did you mean 'parametrize'?")

                warnings.warn(
                    "Unknown pytest.mark.%s - is this a typo?  You can register "
                    "custom marks to avoid this warning - for details, see "
                    "https://docs.pytest.org/en/stable/how-to/mark.html" %
                    name,
                    PytestUnknownMarkWarning,
                    2,
                )

        return MarkDecorator(Mark(name, (), {}, _ispytest=True),
                             _ispytest=True)
Esempio n. 37
0
 def __exit__(
     self,
     exc_type: Optional[Type[BaseException]],
     exc_val: Optional[BaseException],
     exc_tb: Optional[TracebackType],
 ) -> bool:
     __tracebackhide__ = True
     if exc_type is None:
         fail(self.message)
     assert self.excinfo is not None
     if not issubclass(exc_type, self.expected_exception):
         return False
     # Cast to narrow the exception type now that it's verified.
     exc_info = cast(Tuple[Type[E], E, TracebackType], (exc_type, exc_val, exc_tb))
     self.excinfo.fill_unfilled(exc_info)
     if self.match_expr is not None:
         self.excinfo.match(self.match_expr)
     return True
Esempio n. 38
0
 def __exit__(self, *tp):
     __tracebackhide__ = True
     if tp[0] is None:
         fail(self.message)
     if sys.version_info < (2, 7):
         # py26: on __exit__() exc_value often does not contain the
         # exception value.
         # http://bugs.python.org/issue7853
         if not isinstance(tp[1], BaseException):
             exc_type, value, traceback = tp
             tp = exc_type, exc_type(value), traceback
     self.excinfo.__init__(tp)
     suppress_exception = issubclass(self.excinfo.type, self.expected_exception)
     if sys.version_info[0] == 2 and suppress_exception:
         sys.exc_clear()
     if self.match_expr:
         self.excinfo.match(self.match_expr)
     return suppress_exception
Esempio n. 39
0
    def __exit__(self, *tp):
        from _pytest.outcomes import fail

        if ppg.inside_ppg():
            with pytest.raises(ppg.RuntimeError) as e:
                run_pipegraph()
            assert isinstance(e.value.exceptions[0], self.expected_exception)
            if self.search_message:
                assert self.search_message in str(e.value.exceptions[0])
        else:
            __tracebackhide__ = True
            if tp[0] is None:
                fail(self.message)
            self.excinfo.__init__(tp)
            suppress_exception = issubclass(self.excinfo.type,
                                            self.expected_exception)
            if sys.version_info[0] == 2 and suppress_exception:
                sys.exc_clear()
            return suppress_exception
Esempio n. 40
0
    def _validate_plugins(self) -> None:
        required_plugins = sorted(self.getini("required_plugins"))
        if not required_plugins:
            return

        plugin_info = self.pluginmanager.list_plugin_distinfo()
        plugin_dist_names = [dist.project_name for _, dist in plugin_info]

        missing_plugins = []
        for plugin in required_plugins:
            if plugin not in plugin_dist_names:
                missing_plugins.append(plugin)

        if missing_plugins:
            fail(
                "Missing required plugins: {}".format(
                    ", ".join(missing_plugins)),
                pytrace=False,
            )
Esempio n. 41
0
    def addcall(self, funcargs=None, id=NOTSET, param=NOTSET):
        """ Add a new call to the underlying test function during the collection phase of a test run.

        .. deprecated:: 3.3

            Use :meth:`parametrize` instead.

        Note that request.addcall() is called during the test collection phase prior and
        independently to actual test execution.  You should only use addcall()
        if you need to specify multiple arguments of a test function.

        :arg funcargs: argument keyword dictionary used when invoking
            the test function.

        :arg id: used for reporting and identification purposes.  If you
            don't supply an `id` an automatic unique id will be generated.

        :arg param: a parameter which will be exposed to a later fixture function
            invocation through the ``request.param`` attribute.
        """
        if self.config:
            self.config.warn(
                "C1", message=deprecated.METAFUNC_ADD_CALL, fslocation=None
            )
        assert funcargs is None or isinstance(funcargs, dict)
        if funcargs is not None:
            for name in funcargs:
                if name not in self.fixturenames:
                    fail("funcarg %r not used in this function." % name)
        else:
            funcargs = {}
        if id is None:
            raise ValueError("id=None not allowed")
        if id is NOTSET:
            id = len(self._calls)
        id = str(id)
        if id in self._ids:
            raise ValueError("duplicate id %r" % id)
        self._ids.add(id)

        cs = CallSpec2(self)
        cs.setall(funcargs, id, param)
        self._calls.append(cs)
Esempio n. 42
0
    def from_user(cls,
                  scope_name: "_ScopeName",
                  descr: str,
                  where: Optional[str] = None) -> "Scope":
        """
        Given a scope name from the user, return the equivalent Scope enum. Should be used
        whenever we want to convert a user provided scope name to its enum object.

        If the scope name is invalid, construct a user friendly message and call pytest.fail.
        """
        from _pytest.outcomes import fail

        try:
            return Scope(scope_name)
        except ValueError:
            fail(
                "{} {}got an unexpected scope value '{}'".format(
                    descr, f"from {where} " if where else "", scope_name),
                pytrace=False,
            )
Esempio n. 43
0
def test_convert(converter, stasis_cli, conv_queue, raw_files):
    raw_folder = 'd:\\tmp/'

    try:
        for f in raw_files:
            print(f'adding {raw_folder + f} to queue', flush=True)
            stasis_cli.add_sample_to_convert(raw_folder + f)

        time.sleep(5)

        converter.convert(args={})  # args are not used

        converted = glob.glob(raw_folder + '*.mzml')
        assert len(converted) == len(raw_files)

    except Exception as ex:
        boto3.client('sqs').purge_queue(QueueUrl=conv_queue)
        fail()
    finally:
        [os.remove(d) for d in glob.glob(raw_folder + '*.mzml')]
Esempio n. 44
0
    def _for_parametrize(
        cls,
        argnames: Union[str, List[str], Tuple[str, ...]],
        argvalues: Iterable[Union["ParameterSet", Sequence[object], object]],
        func,
        config: Config,
        nodeid: str,
    ) -> Tuple[Union[List[str], Tuple[str, ...]], List["ParameterSet"]]:
        argnames, force_tuple = cls._parse_parametrize_args(
            argnames, argvalues)
        parameters = cls._parse_parametrize_parameters(argvalues, force_tuple)
        del argvalues

        if parameters:
            # Check all parameter sets have the correct number of values.
            for param in parameters:
                if len(param.values) != len(argnames):
                    msg = (
                        '{nodeid}: in "parametrize" the number of names ({names_len}):\n'
                        "  {names}\n"
                        "must be equal to the number of values ({values_len}):\n"
                        "  {values}")
                    fail(
                        msg.format(
                            nodeid=nodeid,
                            values=param.values,
                            names=argnames,
                            names_len=len(argnames),
                            values_len=len(param.values),
                        ),
                        pytrace=False,
                    )
        else:
            # Empty parameter set (likely computed at runtime): create a single
            # parameter set with NOTSET values, with the "empty parameter set" mark applied to it.
            mark = get_empty_parameterset_mark(config, argnames, func)
            parameters.append(
                ParameterSet(values=(NOTSET, ) * len(argnames),
                             marks=[mark],
                             id=None))
        return argnames, parameters
Esempio n. 45
0
    def _for_parametrize(cls, argnames, argvalues, func, config,
                         function_definition):
        if not isinstance(argnames, (tuple, list)):
            argnames = [x.strip() for x in argnames.split(",") if x.strip()]
            force_tuple = len(argnames) == 1
        else:
            force_tuple = False
        parameters = [
            ParameterSet.extract_from(x, force_tuple=force_tuple)
            for x in argvalues
        ]
        del argvalues

        if parameters:
            # check all parameter sets have the correct number of values
            for param in parameters:
                if len(param.values) != len(argnames):
                    msg = (
                        '{nodeid}: in "parametrize" the number of names ({names_len}):\n'
                        "  {names}\n"
                        "must be equal to the number of values ({values_len}):\n"
                        "  {values}")
                    fail(
                        msg.format(
                            nodeid=function_definition.nodeid,
                            values=param.values,
                            names=argnames,
                            names_len=len(argnames),
                            values_len=len(param.values),
                        ),
                        pytrace=False,
                    )
        else:
            # empty parameter set (likely computed at runtime): create a single
            # parameter set with NOSET values, with the "empty parameter set" mark applied to it
            mark = get_empty_parameterset_mark(config, argnames, func)
            parameters.append(
                ParameterSet(values=(NOTSET, ) * len(argnames),
                             marks=[mark],
                             id=None))
        return argnames, parameters
Esempio n. 46
0
def getcfg(args, config=None):
    """
    Search the list of arguments for a valid ini-file for pytest,
    and return a tuple of (rootdir, inifile, cfg-dict).

    note: config is optional and used only to issue warnings explicitly (#2891).
    """
    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):
                    try:
                        iniconfig = py.iniconfig.IniConfig(p)
                    except py.iniconfig.ParseError as exc:
                        raise UsageError(str(exc))

                    if (inibasename == "setup.cfg"
                            and "tool:pytest" in iniconfig.sections):
                        return base, p, iniconfig["tool:pytest"]
                    elif "pytest" in iniconfig.sections:
                        if inibasename == "setup.cfg" and config is not None:

                            fail(
                                CFG_PYTEST_SECTION.format(
                                    filename=inibasename),
                                pytrace=False,
                            )
                        return base, p, iniconfig["pytest"]
                    elif inibasename == "pytest.ini":
                        # allowed to be empty
                        return base, p, {}
    return None, None, None
Esempio n. 47
0
    def _for_parametrize(cls, argnames, argvalues, func, config, function_definition):
        if not isinstance(argnames, (tuple, list)):
            argnames = [x.strip() for x in argnames.split(",") if x.strip()]
            force_tuple = len(argnames) == 1
        else:
            force_tuple = False
        parameters = [
            ParameterSet.extract_from(x, force_tuple=force_tuple) for x in argvalues
        ]
        del argvalues

        if parameters:
            # check all parameter sets have the correct number of values
            for param in parameters:
                if len(param.values) != len(argnames):
                    msg = (
                        '{nodeid}: in "parametrize" the number of names ({names_len}):\n'
                        "  {names}\n"
                        "must be equal to the number of values ({values_len}):\n"
                        "  {values}"
                    )
                    fail(
                        msg.format(
                            nodeid=function_definition.nodeid,
                            values=param.values,
                            names=argnames,
                            names_len=len(argnames),
                            values_len=len(param.values),
                        ),
                        pytrace=False,
                    )
        else:
            # empty parameter set (likely computed at runtime): create a single
            # parameter set with NOSET values, with the "empty parameter set" mark applied to it
            mark = get_empty_parameterset_mark(config, argnames, func)
            parameters.append(
                ParameterSet(values=(NOTSET,) * len(argnames), marks=[mark], id=None)
            )
        return argnames, parameters
Esempio n. 48
0
 def _addexcinfo(self, rawexcinfo):
     # unwrap potential exception info (see twisted trial support below)
     rawexcinfo = getattr(rawexcinfo, '_rawexcinfo', rawexcinfo)
     try:
         excinfo = _pytest._code.ExceptionInfo(rawexcinfo)
     except TypeError:
         try:
             try:
                 l = traceback.format_exception(*rawexcinfo)
                 l.insert(0, "NOTE: Incompatible Exception Representation, "
                             "displaying natively:\n\n")
                 fail("".join(l), pytrace=False)
             except (fail.Exception, KeyboardInterrupt):
                 raise
             except:
                 fail("ERROR: Unknown Incompatible Exception "
                      "representation:\n%r" % (rawexcinfo,), pytrace=False)
         except KeyboardInterrupt:
             raise
         except fail.Exception:
             excinfo = _pytest._code.ExceptionInfo()
     self.__dict__.setdefault('_excinfo', []).append(excinfo)
Esempio n. 49
0
    def _importconftest(self, conftestpath):
        try:
            return self._conftestpath2mod[conftestpath]
        except KeyError:
            pkgpath = conftestpath.pypkgpath()
            if pkgpath is None:
                _ensure_removed_sysmodule(conftestpath.purebasename)
            try:
                mod = conftestpath.pyimport()
                if (
                    hasattr(mod, "pytest_plugins")
                    and self._configured
                    and not self._using_pyargs
                ):
                    from _pytest.deprecated import (
                        PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST,
                    )

                    fail(
                        PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST.format(
                            conftestpath, self._confcutdir
                        ),
                        pytrace=False,
                    )
            except Exception:
                raise ConftestImportFailure(conftestpath, sys.exc_info())

            self._conftest_plugins.add(mod)
            self._conftestpath2mod[conftestpath] = mod
            dirpath = conftestpath.dirpath()
            if dirpath in self._dirpath2confmods:
                for path, mods in self._dirpath2confmods.items():
                    if path and path.relto(dirpath) or path == dirpath:
                        assert mod not in mods
                        mods.append(mod)
            self.trace("loaded conftestmodule %r" % (mod))
            self.consider_conftest(mod)
            return mod
Esempio n. 50
0
    def _importconftest(self, conftestpath):
        try:
            return self._conftestpath2mod[conftestpath]
        except KeyError:
            pkgpath = conftestpath.pypkgpath()
            if pkgpath is None:
                _ensure_removed_sysmodule(conftestpath.purebasename)
            try:
                mod = conftestpath.pyimport()
                if (
                    hasattr(mod, "pytest_plugins")
                    and self._configured
                    and not self._using_pyargs
                ):
                    from _pytest.deprecated import (
                        PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST,
                    )

                    fail(
                        PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST.format(
                            conftestpath, self._confcutdir
                        ),
                        pytrace=False,
                    )
            except Exception:
                raise ConftestImportFailure(conftestpath, sys.exc_info())

            self._conftest_plugins.add(mod)
            self._conftestpath2mod[conftestpath] = mod
            dirpath = conftestpath.dirpath()
            if dirpath in self._dirpath2confmods:
                for path, mods in self._dirpath2confmods.items():
                    if path and path.relto(dirpath) or path == dirpath:
                        assert mod not in mods
                        mods.append(mod)
            self.trace("loaded conftestmodule %r" % (mod))
            self.consider_conftest(mod)
            return mod
Esempio n. 51
0
    def _istrue(self):
        if hasattr(self, 'result'):
            return self.result
        self._marks = self._get_marks()

        if self._marks:
            self.result = False
            for mark in self._marks:
                self._mark = mark
                if 'condition' in mark.kwargs:
                    args = (mark.kwargs['condition'],)
                else:
                    args = mark.args

                for expr in args:
                    self.expr = expr
                    if isinstance(expr, six.string_types):
                        d = self._getglobals()
                        result = cached_eval(self.item.config, expr, d)
                    else:
                        if "reason" not in mark.kwargs:
                            # XXX better be checked at collection time
                            msg = "you need to specify reason=STRING " \
                                  "when using booleans as conditions."
                            fail(msg)
                        result = bool(expr)
                    if result:
                        self.result = True
                        self.reason = mark.kwargs.get('reason', None)
                        self.expr = expr
                        return self.result

                if not args:
                    self.result = True
                    self.reason = mark.kwargs.get('reason', None)
                    return self.result
        return False
Esempio n. 52
0
def getcfg(args, config=None):
    """
    Search the list of arguments for a valid ini-file for pytest,
    and return a tuple of (rootdir, inifile, cfg-dict).

    note: config is optional and used only to issue warnings explicitly (#2891).
    """
    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 config is not None:

                            fail(
                                CFG_PYTEST_SECTION.format(filename=inibasename),
                                pytrace=False,
                            )
                        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
Esempio n. 53
0
def raises(expected_exception, *args, **kwargs):
    r"""
    Assert that a code block/function call raises ``expected_exception``
    and raise a failure exception otherwise.

    :arg message: if specified, provides a custom failure message if the
        exception is not raised
    :arg match: if specified, asserts that the exception matches a text or regex

    This helper produces a ``ExceptionInfo()`` object (see below).

    You may use this function as a context manager::

        >>> with raises(ZeroDivisionError):
        ...    1/0

    .. versionchanged:: 2.10

    In the context manager form you may use the keyword argument
    ``message`` to specify a custom failure message::

        >>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"):
        ...    pass
        Traceback (most recent call last):
          ...
        Failed: Expecting ZeroDivisionError

    .. note::

       When using ``pytest.raises`` as a context manager, it's worthwhile to
       note that normal context manager rules apply and that the exception
       raised *must* be the final line in the scope of the context manager.
       Lines of code after that, within the scope of the context manager will
       not be executed. For example::

           >>> value = 15
           >>> with raises(ValueError) as exc_info:
           ...     if value > 10:
           ...         raise ValueError("value must be <= 10")
           ...     assert exc_info.type == ValueError  # this will not execute

       Instead, the following approach must be taken (note the difference in
       scope)::

           >>> with raises(ValueError) as exc_info:
           ...     if value > 10:
           ...         raise ValueError("value must be <= 10")
           ...
           >>> assert exc_info.type == ValueError


    Since version ``3.1`` you can use the keyword argument ``match`` to assert that the
    exception matches a text or regex::

        >>> with raises(ValueError, match='must be 0 or None'):
        ...     raise ValueError("value must be 0 or None")

        >>> with raises(ValueError, match=r'must be \d+$'):
        ...     raise ValueError("value must be 42")

    **Legacy forms**

    The forms below are fully supported but are discouraged for new code because the
    context manager form is regarded as more readable and less error-prone.

    It is possible to specify a callable by passing a to-be-called lambda::

        >>> raises(ZeroDivisionError, lambda: 1/0)
        <ExceptionInfo ...>

    or you can specify an arbitrary callable with arguments::

        >>> def f(x): return 1/x
        ...
        >>> raises(ZeroDivisionError, f, 0)
        <ExceptionInfo ...>
        >>> raises(ZeroDivisionError, f, x=0)
        <ExceptionInfo ...>

    It is also possible to pass a string to be evaluated at runtime::

        >>> raises(ZeroDivisionError, "f(0)")
        <ExceptionInfo ...>

    The string will be evaluated using the same ``locals()`` and ``globals()``
    at the moment of the ``raises`` call.

    .. currentmodule:: _pytest._code

    Consult the API of ``excinfo`` objects: :class:`ExceptionInfo`.

    .. note::
        Similar to caught exception objects in Python, explicitly clearing
        local references to returned ``ExceptionInfo`` objects can
        help the Python interpreter speed up its garbage collection.

        Clearing those references breaks a reference cycle
        (``ExceptionInfo`` --> caught exception --> frame stack raising
        the exception --> current frame stack --> local variables -->
        ``ExceptionInfo``) which makes Python keep all objects referenced
        from that cycle (including all local variables in the current
        frame) alive until the next cyclic garbage collection run. See the
        official Python ``try`` statement documentation for more detailed
        information.

    """
    __tracebackhide__ = True
    for exc in filterfalse(isclass, always_iterable(expected_exception, BASE_TYPE)):
        msg = (
            "exceptions must be old-style classes or"
            " derived from BaseException, not %s"
        )
        raise TypeError(msg % type(exc))

    message = "DID NOT RAISE {}".format(expected_exception)
    match_expr = None

    if not args:
        if "message" in kwargs:
            message = kwargs.pop("message")
        if "match" in kwargs:
            match_expr = kwargs.pop("match")
        if kwargs:
            msg = "Unexpected keyword arguments passed to pytest.raises: "
            msg += ", ".join(kwargs.keys())
            raise TypeError(msg)
        return RaisesContext(expected_exception, message, match_expr)
    elif isinstance(args[0], str):
        code, = args
        assert isinstance(code, str)
        frame = sys._getframe(1)
        loc = frame.f_locals.copy()
        loc.update(kwargs)
        # print "raises frame scope: %r" % frame.f_locals
        try:
            code = _pytest._code.Source(code).compile()
            py.builtin.exec_(code, frame.f_globals, loc)
            # XXX didn'T mean f_globals == f_locals something special?
            #     this is destroyed here ...
        except expected_exception:
            return _pytest._code.ExceptionInfo()
    else:
        func = args[0]
        try:
            func(*args[1:], **kwargs)
        except expected_exception:
            return _pytest._code.ExceptionInfo()
    fail(message)
Esempio n. 54
0
 def result(*args, **kwargs):
     fail(message, pytrace=False)
Esempio n. 55
0
def raises(expected_exception, *args, **kwargs):
    r"""
    Assert that a code block/function call raises ``expected_exception``
    or raise a failure exception otherwise.

    :kwparam match: if specified, asserts that the exception matches a text or regex

    :kwparam message: **(deprecated since 4.1)** if specified, provides a custom failure message
        if the exception is not raised

    .. currentmodule:: _pytest._code

    Use ``pytest.raises`` as a context manager, which will capture the exception of the given
    type::

        >>> with raises(ZeroDivisionError):
        ...    1/0

    If the code block does not raise the expected exception (``ZeroDivisionError`` in the example
    above), or no exception at all, the check will fail instead.

    You can also use the keyword argument ``match`` to assert that the
    exception matches a text or regex::

        >>> with raises(ValueError, match='must be 0 or None'):
        ...     raise ValueError("value must be 0 or None")

        >>> with raises(ValueError, match=r'must be \d+$'):
        ...     raise ValueError("value must be 42")

    The context manager produces an :class:`ExceptionInfo` object which can be used to inspect the
    details of the captured exception::

        >>> with raises(ValueError) as exc_info:
        ...     raise ValueError("value must be 42")
        >>> assert exc_info.type is ValueError
        >>> assert exc_info.value.args[0] == "value must be 42"

    .. deprecated:: 4.1

        In the context manager form you may use the keyword argument
        ``message`` to specify a custom failure message that will be displayed
        in case the ``pytest.raises`` check fails. This has been deprecated as it
        is considered error prone as users often mean to use ``match`` instead.

    .. note::

       When using ``pytest.raises`` as a context manager, it's worthwhile to
       note that normal context manager rules apply and that the exception
       raised *must* be the final line in the scope of the context manager.
       Lines of code after that, within the scope of the context manager will
       not be executed. For example::

           >>> value = 15
           >>> with raises(ValueError) as exc_info:
           ...     if value > 10:
           ...         raise ValueError("value must be <= 10")
           ...     assert exc_info.type is ValueError  # this will not execute

       Instead, the following approach must be taken (note the difference in
       scope)::

           >>> with raises(ValueError) as exc_info:
           ...     if value > 10:
           ...         raise ValueError("value must be <= 10")
           ...
           >>> assert exc_info.type is ValueError

    **Using with** ``pytest.mark.parametrize``

    When using :ref:`pytest.mark.parametrize ref`
    it is possible to parametrize tests such that
    some runs raise an exception and others do not.

    See :ref:`parametrizing_conditional_raising` for an example.

    **Legacy form**

    It is possible to specify a callable by passing a to-be-called lambda::

        >>> raises(ZeroDivisionError, lambda: 1/0)
        <ExceptionInfo ...>

    or you can specify an arbitrary callable with arguments::

        >>> def f(x): return 1/x
        ...
        >>> raises(ZeroDivisionError, f, 0)
        <ExceptionInfo ...>
        >>> raises(ZeroDivisionError, f, x=0)
        <ExceptionInfo ...>

    The form above is fully supported but discouraged for new code because the
    context manager form is regarded as more readable and less error-prone.

    .. note::
        Similar to caught exception objects in Python, explicitly clearing
        local references to returned ``ExceptionInfo`` objects can
        help the Python interpreter speed up its garbage collection.

        Clearing those references breaks a reference cycle
        (``ExceptionInfo`` --> caught exception --> frame stack raising
        the exception --> current frame stack --> local variables -->
        ``ExceptionInfo``) which makes Python keep all objects referenced
        from that cycle (including all local variables in the current
        frame) alive until the next cyclic garbage collection run. See the
        official Python ``try`` statement documentation for more detailed
        information.

    """
    __tracebackhide__ = True
    for exc in filterfalse(isclass, always_iterable(expected_exception, BASE_TYPE)):
        msg = (
            "exceptions must be old-style classes or"
            " derived from BaseException, not %s"
        )
        raise TypeError(msg % type(exc))

    message = "DID NOT RAISE {}".format(expected_exception)
    match_expr = None

    if not args:
        if "message" in kwargs:
            message = kwargs.pop("message")
            warnings.warn(deprecated.RAISES_MESSAGE_PARAMETER, stacklevel=2)
        if "match" in kwargs:
            match_expr = kwargs.pop("match")
        if kwargs:
            msg = "Unexpected keyword arguments passed to pytest.raises: "
            msg += ", ".join(kwargs.keys())
            raise TypeError(msg)
        return RaisesContext(expected_exception, message, match_expr)
    elif isinstance(args[0], str):
        warnings.warn(deprecated.RAISES_EXEC, stacklevel=2)
        code, = args
        assert isinstance(code, str)
        frame = sys._getframe(1)
        loc = frame.f_locals.copy()
        loc.update(kwargs)
        # print "raises frame scope: %r" % frame.f_locals
        try:
            code = _pytest._code.Source(code).compile(_genframe=frame)
            six.exec_(code, frame.f_globals, loc)
            # XXX didn't mean f_globals == f_locals something special?
            #     this is destroyed here ...
        except expected_exception:
            return _pytest._code.ExceptionInfo.from_current()
    else:
        func = args[0]
        try:
            func(*args[1:], **kwargs)
        except expected_exception:
            return _pytest._code.ExceptionInfo.from_current()
    fail(message)
Esempio n. 56
0
    def _compute_fixture_value(self, fixturedef):
        """
        Creates a SubRequest based on "self" and calls the execute method of the given fixturedef object. This will
        force the FixtureDef object to throw away any previous results and compute a new fixture value, which
        will be stored into the FixtureDef object itself.

        :param FixtureDef fixturedef:
        """
        # prepare a subrequest object before calling fixture function
        # (latter managed by fixturedef)
        argname = fixturedef.argname
        funcitem = self._pyfuncitem
        scope = fixturedef.scope
        try:
            param = funcitem.callspec.getparam(argname)
        except (AttributeError, ValueError):
            param = NOTSET
            param_index = 0
            has_params = fixturedef.params is not None
            fixtures_not_supported = getattr(funcitem, "nofuncargs", False)
            if has_params and fixtures_not_supported:
                msg = (
                    "{name} does not support fixtures, maybe unittest.TestCase subclass?\n"
                    "Node id: {nodeid}\n"
                    "Function type: {typename}"
                ).format(
                    name=funcitem.name,
                    nodeid=funcitem.nodeid,
                    typename=type(funcitem).__name__,
                )
                fail(msg, pytrace=False)
            if has_params:
                frame = inspect.stack()[3]
                frameinfo = inspect.getframeinfo(frame[0])
                source_path = frameinfo.filename
                source_lineno = frameinfo.lineno
                source_path = py.path.local(source_path)
                if source_path.relto(funcitem.config.rootdir):
                    source_path = source_path.relto(funcitem.config.rootdir)
                msg = (
                    "The requested fixture has no parameter defined for test:\n"
                    "    {}\n\n"
                    "Requested fixture '{}' defined in:\n{}"
                    "\n\nRequested here:\n{}:{}".format(
                        funcitem.nodeid,
                        fixturedef.argname,
                        getlocation(fixturedef.func, funcitem.config.rootdir),
                        source_path,
                        source_lineno,
                    )
                )
                fail(msg, pytrace=False)
        else:
            param_index = funcitem.callspec.indices[argname]
            # if a parametrize invocation set a scope it will override
            # the static scope defined with the fixture function
            paramscopenum = funcitem.callspec._arg2scopenum.get(argname)
            if paramscopenum is not None:
                scope = scopes[paramscopenum]

        subrequest = SubRequest(self, scope, param, param_index, fixturedef)

        # check if a higher-level scoped fixture accesses a lower level one
        subrequest._check_scope(argname, self.scope, scope)

        # clear sys.exc_info before invoking the fixture (python bug?)
        # if it's not explicitly cleared it will leak into the call
        exc_clear()
        try:
            # call the fixture function
            fixturedef.execute(request=subrequest)
        finally:
            self._schedule_finalizers(fixturedef, subrequest)
Esempio n. 57
0
def fail_fixturefunc(fixturefunc, msg):
    fs, lineno = getfslineno(fixturefunc)
    location = "%s:%s" % (fs, lineno + 1)
    source = _pytest._code.Source(fixturefunc)
    fail(msg + ":\n\n" + str(source.indent()) + "\n" + location,
         pytrace=False)