monkeypatch: add type annotations
This commit is contained in:
		
							parent
							
								
									f84ffd9747
								
							
						
					
					
						commit
						b4f046b777
					
				| 
						 | 
					@ -4,17 +4,29 @@ import re
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import warnings
 | 
					import warnings
 | 
				
			||||||
from contextlib import contextmanager
 | 
					from contextlib import contextmanager
 | 
				
			||||||
 | 
					from typing import Any
 | 
				
			||||||
from typing import Generator
 | 
					from typing import Generator
 | 
				
			||||||
 | 
					from typing import List
 | 
				
			||||||
 | 
					from typing import MutableMapping
 | 
				
			||||||
 | 
					from typing import Optional
 | 
				
			||||||
 | 
					from typing import Tuple
 | 
				
			||||||
 | 
					from typing import TypeVar
 | 
				
			||||||
 | 
					from typing import Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
 | 
					from _pytest.compat import overload
 | 
				
			||||||
from _pytest.fixtures import fixture
 | 
					from _pytest.fixtures import fixture
 | 
				
			||||||
from _pytest.pathlib import Path
 | 
					from _pytest.pathlib import Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RE_IMPORT_ERROR_NAME = re.compile(r"^No module named (.*)$")
 | 
					RE_IMPORT_ERROR_NAME = re.compile(r"^No module named (.*)$")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					K = TypeVar("K")
 | 
				
			||||||
 | 
					V = TypeVar("V")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@fixture
 | 
					@fixture
 | 
				
			||||||
def monkeypatch():
 | 
					def monkeypatch() -> Generator["MonkeyPatch", None, None]:
 | 
				
			||||||
    """The returned ``monkeypatch`` fixture provides these
 | 
					    """The returned ``monkeypatch`` fixture provides these
 | 
				
			||||||
    helper methods to modify objects, dictionaries or os.environ::
 | 
					    helper methods to modify objects, dictionaries or os.environ::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,7 +49,7 @@ def monkeypatch():
 | 
				
			||||||
    mpatch.undo()
 | 
					    mpatch.undo()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def resolve(name):
 | 
					def resolve(name: str) -> object:
 | 
				
			||||||
    # simplified from zope.dottedname
 | 
					    # simplified from zope.dottedname
 | 
				
			||||||
    parts = name.split(".")
 | 
					    parts = name.split(".")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,7 +78,7 @@ def resolve(name):
 | 
				
			||||||
    return found
 | 
					    return found
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def annotated_getattr(obj, name, ann):
 | 
					def annotated_getattr(obj: object, name: str, ann: str) -> object:
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        obj = getattr(obj, name)
 | 
					        obj = getattr(obj, name)
 | 
				
			||||||
    except AttributeError:
 | 
					    except AttributeError:
 | 
				
			||||||
