Merge pull request #7387 from cool-RR/2020-06-11-raise-from
Fix exception causes all over the codebase
This commit is contained in:
		
						commit
						83891d9022
					
				
							
								
								
									
										1
									
								
								AUTHORS
								
								
								
								
							
							
						
						
									
										1
									
								
								AUTHORS
								
								
								
								
							| 
						 | 
				
			
			@ -233,6 +233,7 @@ Pulkit Goyal
 | 
			
		|||
Punyashloka Biswal
 | 
			
		||||
Quentin Pradet
 | 
			
		||||
Ralf Schmitt
 | 
			
		||||
Ram Rachum
 | 
			
		||||
Ralph Giles
 | 
			
		||||
Ran Benita
 | 
			
		||||
Raphael Castaneda
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
Fixed exception causes all over the codebase, i.e. use `raise new_exception from old_exception` when wrapping an exception.
 | 
			
		||||
| 
						 | 
				
			
			@ -215,7 +215,7 @@ class Source:
 | 
			
		|||
            newex.offset = ex.offset
 | 
			
		||||
            newex.lineno = ex.lineno
 | 
			
		||||
            newex.text = ex.text
 | 
			
		||||
            raise newex
 | 
			
		||||
            raise newex from ex
 | 
			
		||||
        else:
 | 
			
		||||
            if flag & ast.PyCF_ONLY_AST:
 | 
			
		||||
                assert isinstance(co, ast.AST)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1189,8 +1189,8 @@ class Config:
 | 
			
		|||
    def _getini(self, name: str) -> Any:
 | 
			
		||||
        try:
 | 
			
		||||
            description, type, default = self._parser._inidict[name]
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            raise ValueError("unknown configuration value: {!r}".format(name))
 | 
			
		||||
        except KeyError as e:
 | 
			
		||||
            raise ValueError("unknown configuration value: {!r}".format(name)) from e
 | 
			
		||||
        override_value = self._get_override_ini_value(name)
 | 
			
		||||
        if override_value is None:
 | 
			
		||||
            try:
 | 
			
		||||
