Compare commits
7 Commits
6.3.0.dev0
...
6.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3971c30f4 | ||
|
|
780044b64a | ||
|
|
8354995abc | ||
|
|
8b8b1214f4 | ||
|
|
f854cf66f4 | ||
|
|
c475106f12 | ||
|
|
e7073afe6e |
@@ -6,6 +6,7 @@ Release announcements
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
release-6.2.1
|
||||
release-6.2.0
|
||||
release-6.1.2
|
||||
release-6.1.1
|
||||
|
||||
20
doc/en/announce/release-6.2.1.rst
Normal file
20
doc/en/announce/release-6.2.1.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
pytest-6.2.1
|
||||
=======================================
|
||||
|
||||
pytest 6.2.1 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Bruno Oliveira
|
||||
* Jakob van Santen
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -28,6 +28,28 @@ with advance notice in the **Deprecations** section of releases.
|
||||
|
||||
.. towncrier release notes start
|
||||
|
||||
pytest 6.2.1 (2020-12-15)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#7678 <https://github.com/pytest-dev/pytest/issues/7678>`_: Fixed bug where ``ImportPathMismatchError`` would be raised for files compiled in
|
||||
the host and loaded later from an UNC mounted path (Windows).
|
||||
|
||||
|
||||
- `#8132 <https://github.com/pytest-dev/pytest/issues/8132>`_: Fixed regression in ``approx``: in 6.2.0 ``approx`` no longer raises
|
||||
``TypeError`` when dealing with non-numeric types, falling back to normal comparison.
|
||||
Before 6.2.0, array types like tf.DeviceArray fell through to the scalar case,
|
||||
and happened to compare correctly to a scalar if they had only one element.
|
||||
After 6.2.0, these types began failing, because they inherited neither from
|
||||
standard Python number hierarchy nor from ``numpy.ndarray``.
|
||||
|
||||
``approx`` now converts arguments to ``numpy.ndarray`` if they expose the array
|
||||
protocol and are not scalars. This treats array-like objects like numpy arrays,
|
||||
regardless of size.
|
||||
|
||||
|
||||
pytest 6.2.0 (2020-12-12)
|
||||
=========================
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Install ``pytest``
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest --version
|
||||
pytest 6.2.0
|
||||
pytest 6.2.1
|
||||
|
||||
.. _`simpletest`:
|
||||
|
||||
|
||||
@@ -543,7 +543,7 @@ def import_path(
|
||||
module_file = module_file[: -(len(os.path.sep + "__init__.py"))]
|
||||
|
||||
try:
|
||||
is_same = os.path.samefile(str(path), module_file)
|
||||
is_same = _is_same(str(path), module_file)
|
||||
except FileNotFoundError:
|
||||
is_same = False
|
||||
|
||||
@@ -553,6 +553,20 @@ def import_path(
|
||||
return mod
|
||||
|
||||
|
||||
# Implement a special _is_same function on Windows which returns True if the two filenames
|
||||
# compare equal, to circumvent os.path.samefile returning False for mounts in UNC (#7678).
|
||||
if sys.platform.startswith("win"):
|
||||
|
||||
def _is_same(f1: str, f2: str) -> bool:
|
||||
return Path(f1) == Path(f2) or os.path.samefile(f1, f2)
|
||||
|
||||
|
||||
else:
|
||||
|
||||
def _is_same(f1: str, f2: str) -> bool:
|
||||
return os.path.samefile(f1, f2)
|
||||
|
||||
|
||||
def resolve_package_path(path: Path) -> Optional[Path]:
|
||||
"""Return the Python package path by looking for the last
|
||||
directory upwards which still contains an __init__.py.
|
||||
|
||||
@@ -15,9 +15,14 @@ from typing import overload
|
||||
from typing import Pattern
|
||||
from typing import Tuple
|
||||
from typing import Type
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TypeVar
|
||||
from typing import Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from numpy import ndarray
|
||||
|
||||
|
||||
import _pytest._code
|
||||
from _pytest.compat import final
|
||||
from _pytest.compat import STRING_TYPES
|
||||
@@ -232,10 +237,11 @@ class ApproxScalar(ApproxBase):
|
||||
def __eq__(self, actual) -> bool:
|
||||
"""Return whether the given value is equal to the expected value
|
||||
within the pre-specified tolerance."""
|
||||
if _is_numpy_array(actual):
|
||||
asarray = _as_numpy_array(actual)
|
||||
if asarray is not None:
|
||||
# Call ``__eq__()`` manually to prevent infinite-recursion with
|
||||
# numpy<1.13. See #3748.
|
||||
return all(self.__eq__(a) for a in actual.flat)
|
||||
return all(self.__eq__(a) for a in asarray.flat)
|
||||
|
||||
# Short-circuit exact equality.
|
||||
if actual == self.expected:
|
||||
@@ -521,6 +527,7 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
|
||||
elif isinstance(expected, Mapping):
|
||||
cls = ApproxMapping
|
||||
elif _is_numpy_array(expected):
|
||||
expected = _as_numpy_array(expected)
|
||||
cls = ApproxNumpy
|
||||
elif (
|
||||
isinstance(expected, Iterable)
|
||||
@@ -536,16 +543,30 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase:
|
||||
|
||||
|
||||
def _is_numpy_array(obj: object) -> bool:
|
||||
"""Return true if the given object is a numpy array.
|
||||
"""
|
||||
Return true if the given object is implicitly convertible to ndarray,
|
||||
and numpy is already imported.
|
||||
"""
|
||||
return _as_numpy_array(obj) is not None
|
||||
|
||||
A special effort is made to avoid importing numpy unless it's really necessary.
|
||||
|
||||
def _as_numpy_array(obj: object) -> Optional["ndarray"]:
|
||||
"""
|
||||
Return an ndarray if the given object is implicitly convertible to ndarray,
|
||||
and numpy is already imported, otherwise None.
|
||||
"""
|
||||
import sys
|
||||
|
||||
np: Any = sys.modules.get("numpy")
|
||||
if np is not None:
|
||||
return isinstance(obj, np.ndarray)
|
||||
return False
|
||||
# avoid infinite recursion on numpy scalars, which have __array__
|
||||
if np.isscalar(obj):
|
||||
return None
|
||||
elif isinstance(obj, np.ndarray):
|
||||
return obj
|
||||
elif hasattr(obj, "__array__") or hasattr("obj", "__array_interface__"):
|
||||
return np.asarray(obj)
|
||||
return None
|
||||
|
||||
|
||||
# builtin pytest.raises helper
|
||||
|
||||
@@ -447,6 +447,36 @@ class TestApprox:
|
||||
assert a12 != approx(a21)
|
||||
assert a21 != approx(a12)
|
||||
|
||||
def test_numpy_array_protocol(self):
|
||||
"""
|
||||
array-like objects such as tensorflow's DeviceArray are handled like ndarray.
|
||||
See issue #8132
|
||||
"""
|
||||
np = pytest.importorskip("numpy")
|
||||
|
||||
class DeviceArray:
|
||||
def __init__(self, value, size):
|
||||
self.value = value
|
||||
self.size = size
|
||||
|
||||
def __array__(self):
|
||||
return self.value * np.ones(self.size)
|
||||
|
||||
class DeviceScalar:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __array__(self):
|
||||
return np.array(self.value)
|
||||
|
||||
expected = 1
|
||||
actual = 1 + 1e-6
|
||||
assert approx(expected) == DeviceArray(actual, size=1)
|
||||
assert approx(expected) == DeviceArray(actual, size=2)
|
||||
assert approx(expected) == DeviceScalar(actual)
|
||||
assert approx(DeviceScalar(expected)) == actual
|
||||
assert approx(DeviceScalar(expected)) == DeviceScalar(actual)
|
||||
|
||||
def test_doctests(self, mocked_doctest_runner) -> None:
|
||||
import doctest
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ from textwrap import dedent
|
||||
import py
|
||||
|
||||
import pytest
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
from _pytest.pathlib import bestrelpath
|
||||
from _pytest.pathlib import commonpath
|
||||
from _pytest.pathlib import ensure_deletable
|
||||
@@ -414,3 +415,23 @@ def test_visit_ignores_errors(tmpdir) -> None:
|
||||
"bar",
|
||||
"foo",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
|
||||
def test_samefile_false_negatives(tmp_path: Path, monkeypatch: MonkeyPatch) -> None:
|
||||
"""
|
||||
import_file() should not raise ImportPathMismatchError if the paths are exactly
|
||||
equal on Windows. It seems directories mounted as UNC paths make os.path.samefile
|
||||
return False, even when they are clearly equal.
|
||||
"""
|
||||
module_path = tmp_path.joinpath("my_module.py")
|
||||
module_path.write_text("def foo(): return 42")
|
||||
monkeypatch.syspath_prepend(tmp_path)
|
||||
|
||||
with monkeypatch.context() as mp:
|
||||
# Forcibly make os.path.samefile() return False here to ensure we are comparing
|
||||
# the paths too. Using a context to narrow the patch as much as possible given
|
||||
# this is an important system function.
|
||||
mp.setattr(os.path, "samefile", lambda x, y: False)
|
||||
module = import_path(module_path)
|
||||
assert getattr(module, "foo")() == 42
|
||||
|
||||
Reference in New Issue
Block a user