Compare commits

...

10 Commits

Author SHA1 Message Date
Thomas Grainger 662fc9c012
docs 2023-10-19 18:31:45 +01:00
Thomas Grainger db62b80e8d
fix some_dir NameError 2023-10-19 18:29:24 +01:00
Thomas Grainger 4821a41967
add type annotations 2023-10-19 18:29:11 +01:00
Thomas Grainger ff12e083c5
doc exc param to importorskip 2023-10-19 18:25:56 +01:00
Thomas Grainger 6e40458fc1
make exc kwonly 2023-10-19 18:25:43 +01:00
Thomas Grainger e74a6da699
use old style type annotation 2023-10-19 18:23:36 +01:00
pre-commit-ci[bot] 5e6dc297c2 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2023-10-19 17:18:56 +00:00
Thomas Grainger 5ba3351b52
add tests 2023-10-19 18:17:27 +01:00
pre-commit-ci[bot] f34091f0ec [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2023-10-19 17:11:49 +00:00
Thomas Grainger dc2080f3be
gh-11523: add importorskip(exc=...) kwarg
Fixes #11523
2023-10-19 18:10:41 +01:00
3 changed files with 42 additions and 3 deletions

View File

@ -197,6 +197,14 @@ the test. You can also skip based on the version number of a library:
The version will be read from the specified
module's ``__version__`` attribute.
Sometimes importing a module can fail due to an exception, if you want to
only skip if the module does not exist pass ModuleNotFoundError as the
``exc`` kwarg:
.. code-block:: python
docutils = pytest.importorskip("docutils", exc=ModuleNotFoundError)
Summary
~~~~~~~

View File

@ -249,7 +249,11 @@ def xfail(reason: str = "") -> NoReturn:
def importorskip(
modname: str, minversion: Optional[str] = None, reason: Optional[str] = None
modname: str,
minversion: Optional[str] = None,
reason: Optional[str] = None,
*,
exc: Type[ImportError] = ImportError,
) -> Any:
"""Import and return the requested module ``modname``, or skip the
current test if the module cannot be imported.
@ -262,6 +266,9 @@ def importorskip(
:param reason:
If given, this reason is shown as the message when the module cannot
be imported.
:param exc:
Either ImportError or ModuleNotFoundError, the exception to catch
when importing.
:returns:
The imported module. This should be assigned to its canonical name.
@ -282,9 +289,9 @@ def importorskip(
warnings.simplefilter("ignore")
try:
__import__(modname)
except ImportError as exc:
except exc as e:
if reason is None:
reason = f"could not import {modname!r}: {exc}"
reason = f"could not import {modname!r}: {e}"
raise Skipped(reason, allow_module_level=True) from None
mod = sys.modules[modname]
if minversion is None:

View File

@ -1,7 +1,9 @@
import sys
import textwrap
from pathlib import Path
import pytest
from _pytest.monkeypatch import MonkeyPatch
from _pytest.pytester import Pytester
from _pytest.runner import runtestprotocol
from _pytest.skipping import evaluate_skip_marks
@ -1428,6 +1430,28 @@ def test_importorskip() -> None:
pytest.importorskip("doesnotexist")
def test_importorskip_module_not_found() -> None:
with pytest.raises(
pytest.skip.Exception,
match="^could not import 'doesnotexist': No module named .*",
):
pytest.importorskip("doesnotexist", exc=ModuleNotFoundError)
def test_importorskip_module_not_found_raises_on_import_error(
monkeypatch: MonkeyPatch, tmp_path: Path
) -> None:
on_path = tmp_path / "on_path"
on_path.mkdir()
(on_path / "doesnotexist.py").write_bytes(b"1 / 0")
monkeypatch.syspath_prepend(on_path)
with pytest.raises(ImportError):
pytest.importorskip("doesnotexist", exc=ModuleNotFoundError)
def test_relpath_rootdir(pytester: Pytester) -> None:
pytester.makepyfile(
**{