| 
						 | 
				
			
			@ -1286,14 +1286,14 @@ class Config:
 | 
			
		|||
            if val is None and skip:
 | 
			
		||||
                raise AttributeError(name)
 | 
			
		||||
            return val
 | 
			
		||||
        except AttributeError:
 | 
			
		||||
        except AttributeError as e:
 | 
			
		||||
            if default is not notset:
 | 
			
		||||
                return default
 | 
			
		||||
            if skip:
 | 
			
		||||
                import pytest
 | 
			
		||||
 | 
			
		||||
                pytest.skip("no {!r} option found".format(name))
 | 
			
		||||
            raise ValueError("no option named {!r}".format(name))
 | 
			
		||||
            raise ValueError("no option named {!r}".format(name)) from e
 | 
			
		||||
 | 
			
		||||
    def getvalue(self, name, path=None):
 | 
			
		||||
        """ (deprecated, use getoption()) """
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -265,9 +265,9 @@ class Argument:
 | 
			
		|||
        else:
 | 
			
		||||
            try:
 | 
			
		||||
                self.dest = self._short_opts[0][1:]
 | 
			
		||||
            except IndexError:
 | 
			
		||||
            except IndexError as e:
 | 
			
		||||
                self.dest = "???"  # Needed for the error repr.
 | 
			
		||||
                raise ArgumentError("need a long or short option", self)
 | 
			
		||||
                raise ArgumentError("need a long or short option", self) from e
 | 
			
		||||
 | 
			
		||||
    def names(self) -> List[str]:
 | 
			
		||||
        return self._short_opts + self._long_opts
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ def _parse_ini_config(path: py.path.local) -> iniconfig.IniConfig:
 | 
			
		|||
    try:
 | 
			
		||||
        return iniconfig.IniConfig(path)
 | 
			
		||||
    except iniconfig.ParseError as exc:
 | 
			
		||||
        raise UsageError(str(exc))
 | 
			
		||||
        raise UsageError(str(exc)) from exc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def load_config_dict_from_file(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,10 +28,10 @@ def _validate_usepdb_cls(value: str) -> Tuple[str, str]:
 | 
			
		|||
    """Validate syntax of --pdbcls option."""
 | 
			
		||||
    try:
 | 
			
		||||
        modname, classname = value.split(":")
 | 
			
		||||
    except ValueError:
 | 
			
		||||
    except ValueError as e:
 | 
			
		||||
        raise argparse.ArgumentTypeError(
 | 
			
		||||
            "{!r} is not in the format 'modname:classname'".format(value)
 | 
			
		||||
        )
 | 
			
		||||
        ) from e
 | 
			
		||||
    return (modname, classname)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +130,7 @@ class pytestPDB:
 | 
			
		|||
                value = ":".join((modname, classname))
 | 
			
		||||
                raise UsageError(
 | 
			
		||||
                    "--pdbcls: could not import {!r}: {}".format(value, exc)
 | 
			
		||||
                )
 | 
			
		||||
                ) from exc
 | 
			
		||||
        else:
 | 
			
		||||
            import pdb
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -938,13 +938,13 @@ def _eval_scope_callable(
 | 
			
		|||
        # Type ignored because there is no typing mechanism to specify
 | 
			
		||||
        # keyword arguments, currently.
 | 
			
		||||
        result = scope_callable(fixture_name=fixture_name, config=config)  # type: ignore[call-arg] # noqa: F821
 | 
			
		||||
    except Exception:
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        raise TypeError(
 | 
			
		||||
            "Error evaluating {} while defining fixture '{}'.\n"
 | 
			
		||||
            "Expected a function with the signature (*, fixture_name, config)".format(
 | 
			
		||||
                scope_callable, fixture_name
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
        ) from e
 | 
			
		||||
    if not isinstance(result, str):
 | 
			
		||||
        fail(
 | 
			
		||||
            "Expected {} to return a 'str' while defining fixture '{}', but it returned:\n"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -487,13 +487,13 @@ def get_log_level_for_setting(config: Config, *setting_names: str) -> Optional[i
 | 
			
		|||
        log_level = log_level.upper()
 | 
			
		||||
    try:
 | 
			
		||||
        return int(getattr(logging, log_level, log_level))
 | 
			
		||||
    except ValueError:
 | 
			
		||||
    except ValueError as e:
 | 
			
		||||
        # Python logging does not recognise this as a logging level
 | 
			
		||||
        raise pytest.UsageError(
 | 
			
		||||
            "'{}' is not recognized as a logging level name for "
 | 
			
		||||
            "'{}'. Please consider passing the "
 | 
			
		||||
            "logging level num instead.".format(log_level, setting_name)
 | 
			
		||||
        )
 | 
			
		||||
        ) from e
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# run after terminalreporter/capturemanager are configured
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,7 +73,7 @@ def resolve(name: str) -> object:
 | 
			
		|||
            if expected == used:
 | 
			
		||||
                raise
 | 
			
		||||
            else:
 | 
			
		||||
                raise ImportError("import error in {}: {}".format(used, ex))
 | 
			
		||||
                raise ImportError("import error in {}: {}".format(used, ex)) from ex
 | 
			
		||||
        found = annotated_getattr(found, part, used)
 | 
			
		||||
    return found
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -81,12 +81,12 @@ def resolve(name: str) -> object:
 | 
			
		|||
def annotated_getattr(obj: object, name: str, ann: str) -> object:
 | 
			
		||||
    try:
 | 
			
		||||
        obj = getattr(obj, name)
 | 
			
		||||
    except AttributeError:
 | 
			
		||||
    except AttributeError as e:
 | 
			
		||||
        raise AttributeError(
 | 
			
		||||
            "{!r} object at {} has no attribute {!r}".format(
 | 
			
		||||
                type(obj).__name__, ann, name
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
        ) from e
 | 
			
		||||
    return obj
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -551,8 +551,10 @@ class Module(nodes.File, PyCollector):
 | 
			
		|||
        importmode = self.config.getoption("--import-mode")
 | 
			
		||||
        try:
 | 
			
		||||
            mod = import_path(self.fspath, mode=importmode)
 | 
			
		||||
        except SyntaxError:
 | 
			
		||||
            raise self.CollectError(ExceptionInfo.from_current().getrepr(style="short"))
 | 
			
		||||
        except SyntaxError as e:
 | 
			
		||||
            raise self.CollectError(
 | 
			
		||||
                ExceptionInfo.from_current().getrepr(style="short")
 | 
			
		||||
            ) from e
 | 
			
		||||
        except ImportPathMismatchError as e:
 | 
			
		||||
            raise self.CollectError(
 | 
			
		||||
                "import file mismatch:\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -562,8 +564,8 @@ class Module(nodes.File, PyCollector):
 | 
			
		|||
                "  %s\n"
 | 
			
		||||
                "HINT: remove __pycache__ / .pyc files and/or use a "
 | 
			
		||||
                "unique basename for your test file modules" % e.args
 | 
			
		||||
            )
 | 
			
		||||
        except ImportError:
 | 
			
		||||
            ) from e
 | 
			
		||||
        except ImportError as e:
 | 
			
		||||
            exc_info = ExceptionInfo.from_current()
 | 
			
		||||
            if self.config.getoption("verbose") < 2:
 | 
			
		||||
                exc_info.traceback = exc_info.traceback.filter(filter_traceback)
 | 
			
		||||
| 
						 | 
				
			
			@ -578,7 +580,7 @@ class Module(nodes.File, PyCollector):
 | 
			
		|||
                "Hint: make sure your test modules/packages have valid Python names.\n"
 | 
			
		||||
                "Traceback:\n"
 | 
			
		||||
                "{traceback}".format(fspath=self.fspath, traceback=formatted_tb)
 | 
			
		||||
            )
 | 
			
		||||
            ) from e
 | 
			
		||||
        except _pytest.runner.Skipped as e:
 | 
			
		||||
            if e.allow_module_level:
 | 
			
		||||
                raise
 | 
			
		||||
| 
						 | 
				
			
			@ -587,7 +589,7 @@ class Module(nodes.File, PyCollector):
 | 
			
		|||
                "To decorate a test function, use the @pytest.mark.skip "
 | 
			
		||||
                "or @pytest.mark.skipif decorators instead, and to skip a "
 | 
			
		||||
                "module use `pytestmark = pytest.mark.{skip,skipif}."
 | 
			
		||||
            )
 | 
			
		||||
            ) from e
 | 
			
		||||
        self.config.pluginmanager.consider_module(mod)
 | 
			
		||||
        return mod
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -836,8 +838,8 @@ class CallSpec2:
 | 
			
		|||
    def getparam(self, name: str) -> object:
 | 
			
		||||
        try:
 | 
			
		||||
            return self.params[name]
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            raise ValueError(name)
 | 
			
		||||
        except KeyError as e:
 | 
			
		||||
            raise ValueError(name) from e
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def id(self) -> str:
 | 
			
		||||
