Skip to content

Commit 48d6021

Browse files
committed
Fix exception causes all over the codebase
1 parent 4cc4ebf commit 48d6021

14 files changed

+40
-34
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ Pulkit Goyal
233233
Punyashloka Biswal
234234
Quentin Pradet
235235
Ralf Schmitt
236+
Ram Rachum
236237
Ralph Giles
237238
Ran Benita
238239
Raphael Castaneda

changelog/7383.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed exception causes all over the codebase, i.e. use `raise new_exception from old_exception` when wrapping an exception.

src/_pytest/_code/source.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ def compile( # noqa: F811
215215
newex.offset = ex.offset
216216
newex.lineno = ex.lineno
217217
newex.text = ex.text
218-
raise newex
218+
raise newex from ex
219219
else:
220220
if flag & ast.PyCF_ONLY_AST:
221221
assert isinstance(co, ast.AST)

src/_pytest/config/__init__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,8 +1189,10 @@ def getini(self, name: str):
11891189
def _getini(self, name: str) -> Any:
11901190
try:
11911191
description, type, default = self._parser._inidict[name]
1192-
except KeyError:
1193-
raise ValueError("unknown configuration value: {!r}".format(name))
1192+
except KeyError as e:
1193+
raise ValueError(
1194+
"unknown configuration value: {!r}".format(name)
1195+
) from e
11941196
override_value = self._get_override_ini_value(name)
11951197
if override_value is None:
11961198
try:
@@ -1286,14 +1288,14 @@ def getoption(self, name: str, default=notset, skip: bool = False):
12861288
if val is None and skip:
12871289
raise AttributeError(name)
12881290
return val
1289-
except AttributeError:
1291+
except AttributeError as e:
12901292
if default is not notset:
12911293
return default
12921294
if skip:
12931295
import pytest
12941296

12951297
pytest.skip("no {!r} option found".format(name))
1296-
raise ValueError("no option named {!r}".format(name))
1298+
raise ValueError("no option named {!r}".format(name)) from e
12971299

12981300
def getvalue(self, name, path=None):
12991301
""" (deprecated, use getoption()) """

src/_pytest/config/argparsing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,9 +265,9 @@ def __init__(self, *names: str, **attrs: Any) -> None:
265265
else:
266266
try:
267267
self.dest = self._short_opts[0][1:]
268-
except IndexError:
268+
except IndexError as e:
269269
self.dest = "???" # Needed for the error repr.
270-
raise ArgumentError("need a long or short option", self)
270+
raise ArgumentError("need a long or short option", self) from e
271271

272272
def names(self) -> List[str]:
273273
return self._short_opts + self._long_opts

src/_pytest/config/findpaths.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def _parse_ini_config(path: py.path.local) -> iniconfig.IniConfig:
2626
try:
2727
return iniconfig.IniConfig(path)
2828
except iniconfig.ParseError as exc:
29-
raise UsageError(str(exc))
29+
raise UsageError(str(exc)) from exc
3030

3131

3232
def load_config_dict_from_file(

src/_pytest/debugging.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ def _validate_usepdb_cls(value: str) -> Tuple[str, str]:
2828
"""Validate syntax of --pdbcls option."""
2929
try:
3030
modname, classname = value.split(":")
31-
except ValueError:
31+
except ValueError as e:
3232
raise argparse.ArgumentTypeError(
3333
"{!r} is not in the format 'modname:classname'".format(value)
34-
)
34+
) from e
3535
return (modname, classname)
3636

3737

@@ -130,7 +130,7 @@ def _import_pdb_cls(cls, capman: "CaptureManager"):
130130
value = ":".join((modname, classname))
131131
raise UsageError(
132132
"--pdbcls: could not import {!r}: {}".format(value, exc)
133-
)
133+
) from exc
134134
else:
135135
import pdb
136136

src/_pytest/fixtures.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -938,13 +938,13 @@ def _eval_scope_callable(
938938
# Type ignored because there is no typing mechanism to specify
939939
# keyword arguments, currently.
940940
result = scope_callable(fixture_name=fixture_name, config=config) # type: ignore[call-arg] # noqa: F821
941-
except Exception:
941+
except Exception as e:
942942
raise TypeError(
943943
"Error evaluating {} while defining fixture '{}'.\n"
944944
"Expected a function with the signature (*, fixture_name, config)".format(
945945
scope_callable, fixture_name
946946
)
947-
)
947+
) from e
948948
if not isinstance(result, str):
949949
fail(
950950
"Expected {} to return a 'str' while defining fixture '{}', but it returned:\n"

src/_pytest/logging.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,13 +487,13 @@ def get_log_level_for_setting(config: Config, *setting_names: str) -> Optional[i
487487
log_level = log_level.upper()
488488
try:
489489
return int(getattr(logging, log_level, log_level))
490-
except ValueError:
490+
except ValueError as e:
491491
# Python logging does not recognise this as a logging level
492492
raise pytest.UsageError(
493493
"'{}' is not recognized as a logging level name for "
494494
"'{}'. Please consider passing the "
495495
"logging level num instead.".format(log_level, setting_name)
496-
)
496+
) from e
497497

498498

499499
# run after terminalreporter/capturemanager are configured

src/_pytest/monkeypatch.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,20 @@ def resolve(name: str) -> object:
7373
if expected == used:
7474
raise
7575
else:
76-
raise ImportError("import error in {}: {}".format(used, ex))
76+
raise ImportError("import error in {}: {}".format(used, ex)) from ex
7777
found = annotated_getattr(found, part, used)
7878
return found
7979

8080

8181
def annotated_getattr(obj: object, name: str, ann: str) -> object:
8282
try:
8383
obj = getattr(obj, name)
84-
except AttributeError:
84+
except AttributeError as e:
8585
raise AttributeError(
8686
"{!r} object at {} has no attribute {!r}".format(
8787
type(obj).__name__, ann, name
8888
)
89-
)
89+
) from e
9090
return obj
9191