| 
						 | 
					@ -78,7 +90,7 @@ def annotated_getattr(obj, name, ann):
 | 
				
			||||||
    return obj
 | 
					    return obj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def derive_importpath(import_path, raising):
 | 
					def derive_importpath(import_path: str, raising: bool) -> Tuple[str, object]:
 | 
				
			||||||
    if not isinstance(import_path, str) or "." not in import_path:
 | 
					    if not isinstance(import_path, str) or "." not in import_path:
 | 
				
			||||||
        raise TypeError(
 | 
					        raise TypeError(
 | 
				
			||||||
            "must be absolute import path string, not {!r}".format(import_path)
 | 
					            "must be absolute import path string, not {!r}".format(import_path)
 | 
				
			||||||
| 
						 | 
					@ -91,7 +103,7 @@ def derive_importpath(import_path, raising):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Notset:
 | 
					class Notset:
 | 
				
			||||||
    def __repr__(self):
 | 
					    def __repr__(self) -> str:
 | 
				
			||||||
        return "<notset>"
 | 
					        return "<notset>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -102,11 +114,13 @@ class MonkeyPatch:
 | 
				
			||||||
    """ Object returned by the ``monkeypatch`` fixture keeping a record of setattr/item/env/syspath changes.
 | 
					    """ Object returned by the ``monkeypatch`` fixture keeping a record of setattr/item/env/syspath changes.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self) -> None:
 | 
				
			||||||
        self._setattr = []
 | 
					        self._setattr = []  # type: List[Tuple[object, str, object]]
 | 
				
			||||||
        self._setitem = []
 | 
					        self._setitem = (
 | 
				
			||||||
        self._cwd = None
 | 
					            []
 | 
				
			||||||
        self._savesyspath = None
 | 
					        )  # type: List[Tuple[MutableMapping[Any, Any], object, object]]
 | 
				
			||||||
 | 
					        self._cwd = None  # type: Optional[str]
 | 
				
			||||||
 | 
					        self._savesyspath = None  # type: Optional[List[str]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @contextmanager
 | 
					    @contextmanager
 | 
				
			||||||
    def context(self) -> Generator["MonkeyPatch", None, None]:
 | 
					    def context(self) -> Generator["MonkeyPatch", None, None]:
 | 
				
			||||||
| 
						 | 
					@ -133,7 +147,25 @@ class MonkeyPatch:
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
            m.undo()
 | 
					            m.undo()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setattr(self, target, name, value=notset, raising=True):
 | 
					    @overload
 | 
				
			||||||
 | 
					    def setattr(
 | 
				
			||||||
 | 
					        self, target: str, name: object, value: Notset = ..., raising: bool = ...,
 | 
				
			||||||
 | 
					    ) -> None:
 | 
				
			||||||
 | 
					        raise NotImplementedError()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @overload  # noqa: F811
 | 
				
			||||||
 | 
					    def setattr(  # noqa: F811
 | 
				
			||||||
 | 
					        self, target: object, name: str, value: object, raising: bool = ...,
 | 
				
			||||||
 | 
					    ) -> None:
 | 
				
			||||||
 | 
					        raise NotImplementedError()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setattr(  # noqa: F811
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        target: Union[str, object],
 | 
				
			||||||
 | 
					        name: Union[object, str],
 | 
				
			||||||
 | 
					        value: object = notset,
 | 
				
			||||||
 | 
					        raising: bool = True,
 | 
				
			||||||
 | 
					    ) -> None:
 | 
				
			||||||
        """ Set attribute value on target, memorizing the old value.
 | 
					        """ Set attribute value on target, memorizing the old value.
 | 
				
			||||||
        By default raise AttributeError if the attribute did not exist.
 | 
					        By default raise AttributeError if the attribute did not exist.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,7 +182,7 @@ class MonkeyPatch:
 | 
				
			||||||
        __tracebackhide__ = True
 | 
					        __tracebackhide__ = True
 | 
				
			||||||
        import inspect
 | 
					        import inspect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if value is notset:
 | 
					        if isinstance(value, Notset):
 | 
				
			||||||
            if not isinstance(target, str):
 | 
					            if not isinstance(target, str):
 | 
				
			||||||
                raise TypeError(
 | 
					                raise TypeError(
 | 
				
			||||||
                    "use setattr(target, name, value) or "
 | 
					                    "use setattr(target, name, value) or "
 | 
				
			||||||
| 
						 | 
					@ -159,6 +191,13 @@ class MonkeyPatch:
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            value = name
 | 
					            value = name
 | 
				
			||||||
            name, target = derive_importpath(target, raising)
 | 
					            name, target = derive_importpath(target, raising)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if not isinstance(name, str):
 | 
				
			||||||
 | 
					                raise TypeError(
 | 
				
			||||||
 | 
					                    "use setattr(target, name, value) with name being a string or "
 | 
				
			||||||
 | 
					                    "setattr(target, value) with target being a dotted "
 | 
				
			||||||
 | 
					                    "import string"
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        oldval = getattr(target, name, notset)
 | 
					        oldval = getattr(target, name, notset)
 | 
				
			||||||
        if raising and oldval is notset:
 | 
					        if raising and oldval is notset:
 | 
				
			||||||
| 
						 | 
					@ -170,7 +209,12 @@ class MonkeyPatch:
 | 
				
			||||||
        self._setattr.append((target, name, oldval))
 | 
					        self._setattr.append((target, name, oldval))
 | 
				
			||||||
        setattr(target, name, value)
 | 
					        setattr(target, name, value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delattr(self, target, name=notset, raising=True):
 | 
					    def delattr(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        target: Union[object, str],
 | 
				
			||||||
 | 
					        name: Union[str, Notset] = notset,
 | 
				
			||||||
 | 
					        raising: bool = True,
 | 
				
			||||||
 | 
					    ) -> None:
 | 
				
			||||||
        """ Delete attribute ``name`` from ``target``, by default raise
 | 
					        """ Delete attribute ``name`` from ``target``, by default raise
 | 
				
			||||||
        AttributeError it the attribute did not previously exist.
 | 
					        AttributeError it the attribute did not previously exist.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -184,7 +228,7 @@ class MonkeyPatch:
 | 
				
			||||||
        __tracebackhide__ = True
 | 
					        __tracebackhide__ = True
 | 
				
			||||||
        import inspect
 | 
					        import inspect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if name is notset:
 | 
					        if isinstance(name, Notset):
 | 
				
			||||||
            if not isinstance(target, str):
 | 
					            if not isinstance(target, str):
 | 
				
			||||||
                raise TypeError(
 | 
					                raise TypeError(
 | 
				
			||||||
                    "use delattr(target, name) or "
 | 
					                    "use delattr(target, name) or "
 | 
				
			||||||
| 
						 | 
					@ -204,12 +248,12 @@ class MonkeyPatch:
 | 
				
			||||||
            self._setattr.append((target, name, oldval))
 | 
					            self._setattr.append((target, name, oldval))
 | 
				
			||||||
            delattr(target, name)
 | 
					            delattr(target, name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setitem(self, dic, name, value):
 | 
					    def setitem(self, dic: MutableMapping[K, V], name: K, value: V) -> None:
 | 
				
			||||||
        """ Set dictionary entry ``name`` to value. """
 | 
					        """ Set dictionary entry ``name`` to value. """
 | 
				
			||||||
        self._setitem.append((dic, name, dic.get(name, notset)))
 | 
					        self._setitem.append((dic, name, dic.get(name, notset)))
 | 
				
			||||||
        dic[name] = value
 | 
					        dic[name] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delitem(self, dic, name, raising=True):
 | 
					    def delitem(self, dic: MutableMapping[K, V], name: K, raising: bool = True) -> None:
 | 
				
			||||||
        """ Delete ``name`` from dict. Raise KeyError if it doesn't exist.
 | 
					        """ Delete ``name`` from dict. Raise KeyError if it doesn't exist.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        If ``raising`` is set to False, no exception will be raised if the
 | 
					        If ``raising`` is set to False, no exception will be raised if the
 | 
				
			||||||
| 
						 | 
					@ -222,7 +266,7 @@ class MonkeyPatch:
 | 
				
			||||||
            self._setitem.append((dic, name, dic.get(name, notset)))
 | 
					            self._setitem.append((dic, name, dic.get(name, notset)))
 | 
				
			||||||
            del dic[name]
 | 
					            del dic[name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setenv(self, name, value, prepend=None):
 | 
					    def setenv(self, name: str, value: str, prepend: Optional[str] = None) -> None:
 | 
				
			||||||
        """ Set environment variable ``name`` to ``value``.  If ``prepend``
 | 
					        """ Set environment variable ``name`` to ``value``.  If ``prepend``
 | 
				
			||||||
        is a character, read the current environment variable value
 | 
					        is a character, read the current environment variable value
 | 
				
			||||||
        and prepend the ``value`` adjoined with the ``prepend`` character."""
 | 
					        and prepend the ``value`` adjoined with the ``prepend`` character."""
 | 
				
			||||||
| 
						 | 
					@ -241,16 +285,17 @@ class MonkeyPatch:
 | 
				
			||||||
            value = value + prepend + os.environ[name]
 | 
					            value = value + prepend + os.environ[name]
 | 
				
			||||||
        self.setitem(os.environ, name, value)
 | 
					        self.setitem(os.environ, name, value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delenv(self, name, raising=True):
 | 
					    def delenv(self, name: str, raising: bool = True) -> None:
 | 
				
			||||||
        """ Delete ``name`` from the environment. Raise KeyError if it does
 | 
					        """ Delete ``name`` from the environment. Raise KeyError if it does
 | 
				
			||||||
        not exist.
 | 
					        not exist.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        If ``raising`` is set to False, no exception will be raised if the
 | 
					        If ``raising`` is set to False, no exception will be raised if the
 | 
				
			||||||
        environment variable is missing.
 | 
					        environment variable is missing.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        self.delitem(os.environ, name, raising=raising)
 | 
					        environ = os.environ  # type: MutableMapping[str, str]
 | 
				
			||||||
 | 
					        self.delitem(environ, name, raising=raising)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def syspath_prepend(self, path):
 | 
					    def syspath_prepend(self, path) -> None:
 | 
				
			||||||
        """ Prepend ``path`` to ``sys.path`` list of import locations. """
 | 
					        """ Prepend ``path`` to ``sys.path`` list of import locations. """
 | 
				
			||||||
        from pkg_resources import fixup_namespace_packages
 | 
					        from pkg_resources import fixup_namespace_packages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -272,7 +317,7 @@ class MonkeyPatch:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        invalidate_caches()
 | 
					        invalidate_caches()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def chdir(self, path):
 | 
					    def chdir(self, path) -> None:
 | 
				
			||||||
        """ Change the current working directory to the specified path.
 | 
					        """ Change the current working directory to the specified path.
 | 
				
			||||||
        Path can be a string or a py.path.local object.
 | 
					        Path can be a string or a py.path.local object.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
| 
						 | 
					@ -286,7 +331,7 @@ class MonkeyPatch:
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            os.chdir(path)
 | 
					            os.chdir(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def undo(self):
 | 
					    def undo(self) -> None:
 | 
				
			||||||
        """ Undo previous changes.  This call consumes the
 | 
					        """ Undo previous changes.  This call consumes the
 | 
				
			||||||
        undo stack. Calling it a second time has no effect unless
 | 
					        undo stack. Calling it a second time has no effect unless
 | 
				
			||||||
        you do more monkeypatching after the undo call.
 | 
					        you do more monkeypatching after the undo call.
 | 
				
			||||||
| 
						 | 
					@ -306,14 +351,14 @@ class MonkeyPatch:
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                delattr(obj, name)
 | 
					                delattr(obj, name)
 | 
				
			||||||
        self._setattr[:] = []
 | 
					        self._setattr[:] = []
 | 
				
			||||||
        for dictionary, name, value in reversed(self._setitem):
 | 
					        for dictionary, key, value in reversed(self._setitem):
 | 
				
			||||||
            if value is notset:
 | 
					            if value is notset:
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    del dictionary[name]
 | 
					                    del dictionary[key]
 | 
				
			||||||
                except KeyError:
 | 
					                except KeyError:
 | 
				
			||||||
                    pass  # was already deleted, so we have the desired state
 | 
					                    pass  # was already deleted, so we have the desired state
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                dictionary[name] = value
 | 
					                dictionary[key] = value
 | 
				
			||||||
        self._setitem[:] = []
 | 
					        self._setitem[:] = []
 | 
				
			||||||
        if self._savesyspath is not None:
 | 
					        if self._savesyspath is not None:
 | 
				
			||||||
            sys.path[:] = self._savesyspath
 | 
					            sys.path[:] = self._savesyspath
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,9 +5,12 @@ import textwrap
 | 
				
			||||||
from typing import Dict
 | 
					from typing import Dict
 | 
				
			||||||
from typing import Generator
 | 
					from typing import Generator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from _pytest.compat import TYPE_CHECKING
 | 
					from _pytest.compat import TYPE_CHECKING
 | 
				
			||||||
from _pytest.monkeypatch import MonkeyPatch
 | 
					from _pytest.monkeypatch import MonkeyPatch
 | 
				
			||||||
 | 
					from _pytest.pytester import Testdir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if TYPE_CHECKING:
 | 
					if TYPE_CHECKING:
 | 
				
			||||||
    from typing import Type
 | 
					    from typing import Type
 | 
				
			||||||
| 
						 | 
					@ -45,9 +48,12 @@ def test_setattr() -> None:
 | 
				
			||||||
    monkeypatch.undo()  # double-undo makes no modification
 | 
					    monkeypatch.undo()  # double-undo makes no modification
 | 
				
			||||||
    assert A.x == 5
 | 
					    assert A.x == 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with pytest.raises(TypeError):
 | 
				
			||||||
 | 
					        monkeypatch.setattr(A, "y")  # type: ignore[call-overload]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestSetattrWithImportPath:
 | 
					class TestSetattrWithImportPath:
 | 
				
			||||||
    def test_string_expression(self, monkeypatch):
 | 
					    def test_string_expression(self, monkeypatch: MonkeyPatch) -> None:
 | 
				
			||||||
        monkeypatch.setattr("os.path.abspath", lambda x: "hello2")
 | 
					        monkeypatch.setattr("os.path.abspath", lambda x: "hello2")
 | 
				
			||||||
        assert os.path.abspath("123") == "hello2"
 | 
					        assert os.path.abspath("123") == "hello2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,30 +70,31 @@ class TestSetattrWithImportPath:
 | 
				
			||||||
        assert _pytest.config.Config == 42  # type: ignore
 | 
					        assert _pytest.config.Config == 42  # type: ignore
 | 
				
			||||||
        monkeypatch.delattr("_pytest.config.Config")
 | 
					        monkeypatch.delattr("_pytest.config.Config")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_wrong_target(self, monkeypatch):
 | 
					    def test_wrong_target(self, monkeypatch: MonkeyPatch) -> None:
 | 
				
			||||||
        pytest.raises(TypeError, lambda: monkeypatch.setattr(None, None))
 | 
					        with pytest.raises(TypeError):
 | 
				
			||||||
 | 
					            monkeypatch.setattr(None, None)  # type: ignore[call-overload]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_unknown_import(self, monkeypatch):
 | 
					    def test_unknown_import(self, monkeypatch: MonkeyPatch) -> None:
 | 
				
			||||||
        pytest.raises(ImportError, lambda: monkeypatch.setattr("unkn123.classx", None))
 | 
					        with pytest.raises(ImportError):
 | 
				
			||||||
 | 
					            monkeypatch.setattr("unkn123.classx", None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_unknown_attr(self, monkeypatch):
 | 
					    def test_unknown_attr(self, monkeypatch: MonkeyPatch) -> None:
 | 
				
			||||||
        pytest.raises(
 | 
					        with pytest.raises(AttributeError):
 | 
				
			||||||
            AttributeError, lambda: monkeypatch.setattr("os.path.qweqwe", None)
 | 
					            monkeypatch.setattr("os.path.qweqwe", None)
 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_unknown_attr_non_raising(self, monkeypatch: MonkeyPatch) -> None:
 | 
					    def test_unknown_attr_non_raising(self, monkeypatch: MonkeyPatch) -> None:
 | 
				
			||||||
        # https://github.com/pytest-dev/pytest/issues/746
 | 
					        # https://github.com/pytest-dev/pytest/issues/746
 | 
				
			||||||
        monkeypatch.setattr("os.path.qweqwe", 42, raising=False)
 | 
					        monkeypatch.setattr("os.path.qweqwe", 42, raising=False)
 | 
				
			||||||
        assert os.path.qweqwe == 42  # type: ignore
 | 
					        assert os.path.qweqwe == 42  # type: ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_delattr(self, monkeypatch):
 | 
					    def test_delattr(self, monkeypatch: MonkeyPatch) -> None:
 | 
				
			||||||
        monkeypatch.delattr("os.path.abspath")
 | 
					        monkeypatch.delattr("os.path.abspath")
 | 
				
			||||||
        assert not hasattr(os.path, "abspath")
 | 
					        assert not hasattr(os.path, "abspath")
 | 
				
			||||||
        monkeypatch.undo()
 | 
					        monkeypatch.undo()
 | 
				
			||||||
        assert os.path.abspath
 | 
					        assert os.path.abspath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_delattr():
 | 
					def test_delattr() -> None:
 | 
				
			||||||
    class A:
 | 
					    class A:
 | 
				
			||||||
        x = 1
 | 
					        x = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,7 +114,7 @@ def test_delattr():
 | 
				
			||||||
    assert A.x == 1
 | 
					    assert A.x == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_setitem():
 | 
					def test_setitem() -> None:
 | 
				
			||||||
    d = {"x": 1}
 | 
					    d = {"x": 1}
 | 
				
			||||||
    monkeypatch = MonkeyPatch()
 | 
					    monkeypatch = MonkeyPatch()
 | 
				
			||||||
    monkeypatch.setitem(d, "x", 2)
 | 
					    monkeypatch.setitem(d, "x", 2)
 | 
				
			||||||
| 
						 | 
					@ -135,7 +142,7 @@ def test_setitem_deleted_meanwhile() -> None:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize("before", [True, False])
 | 
					@pytest.mark.parametrize("before", [True, False])
 | 
				
			||||||
def test_setenv_deleted_meanwhile(before):
 | 
					def test_setenv_deleted_meanwhile(before: bool) -> None:
 | 
				
			||||||
    key = "qwpeoip123"
 | 
					    key = "qwpeoip123"
 | 
				
			||||||
    if before:
 | 
					    if before:
 | 
				
			||||||
        os.environ[key] = "world"
 | 
					        os.environ[key] = "world"
 | 
				
			||||||
| 
						 | 
					@ -167,10 +174,10 @@ def test_delitem() -> None:
 | 
				
			||||||
    assert d == {"hello": "world", "x": 1}
 | 
					    assert d == {"hello": "world", "x": 1}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_setenv():
 | 
					def test_setenv() -> None:
 | 
				
			||||||
    monkeypatch = MonkeyPatch()
 | 
					    monkeypatch = MonkeyPatch()
 | 
				
			||||||
    with pytest.warns(pytest.PytestWarning):
 | 
					    with pytest.warns(pytest.PytestWarning):
 | 
				
			||||||
        monkeypatch.setenv("XYZ123", 2)
 | 
					        monkeypatch.setenv("XYZ123", 2)  # type: ignore[arg-type]
 | 
				
			||||||
    import os
 | 
					    import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert os.environ["XYZ123"] == "2"
 | 
					    assert os.environ["XYZ123"] == "2"
 | 
				
			||||||
| 
						 | 
					@ -178,7 +185,7 @@ def test_setenv():
 | 
				
			||||||
    assert "XYZ123" not in os.environ
 | 
					    assert "XYZ123" not in os.environ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_delenv():
 | 
					def test_delenv() -> None:
 | 
				
			||||||
    name = "xyz1234"
 | 
					    name = "xyz1234"
 | 
				
			||||||
    assert name not in os.environ
 | 
					    assert name not in os.environ
 | 
				
			||||||
    monkeypatch = MonkeyPatch()
 | 
					    monkeypatch = MonkeyPatch()
 | 
				
			||||||
| 
						 | 
					@ -208,31 +215,28 @@ class TestEnvironWarnings:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    VAR_NAME = "PYTEST_INTERNAL_MY_VAR"
 | 
					    VAR_NAME = "PYTEST_INTERNAL_MY_VAR"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_setenv_non_str_warning(self, monkeypatch):
 | 
					    def test_setenv_non_str_warning(self, monkeypatch: MonkeyPatch) -> None:
 | 
				
			||||||
        value = 2
 | 
					        value = 2
 | 
				
			||||||
        msg = (
 | 
					        msg = (
 | 
				
			||||||
            "Value of environment variable PYTEST_INTERNAL_MY_VAR type should be str, "
 | 
					            "Value of environment variable PYTEST_INTERNAL_MY_VAR type should be str, "
 | 
				
			||||||
            "but got 2 (type: int); converted to str implicitly"
 | 
					            "but got 2 (type: int); converted to str implicitly"
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        with pytest.warns(pytest.PytestWarning, match=re.escape(msg)):
 | 
					        with pytest.warns(pytest.PytestWarning, match=re.escape(msg)):
 | 
				
			||||||
            monkeypatch.setenv(str(self.VAR_NAME), value)
 | 
					            monkeypatch.setenv(str(self.VAR_NAME), value)  # type: ignore[arg-type]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_setenv_prepend():
 | 
					def test_setenv_prepend() -> None:
 | 
				
			||||||
    import os
 | 
					    import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    monkeypatch = MonkeyPatch()
 | 
					    monkeypatch = MonkeyPatch()
 | 
				
			||||||
    with pytest.warns(pytest.PytestWarning):
 | 
					    monkeypatch.setenv("XYZ123", "2", prepend="-")
 | 
				
			||||||
        monkeypatch.setenv("XYZ123", 2, prepend="-")
 | 
					    monkeypatch.setenv("XYZ123", "3", prepend="-")
 | 
				
			||||||
    assert os.environ["XYZ123"] == "2"
 | 
					 | 
				
			||||||
    with pytest.warns(pytest.PytestWarning):
 | 
					 | 
				
			||||||
        monkeypatch.setenv("XYZ123", 3, prepend="-")
 | 
					 | 
				
			||||||
    assert os.environ["XYZ123"] == "3-2"
 | 
					    assert os.environ["XYZ123"] == "3-2"
 | 
				
			||||||
    monkeypatch.undo()
 | 
					    monkeypatch.undo()
 | 
				
			||||||
    assert "XYZ123" not in os.environ
 | 
					    assert "XYZ123" not in os.environ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_monkeypatch_plugin(testdir):
 | 
					def test_monkeypatch_plugin(testdir: Testdir) -> None:
 | 
				
			||||||
    reprec = testdir.inline_runsource(
 | 
					    reprec = testdir.inline_runsource(
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        def test_method(monkeypatch):
 | 
					        def test_method(monkeypatch):
 | 
				
			||||||
| 
						 | 
					@ -243,7 +247,7 @@ def test_monkeypatch_plugin(testdir):
 | 
				
			||||||
    assert tuple(res) == (1, 0, 0), res
 | 
					    assert tuple(res) == (1, 0, 0), res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_syspath_prepend(mp: MonkeyPatch):
 | 
					def test_syspath_prepend(mp: MonkeyPatch) -> None:
 | 
				
			||||||
    old = list(sys.path)
 | 
					    old = list(sys.path)
 | 
				
			||||||
    mp.syspath_prepend("world")
 | 
					    mp.syspath_prepend("world")
 | 
				
			||||||
    mp.syspath_prepend("hello")
 | 
					    mp.syspath_prepend("hello")
 | 
				
			||||||
| 
						 | 
					@ -255,7 +259,7 @@ def test_syspath_prepend(mp: MonkeyPatch):
 | 
				
			||||||
    assert sys.path == old
 | 
					    assert sys.path == old
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_syspath_prepend_double_undo(mp: MonkeyPatch):
 | 
					def test_syspath_prepend_double_undo(mp: MonkeyPatch) -> None:
 | 
				
			||||||
    old_syspath = sys.path[:]
 | 
					    old_syspath = sys.path[:]
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        mp.syspath_prepend("hello world")
 | 
					        mp.syspath_prepend("hello world")
 | 
				
			||||||
| 
						 | 
					@ -267,24 +271,24 @@ def test_syspath_prepend_double_undo(mp: MonkeyPatch):
 | 
				
			||||||
        sys.path[:] = old_syspath
 | 
					        sys.path[:] = old_syspath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_chdir_with_path_local(mp: MonkeyPatch, tmpdir):
 | 
					def test_chdir_with_path_local(mp: MonkeyPatch, tmpdir: py.path.local) -> None:
 | 
				
			||||||
    mp.chdir(tmpdir)
 | 
					    mp.chdir(tmpdir)
 | 
				
			||||||
    assert os.getcwd() == tmpdir.strpath
 | 
					    assert os.getcwd() == tmpdir.strpath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_chdir_with_str(mp: MonkeyPatch, tmpdir):
 | 
					def test_chdir_with_str(mp: MonkeyPatch, tmpdir: py.path.local) -> None:
 | 
				
			||||||
    mp.chdir(tmpdir.strpath)
 | 
					    mp.chdir(tmpdir.strpath)
 | 
				
			||||||
    assert os.getcwd() == tmpdir.strpath
 | 
					    assert os.getcwd() == tmpdir.strpath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_chdir_undo(mp: MonkeyPatch, tmpdir):
 | 
					def test_chdir_undo(mp: MonkeyPatch, tmpdir: py.path.local) -> None:
 | 
				
			||||||
    cwd = os.getcwd()
 | 
					    cwd = os.getcwd()
 | 
				
			||||||
    mp.chdir(tmpdir)
 | 
					    mp.chdir(tmpdir)
 | 
				
			||||||
    mp.undo()
 | 
					    mp.undo()
 | 
				
			||||||
    assert os.getcwd() == cwd
 | 
					    assert os.getcwd() == cwd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_chdir_double_undo(mp: MonkeyPatch, tmpdir):
 | 
					def test_chdir_double_undo(mp: MonkeyPatch, tmpdir: py.path.local) -> None:
 | 
				
			||||||
    mp.chdir(tmpdir.strpath)
 | 
					    mp.chdir(tmpdir.strpath)
 | 
				
			||||||
    mp.undo()
 | 
					    mp.undo()
 | 
				
			||||||
    tmpdir.chdir()
 | 
					    tmpdir.chdir()
 | 
				
			||||||
| 
						 | 
					@ -292,7 +296,7 @@ def test_chdir_double_undo(mp: MonkeyPatch, tmpdir):
 | 
				
			||||||
    assert os.getcwd() == tmpdir.strpath
 | 
					    assert os.getcwd() == tmpdir.strpath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_issue185_time_breaks(testdir):
 | 
					def test_issue185_time_breaks(testdir: Testdir) -> None:
 | 
				
			||||||
    testdir.makepyfile(
 | 
					    testdir.makepyfile(
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        import time
 | 
					        import time
 | 
				
			||||||
| 
						 | 
					@ -310,7 +314,7 @@ def test_issue185_time_breaks(testdir):
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_importerror(testdir):
 | 
					def test_importerror(testdir: Testdir) -> None:
 | 
				
			||||||
    p = testdir.mkpydir("package")
 | 
					    p = testdir.mkpydir("package")
 | 
				
			||||||
    p.join("a.py").write(
 | 
					    p.join("a.py").write(
 | 
				
			||||||
        textwrap.dedent(
 | 
					        textwrap.dedent(
 | 
				
			||||||
| 
						 | 
					@ -360,7 +364,7 @@ def test_issue156_undo_staticmethod(Sample: "Type[Sample]") -> None:
 | 
				
			||||||
    assert Sample.hello()
 | 
					    assert Sample.hello()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_undo_class_descriptors_delattr():
 | 
					def test_undo_class_descriptors_delattr() -> None:
 | 
				
			||||||
    class SampleParent:
 | 
					    class SampleParent:
 | 
				
			||||||
        @classmethod
 | 
					        @classmethod
 | 
				
			||||||
        def hello(_cls):
 | 
					        def hello(_cls):
 | 
				
			||||||
| 
						 | 
					@ -387,7 +391,7 @@ def test_undo_class_descriptors_delattr():
 | 
				
			||||||
    assert original_world == SampleChild.world
 | 
					    assert original_world == SampleChild.world
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_issue1338_name_resolving():
 | 
					def test_issue1338_name_resolving() -> None:
 | 
				
			||||||
    pytest.importorskip("requests")
 | 
					    pytest.importorskip("requests")
 | 
				
			||||||
    monkeypatch = MonkeyPatch()
 | 
					    monkeypatch = MonkeyPatch()
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
| 
						 | 
					@ -396,7 +400,7 @@ def test_issue1338_name_resolving():
 | 
				
			||||||
        monkeypatch.undo()
 | 
					        monkeypatch.undo()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_context():
 | 
					def test_context() -> None:
 | 
				
			||||||
    monkeypatch = MonkeyPatch()
 | 
					    monkeypatch = MonkeyPatch()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    import functools
 | 
					    import functools
 | 
				
			||||||
| 
						 | 
					@ -408,7 +412,9 @@ def test_context():
 | 
				
			||||||
    assert inspect.isclass(functools.partial)
 | 
					    assert inspect.isclass(functools.partial)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_syspath_prepend_with_namespace_packages(testdir, monkeypatch):
 | 
					def test_syspath_prepend_with_namespace_packages(
 | 
				
			||||||
 | 
					    testdir: Testdir, monkeypatch: MonkeyPatch
 | 
				
			||||||
 | 
					) -> None:
 | 
				
			||||||
    for dirname in "hello", "world":
 | 
					    for dirname in "hello", "world":
 | 
				
			||||||
        d = testdir.mkdir(dirname)
 | 
					        d = testdir.mkdir(dirname)
 | 
				
			||||||
        ns = d.mkdir("ns_pkg")
 | 
					        ns = d.mkdir("ns_pkg")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue