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], ) )
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
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)
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)
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)
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, (), {}))
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
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, )
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
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)
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)
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
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
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)
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
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)
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)
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)
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, )
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)
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
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 {}
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, )
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]))
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)
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())
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
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)
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)
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 {}
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)
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)
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)
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
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
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
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, )
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)
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, )
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')]
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
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
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
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
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)
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
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
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
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)
def result(*args, **kwargs): fail(message, pytrace=False)
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)
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)
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)