9292

src/_pytest/python.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -551,8 +551,10 @@ def _importtestmodule(self):
551551
importmode = self.config.getoption("--import-mode")
552552
try:
553553
mod = import_path(self.fspath, mode=importmode)
554-
except SyntaxError:
555-
raise self.CollectError(ExceptionInfo.from_current().getrepr(style="short"))
554+
except SyntaxError as e:
555+
raise self.CollectError(
556+
ExceptionInfo.from_current().getrepr(style="short")
557+
) from e
556558
except ImportPathMismatchError as e:
557559
raise self.CollectError(
558560
"import file mismatch:\n"
@@ -562,8 +564,8 @@ def _importtestmodule(self):
562564
" %s\n"
563565
"HINT: remove __pycache__ / .pyc files and/or use a "
564566
"unique basename for your test file modules" % e.args
565-
)
566-
except ImportError:
567+
) from e
568+
except ImportError as e:
567569
exc_info = ExceptionInfo.from_current()
568570
if self.config.getoption("verbose") < 2:
569571
exc_info.traceback = exc_info.traceback.filter(filter_traceback)
@@ -578,7 +580,7 @@ def _importtestmodule(self):
578580
"Hint: make sure your test modules/packages have valid Python names.\n"
579581
"Traceback:\n"
580582
"{traceback}".format(fspath=self.fspath, traceback=formatted_tb)
581-
)
583+
) from e
582584
except _pytest.runner.Skipped as e:
583585
if e.allow_module_level:
584586
raise
@@ -587,7 +589,7 @@ def _importtestmodule(self):
587589
"To decorate a test function, use the @pytest.mark.skip "
588590
"or @pytest.mark.skipif decorators instead, and to skip a "
589591
"module use `pytestmark = pytest.mark.{skip,skipif}."
590-
)
592+
) from e
591593
self.config.pluginmanager.consider_module(mod)
592594
return mod
593595

@@ -836,8 +838,8 @@ def _checkargnotcontained(self, arg: str) -> None:
836838
def getparam(self, name: str) -> object:
837839
try:
838840
return self.params[name]
839-
except KeyError:
840-
raise ValueError(name)
841+
except KeyError as e:
842+
raise ValueError(name) from e
841843

842844
@property
843845
def id(self) -> str:
@@ -1074,8 +1076,8 @@ def _validate_ids(
10741076
except TypeError:
10751077
try:
10761078
iter(ids)
1077-
except TypeError:
1078-
raise TypeError("ids must be a callable or an iterable")
1079+
except TypeError as e:
1080+
raise TypeError("ids must be a callable or an iterable") from e
10791081
num_ids = len(parameters)
10801082

10811083
# num_ids == 0 is a special case: https://github.com/pytest-dev/pytest/issues/1849

src/_pytest/warnings.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ def _parse_filter(
4848
lineno = int(lineno_)
4949
if lineno < 0:
5050
raise ValueError
51-
except (ValueError, OverflowError):
52-
raise warnings._OptionError("invalid lineno {!r}".format(lineno_))
51+
except (ValueError, OverflowError) as e:
52+
raise warnings._OptionError("invalid lineno {!r}".format(lineno_)) from e
5353
else:
5454
lineno = 0
5555
return (action, message, category, module, lineno)

testing/test_config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,5 +1778,5 @@ def test_conftest_import_error_repr(tmpdir):
17781778
):
17791779
try:
17801780
raise RuntimeError("some error")
1781-
except Exception:
1782-
raise ConftestImportFailure(path, sys.exc_info())
1781+
except Exception as e:
1782+
raise ConftestImportFailure(path, sys.exc_info()) from e

testing/test_runner.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,8 +534,8 @@ def test_outcomeexception_passes_except_Exception() -> None:
534534
with pytest.raises(outcomes.OutcomeException):
535535
try:
536536
raise outcomes.OutcomeException("test")
537-
except Exception:
538-
raise NotImplementedError()
537+
except Exception as e:
538+
raise NotImplementedError from e
539539

540540

541541
def test_pytest_exit() -> None:

0 commit comments

Comments
 (0)