| 
						 | 
				
			
			@ -1074,8 +1076,8 @@ class Metafunc:
 | 
			
		|||
        except TypeError:
 | 
			
		||||
            try:
 | 
			
		||||
                iter(ids)
 | 
			
		||||
            except TypeError:
 | 
			
		||||
                raise TypeError("ids must be a callable or an iterable")
 | 
			
		||||
            except TypeError as e:
 | 
			
		||||
                raise TypeError("ids must be a callable or an iterable") from e
 | 
			
		||||
            num_ids = len(parameters)
 | 
			
		||||
 | 
			
		||||
        # num_ids == 0 is a special case: https://github.com/pytest-dev/pytest/issues/1849
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,8 +48,8 @@ def _parse_filter(
 | 
			
		|||
            lineno = int(lineno_)
 | 
			
		||||
            if lineno < 0:
 | 
			
		||||
                raise ValueError
 | 
			
		||||
        except (ValueError, OverflowError):
 | 
			
		||||
            raise warnings._OptionError("invalid lineno {!r}".format(lineno_))
 | 
			
		||||
        except (ValueError, OverflowError) as e:
 | 
			
		||||
            raise warnings._OptionError("invalid lineno {!r}".format(lineno_)) from e
 | 
			
		||||
    else:
 | 
			
		||||
        lineno = 0
 | 
			
		||||
    return (action, message, category, module, lineno)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1778,5 +1778,5 @@ def test_conftest_import_error_repr(tmpdir):
 | 
			
		|||
    ):
 | 
			
		||||
        try:
 | 
			
		||||
            raise RuntimeError("some error")
 | 
			
		||||
        except Exception:
 | 
			
		||||
            raise ConftestImportFailure(path, sys.exc_info())
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            raise ConftestImportFailure(path, sys.exc_info()) from e
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -534,8 +534,8 @@ def test_outcomeexception_passes_except_Exception() -> None:
 | 
			
		|||
    with pytest.raises(outcomes.OutcomeException):
 | 
			
		||||
        try:
 | 
			
		||||
            raise outcomes.OutcomeException("test")
 | 
			
		||||
        except Exception:
 | 
			
		||||
            raise NotImplementedError()
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            raise NotImplementedError from e
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_pytest_exit() -> None:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue