Merge branch 'importorskip-ModuleNotFoundError'

This commit is contained in:
shekhuverma 2024-04-19 19:27:12 +05:30
commit 1456b71990
3 changed files with 34 additions and 23 deletions

View File

@ -0,0 +1 @@
pytest.importorskip will now skip both ImportError and ModuleNotFoundError.

View File

@ -11,6 +11,8 @@ from typing import Protocol
from typing import Type from typing import Type
from typing import TypeVar from typing import TypeVar
from .warning_types import PytestDeprecationWarning
class OutcomeException(BaseException): class OutcomeException(BaseException):
"""OutcomeException and its subclass instances indicate and contain info """OutcomeException and its subclass instances indicate and contain info
@ -192,7 +194,10 @@ def xfail(reason: str = "") -> NoReturn:
def importorskip( def importorskip(
modname: str, minversion: Optional[str] = None, reason: Optional[str] = None modname: str,
minversion: Optional[str] = None,
reason: Optional[str] = None,
exc_type: Optional[Type[ImportError]] = None,
) -> Any: ) -> Any:
"""Import and return the requested module ``modname``, or skip the """Import and return the requested module ``modname``, or skip the
current test if the module cannot be imported. current test if the module cannot be imported.
@ -205,6 +210,8 @@ def importorskip(
:param reason: :param reason:
If given, this reason is shown as the message when the module cannot If given, this reason is shown as the message when the module cannot
be imported. be imported.
:param exc_type:
If given, modules are skipped if this exception is raised.
:returns: :returns:
The imported module. This should be assigned to its canonical name. The imported module. This should be assigned to its canonical name.
@ -223,12 +230,24 @@ def importorskip(
# of existing directories with the same name we're trying to # of existing directories with the same name we're trying to
# import but without a __init__.py file. # import but without a __init__.py file.
warnings.simplefilter("ignore") warnings.simplefilter("ignore")
if exc_type is None:
exc_type = ModuleNotFoundError
else:
exc_type = ImportError
warnings.warn(
PytestDeprecationWarning(
"The Default behaviour will change to ImportError in future",
)
)
try: try:
__import__(modname) __import__(modname)
except ModuleNotFoundError as exc: except exc_type as exc:
if reason is None: if reason is None:
reason = f"could not import {modname!r}: {exc}" reason = f"could not import {modname!r}: {exc}"
raise Skipped(reason, allow_module_level=True) from None raise Skipped(reason, allow_module_level=True) from None
mod = sys.modules[modname] mod = sys.modules[modname]
if minversion is None: if minversion is None:
return mod return mod

View File

@ -1,5 +1,4 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import builtins
from functools import partial from functools import partial
import inspect import inspect
import os import os
@ -8,8 +7,6 @@ import sys
import types import types
from typing import Dict from typing import Dict
from typing import List from typing import List
from typing import Mapping
from typing import Sequence
from typing import Tuple from typing import Tuple
from typing import Type from typing import Type
@ -22,6 +19,7 @@ from _pytest.config import ExitCode
from _pytest.monkeypatch import MonkeyPatch from _pytest.monkeypatch import MonkeyPatch
from _pytest.outcomes import OutcomeException from _pytest.outcomes import OutcomeException
from _pytest.pytester import Pytester from _pytest.pytester import Pytester
from _pytest.warning_types import PytestDeprecationWarning
import pytest import pytest
@ -765,25 +763,18 @@ def test_importorskip_imports_last_module_part() -> None:
assert os.path == ospath assert os.path == ospath
def test_importorskip_importError_Exception() -> None: def test_importorskip_importError_warning(pytester: Pytester) -> None:
## Mocking the import function to raise a importError """
realimport = builtins.__import__ importorskip() will only skip modules by ImportError as well as ModuleNotFoundError
will give warning when using ImportError
#11523
"""
fn = pytester.makepyfile("raise ImportError('some specific problem')")
pytester.syspathinsert()
def myimport( with pytest.raises(pytest.skip.Exception):
name: str, with pytest.warns(PytestDeprecationWarning):
globals: Mapping[str, object] | None = None, pytest.importorskip(fn.stem, exc_type=ImportError)
locals: Mapping[str, object] | None = None,
fromlist: Sequence[str] = (),
level: int = 0,
) -> types.ModuleType:
raise ImportError
builtins.__import__ = myimport
with pytest.raises(ImportError):
pytest.importorskip("abcdefghi")
builtins.__import__ = realimport
def test_importorskip_dev_module(monkeypatch) -> None: def test_importorskip_dev_module(monkeypatch) -> None: