chore: move to Ruff and add rules (#4483)

This commit is contained in:
Henry Schreiner 2023-02-22 06:18:55 -08:00 committed by GitHub
parent a19daeac16
commit 438034c5b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 266 additions and 279 deletions

View File

@ -39,19 +39,6 @@ repos:
- id: requirements-txt-fixer - id: requirements-txt-fixer
- id: trailing-whitespace - id: trailing-whitespace
# Upgrade old Python syntax
- repo: https://github.com/asottile/pyupgrade
rev: "v3.3.1"
hooks:
- id: pyupgrade
args: [--py36-plus]
# Nicely sort includes
- repo: https://github.com/PyCQA/isort
rev: "5.12.0"
hooks:
- id: isort
# Black, the code formatter, natively supports pre-commit # Black, the code formatter, natively supports pre-commit
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: "23.1.0" # Keep in sync with blacken-docs rev: "23.1.0" # Keep in sync with blacken-docs
@ -72,47 +59,28 @@ repos:
hooks: hooks:
- id: remove-tabs - id: remove-tabs
# Avoid directional quotes
- repo: https://github.com/sirosen/texthooks - repo: https://github.com/sirosen/texthooks
rev: "0.5.0" rev: "0.5.0"
hooks: hooks:
- id: fix-ligatures - id: fix-ligatures
- id: fix-smartquotes - id: fix-smartquotes
# Autoremoves unused imports # Ruff, the Python auto-correcting linter written in Rust
- repo: https://github.com/hadialqattan/pycln - repo: https://github.com/charliermarsh/ruff-pre-commit
rev: "v2.1.3" rev: v0.0.251
hooks: hooks:
- id: pycln - id: ruff
stages: [manual] args: ["--fix", "--show-fixes"]
# Checking for common mistakes # Checking for common mistakes
- repo: https://github.com/pre-commit/pygrep-hooks - repo: https://github.com/pre-commit/pygrep-hooks
rev: "v1.10.0" rev: "v1.10.0"
hooks: hooks:
- id: python-check-blanket-noqa
- id: python-check-blanket-type-ignore
- id: python-no-log-warn
- id: python-use-type-annotations
- id: rst-backticks - id: rst-backticks
- id: rst-directive-colons - id: rst-directive-colons
- id: rst-inline-touching-normal - id: rst-inline-touching-normal
# Automatically remove noqa that are not used
- repo: https://github.com/asottile/yesqa
rev: "v1.4.0"
hooks:
- id: yesqa
additional_dependencies: &flake8_dependencies
- flake8-bugbear
- pep8-naming
# Flake8 also supports pre-commit natively (same author)
- repo: https://github.com/PyCQA/flake8
rev: "6.0.0"
hooks:
- id: flake8
exclude: ^(docs/.*|tools/.*)$
additional_dependencies: *flake8_dependencies
# PyLint has native support - not always usable, but works for us # PyLint has native support - not always usable, but works for us
- repo: https://github.com/PyCQA/pylint - repo: https://github.com/PyCQA/pylint

View File

@ -353,7 +353,7 @@ def prepare(app):
f.write(contents) f.write(contents)
def clean_up(app, exception): def clean_up(app, exception): # noqa: ARG001
(DIR / "readme.rst").unlink() (DIR / "readme.rst").unlink()

View File

@ -1,6 +1,6 @@
import sys import sys
if sys.version_info < (3, 6): if sys.version_info < (3, 6): # noqa: UP036
msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5." msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5."
raise ImportError(msg) raise ImportError(msg)

View File

@ -3,7 +3,7 @@ import os
DIR = os.path.abspath(os.path.dirname(__file__)) DIR = os.path.abspath(os.path.dirname(__file__))
def get_include(user: bool = False) -> str: # pylint: disable=unused-argument def get_include(user: bool = False) -> str: # noqa: ARG001
""" """
Return the path to the pybind11 include directory. The historical "user" Return the path to the pybind11 include directory. The historical "user"
argument is unused, and may be removed. argument is unused, and may be removed.

View File

@ -341,7 +341,7 @@ def naive_recompile(obj: str, src: str) -> bool:
return os.stat(obj).st_mtime < os.stat(src).st_mtime return os.stat(obj).st_mtime < os.stat(src).st_mtime
def no_recompile(obg: str, src: str) -> bool: # pylint: disable=unused-argument def no_recompile(obg: str, src: str) -> bool: # noqa: ARG001
""" """
This is the safest but slowest choice (and is the default) - will always This is the safest but slowest choice (and is the default) - will always
recompile sources. recompile sources.

View File

@ -15,12 +15,6 @@ ignore = [
"noxfile.py", "noxfile.py",
] ]
[tool.isort]
# Needs the compiled .so modules and env.py from tests
known_first_party = "env,pybind11_cross_module_tests,pybind11_tests,"
# For black compatibility
profile = "black"
[tool.mypy] [tool.mypy]
files = ["pybind11"] files = ["pybind11"]
python_version = "3.6" python_version = "3.6"
@ -58,4 +52,44 @@ messages_control.disable = [
"invalid-name", "invalid-name",
"protected-access", "protected-access",
"missing-module-docstring", "missing-module-docstring",
"unused-argument", # covered by Ruff ARG
] ]
[tool.ruff]
select = [
"E", "F", "W", # flake8
"B", "B904", # flake8-bugbear
"I", # isort
"N", # pep8-naming
"ARG", # flake8-unused-arguments
"C4", # flake8-comprehensions
"EM", # flake8-errmsg
"ICN", # flake8-import-conventions
"ISC", # flake8-implicit-str-concat
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PL", # pylint
"PT", # flake8-pytest-style
"RET", # flake8-return
"RUF100", # Ruff-specific
"SIM", # flake8-simplify
"UP", # pyupgrade
"YTT", # flake8-2020
]
ignore = [
"PLR", # Design related pylint
"E501", # Line too long (Black is enough)
"PT011", # Too broad with raises in pytest
"PT004", # Fixture that doesn't return needs underscore (no, it is fine)
"SIM118",# iter(x) is not always the same as iter(x.keys())
]
target-version = "py37"
typing-modules = ["scikit_build_core._compat.typing"]
src = ["src"]
unfixable = ["T20"]
exclude = []
line-length = 120
isort.known-first-party = ["env", "pybind11_cross_module_tests", "pybind11_tests"]
[tool.ruff.per-file-ignores]
"tests/**" = ["EM", "N"]

View File

@ -40,11 +40,3 @@ project_urls =
[options] [options]
python_requires = >=3.6 python_requires = >=3.6
zip_safe = False zip_safe = False
[flake8]
max-line-length = 120
show_source = True
exclude = .git, __pycache__, build, dist, docs, tools, venv
extend-ignore = E203, E722
extend-select = B902, B904

View File

@ -83,9 +83,8 @@ class Output:
b = _strip_and_dedent(other).splitlines() b = _strip_and_dedent(other).splitlines()
if a == b: if a == b:
return True return True
else: self.explanation = _make_explanation(a, b)
self.explanation = _make_explanation(a, b) return False
return False
class Unordered(Output): class Unordered(Output):
@ -96,9 +95,8 @@ class Unordered(Output):
b = _split_and_sort(other) b = _split_and_sort(other)
if a == b: if a == b:
return True return True
else: self.explanation = _make_explanation(a, b)
self.explanation = _make_explanation(a, b) return False
return False
class Capture: class Capture:
@ -119,9 +117,8 @@ class Capture:
b = other b = other
if a == b: if a == b:
return True return True
else: self.explanation = a.explanation
self.explanation = a.explanation return False
return False
def __str__(self): def __str__(self):
return self.out return self.out
@ -138,7 +135,7 @@ class Capture:
return Output(self.err) return Output(self.err)
@pytest.fixture @pytest.fixture()
def capture(capsys): def capture(capsys):
"""Extended `capsys` with context manager and custom equality operators""" """Extended `capsys` with context manager and custom equality operators"""
return Capture(capsys) return Capture(capsys)
@ -159,25 +156,22 @@ class SanitizedString:
b = _strip_and_dedent(other) b = _strip_and_dedent(other)
if a == b: if a == b:
return True return True
else: self.explanation = _make_explanation(a.splitlines(), b.splitlines())
self.explanation = _make_explanation(a.splitlines(), b.splitlines()) return False
return False
def _sanitize_general(s): def _sanitize_general(s):
s = s.strip() s = s.strip()
s = s.replace("pybind11_tests.", "m.") s = s.replace("pybind11_tests.", "m.")
s = _long_marker.sub(r"\1", s) return _long_marker.sub(r"\1", s)
return s
def _sanitize_docstring(thing): def _sanitize_docstring(thing):
s = thing.__doc__ s = thing.__doc__
s = _sanitize_general(s) return _sanitize_general(s)
return s
@pytest.fixture @pytest.fixture()
def doc(): def doc():
"""Sanitize docstrings and add custom failure explanation""" """Sanitize docstrings and add custom failure explanation"""
return SanitizedString(_sanitize_docstring) return SanitizedString(_sanitize_docstring)
@ -186,30 +180,20 @@ def doc():
def _sanitize_message(thing): def _sanitize_message(thing):
s = str(thing) s = str(thing)
s = _sanitize_general(s) s = _sanitize_general(s)
s = _hexadecimal.sub("0", s) return _hexadecimal.sub("0", s)
return s
@pytest.fixture @pytest.fixture()
def msg(): def msg():
"""Sanitize messages and add custom failure explanation""" """Sanitize messages and add custom failure explanation"""
return SanitizedString(_sanitize_message) return SanitizedString(_sanitize_message)
# noinspection PyUnusedLocal def pytest_assertrepr_compare(op, left, right): # noqa: ARG001
def pytest_assertrepr_compare(op, left, right):
"""Hook to insert custom failure explanation""" """Hook to insert custom failure explanation"""
if hasattr(left, "explanation"): if hasattr(left, "explanation"):
return left.explanation return left.explanation
return None
@contextlib.contextmanager
def suppress(exception):
"""Suppress the desired exception"""
try:
yield
except exception:
pass
def gc_collect(): def gc_collect():
@ -220,7 +204,7 @@ def gc_collect():
def pytest_configure(): def pytest_configure():
pytest.suppress = suppress pytest.suppress = contextlib.suppress
pytest.gc_collect = gc_collect pytest.gc_collect = gc_collect

View File

@ -24,5 +24,4 @@ def deprecated_call():
pytest_major_minor = (int(pieces[0]), int(pieces[1])) pytest_major_minor = (int(pieces[0]), int(pieces[1]))
if pytest_major_minor < (3, 9): if pytest_major_minor < (3, 9):
return pytest.warns((DeprecationWarning, PendingDeprecationWarning)) return pytest.warns((DeprecationWarning, PendingDeprecationWarning))
else: return pytest.deprecated_call()
return pytest.deprecated_call()

View File

@ -4,7 +4,7 @@ asyncio = pytest.importorskip("asyncio")
m = pytest.importorskip("pybind11_tests.async_module") m = pytest.importorskip("pybind11_tests.async_module")
@pytest.fixture @pytest.fixture()
def event_loop(): def event_loop():
loop = asyncio.new_event_loop() loop = asyncio.new_event_loop()
yield loop yield loop
@ -16,7 +16,7 @@ async def get_await_result(x):
def test_await(event_loop): def test_await(event_loop):
assert 5 == event_loop.run_until_complete(get_await_result(m.SupportsAsync())) assert event_loop.run_until_complete(get_await_result(m.SupportsAsync())) == 5
def test_await_missing(event_loop): def test_await_missing(event_loop):

View File

@ -54,7 +54,8 @@ def test_to_python():
mat2 = np.array(mat, copy=False) mat2 = np.array(mat, copy=False)
assert mat2.shape == (5, 4) assert mat2.shape == (5, 4)
assert abs(mat2).sum() == 11 assert abs(mat2).sum() == 11
assert mat2[2, 3] == 4 and mat2[3, 2] == 7 assert mat2[2, 3] == 4
assert mat2[3, 2] == 7
mat2[2, 3] = 5 mat2[2, 3] = 5
assert mat2[2, 3] == 5 assert mat2[2, 3] == 5

View File

@ -126,8 +126,8 @@ def test_bytes_to_string():
assert m.strlen(b"hi") == 2 assert m.strlen(b"hi") == 2
assert m.string_length(b"world") == 5 assert m.string_length(b"world") == 5
assert m.string_length("a\x00b".encode()) == 3 assert m.string_length(b"a\x00b") == 3
assert m.strlen("a\x00b".encode()) == 1 # C-string limitation assert m.strlen(b"a\x00b") == 1 # C-string limitation
# passing in a utf8 encoded string should work # passing in a utf8 encoded string should work
assert m.string_length("💩".encode()) == 4 assert m.string_length("💩".encode()) == 4
@ -421,13 +421,15 @@ def test_reference_wrapper():
a2 = m.refwrap_list(copy=True) a2 = m.refwrap_list(copy=True)
assert [x.value for x in a1] == [2, 3] assert [x.value for x in a1] == [2, 3]
assert [x.value for x in a2] == [2, 3] assert [x.value for x in a2] == [2, 3]
assert not a1[0] is a2[0] and not a1[1] is a2[1] assert a1[0] is not a2[0]
assert a1[1] is not a2[1]
b1 = m.refwrap_list(copy=False) b1 = m.refwrap_list(copy=False)
b2 = m.refwrap_list(copy=False) b2 = m.refwrap_list(copy=False)
assert [x.value for x in b1] == [1, 2] assert [x.value for x in b1] == [1, 2]
assert [x.value for x in b2] == [1, 2] assert [x.value for x in b2] == [1, 2]
assert b1[0] is b2[0] and b1[1] is b2[1] assert b1[0] is b2[0]
assert b1[1] is b2[1]
assert m.refwrap_iiw(IncType(5)) == 5 assert m.refwrap_iiw(IncType(5)) == 5
assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10] assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10]

View File

@ -6,10 +6,7 @@ from pybind11_tests import class_ as m
def test_obj_class_name(): def test_obj_class_name():
if env.PYPY: expected_name = "UserType" if env.PYPY else "pybind11_tests.UserType"
expected_name = "UserType"
else:
expected_name = "pybind11_tests.UserType"
assert m.obj_class_name(UserType(1)) == expected_name assert m.obj_class_name(UserType(1)) == expected_name
assert m.obj_class_name(UserType) == expected_name assert m.obj_class_name(UserType) == expected_name
@ -32,7 +29,7 @@ def test_instance(msg):
assert cstats.alive() == 0 assert cstats.alive() == 0
def test_instance_new(msg): def test_instance_new():
instance = m.NoConstructorNew() # .__new__(m.NoConstructor.__class__) instance = m.NoConstructorNew() # .__new__(m.NoConstructor.__class__)
cstats = ConstructorStats.get(m.NoConstructorNew) cstats = ConstructorStats.get(m.NoConstructorNew)
assert cstats.alive() == 1 assert cstats.alive() == 1
@ -221,7 +218,7 @@ def test_automatic_upcasting():
def test_isinstance(): def test_isinstance():
objects = [tuple(), dict(), m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4 objects = [(), {}, m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4
expected = (True, True, True, True, True, False, False) expected = (True, True, True, True, True, False, False)
assert m.check_instances(objects) == expected assert m.check_instances(objects) == expected
@ -427,7 +424,7 @@ def test_exception_rvalue_abort():
# https://github.com/pybind/pybind11/issues/1568 # https://github.com/pybind/pybind11/issues/1568
def test_multiple_instances_with_same_pointer(capture): def test_multiple_instances_with_same_pointer():
n = 100 n = 100
instances = [m.SamePointer() for _ in range(n)] instances = [m.SamePointer() for _ in range(n)]
for i in range(n): for i in range(n):

View File

@ -3,9 +3,9 @@ import pytest
from pybind11_tests import const_name as m from pybind11_tests import const_name as m
@pytest.mark.parametrize("func", (m.const_name_tests, m.underscore_tests)) @pytest.mark.parametrize("func", [m.const_name_tests, m.underscore_tests])
@pytest.mark.parametrize( @pytest.mark.parametrize(
"selector, expected", ("selector", "expected"),
enumerate( enumerate(
( (
"", "",

View File

@ -100,7 +100,8 @@ def test_custom_caster_destruction():
cstats = m.destruction_tester_cstats() cstats = m.destruction_tester_cstats()
# This one *doesn't* have take_ownership: the pointer should be used but not destroyed: # This one *doesn't* have take_ownership: the pointer should be used but not destroyed:
z = m.custom_caster_no_destroy() z = m.custom_caster_no_destroy()
assert cstats.alive() == 1 and cstats.default_constructions == 1 assert cstats.alive() == 1
assert cstats.default_constructions == 1
assert z assert z
# take_ownership applied: this constructs a new object, casts it, then destroys it: # take_ownership applied: this constructs a new object, casts it, then destroys it:

View File

@ -7,7 +7,7 @@ import env # noqa: F401
from pybind11_tests import custom_type_setup as m from pybind11_tests import custom_type_setup as m
@pytest.fixture @pytest.fixture()
def gc_tester(): def gc_tester():
"""Tests that an object is garbage collected. """Tests that an object is garbage collected.

View File

@ -263,79 +263,96 @@ def test_eigen_return_references():
primary = np.ones((10, 10)) primary = np.ones((10, 10))
a = m.ReturnTester() a = m.ReturnTester()
a_get1 = a.get() a_get1 = a.get()
assert not a_get1.flags.owndata and a_get1.flags.writeable assert not a_get1.flags.owndata
assert a_get1.flags.writeable
assign_both(a_get1, primary, 3, 3, 5) assign_both(a_get1, primary, 3, 3, 5)
a_get2 = a.get_ptr() a_get2 = a.get_ptr()
assert not a_get2.flags.owndata and a_get2.flags.writeable assert not a_get2.flags.owndata
assert a_get2.flags.writeable
assign_both(a_get1, primary, 2, 3, 6) assign_both(a_get1, primary, 2, 3, 6)
a_view1 = a.view() a_view1 = a.view()
assert not a_view1.flags.owndata and not a_view1.flags.writeable assert not a_view1.flags.owndata
assert not a_view1.flags.writeable
with pytest.raises(ValueError): with pytest.raises(ValueError):
a_view1[2, 3] = 4 a_view1[2, 3] = 4
a_view2 = a.view_ptr() a_view2 = a.view_ptr()
assert not a_view2.flags.owndata and not a_view2.flags.writeable assert not a_view2.flags.owndata
assert not a_view2.flags.writeable
with pytest.raises(ValueError): with pytest.raises(ValueError):
a_view2[2, 3] = 4 a_view2[2, 3] = 4
a_copy1 = a.copy_get() a_copy1 = a.copy_get()
assert a_copy1.flags.owndata and a_copy1.flags.writeable assert a_copy1.flags.owndata
assert a_copy1.flags.writeable
np.testing.assert_array_equal(a_copy1, primary) np.testing.assert_array_equal(a_copy1, primary)
a_copy1[7, 7] = -44 # Shouldn't affect anything else a_copy1[7, 7] = -44 # Shouldn't affect anything else
c1want = array_copy_but_one(primary, 7, 7, -44) c1want = array_copy_but_one(primary, 7, 7, -44)
a_copy2 = a.copy_view() a_copy2 = a.copy_view()
assert a_copy2.flags.owndata and a_copy2.flags.writeable assert a_copy2.flags.owndata
assert a_copy2.flags.writeable
np.testing.assert_array_equal(a_copy2, primary) np.testing.assert_array_equal(a_copy2, primary)
a_copy2[4, 4] = -22 # Shouldn't affect anything else a_copy2[4, 4] = -22 # Shouldn't affect anything else
c2want = array_copy_but_one(primary, 4, 4, -22) c2want = array_copy_but_one(primary, 4, 4, -22)
a_ref1 = a.ref() a_ref1 = a.ref()
assert not a_ref1.flags.owndata and a_ref1.flags.writeable assert not a_ref1.flags.owndata
assert a_ref1.flags.writeable
assign_both(a_ref1, primary, 1, 1, 15) assign_both(a_ref1, primary, 1, 1, 15)
a_ref2 = a.ref_const() a_ref2 = a.ref_const()
assert not a_ref2.flags.owndata and not a_ref2.flags.writeable assert not a_ref2.flags.owndata
assert not a_ref2.flags.writeable
with pytest.raises(ValueError): with pytest.raises(ValueError):
a_ref2[5, 5] = 33 a_ref2[5, 5] = 33
a_ref3 = a.ref_safe() a_ref3 = a.ref_safe()
assert not a_ref3.flags.owndata and a_ref3.flags.writeable assert not a_ref3.flags.owndata
assert a_ref3.flags.writeable
assign_both(a_ref3, primary, 0, 7, 99) assign_both(a_ref3, primary, 0, 7, 99)
a_ref4 = a.ref_const_safe() a_ref4 = a.ref_const_safe()
assert not a_ref4.flags.owndata and not a_ref4.flags.writeable assert not a_ref4.flags.owndata
assert not a_ref4.flags.writeable
with pytest.raises(ValueError): with pytest.raises(ValueError):
a_ref4[7, 0] = 987654321 a_ref4[7, 0] = 987654321
a_copy3 = a.copy_ref() a_copy3 = a.copy_ref()
assert a_copy3.flags.owndata and a_copy3.flags.writeable assert a_copy3.flags.owndata
assert a_copy3.flags.writeable
np.testing.assert_array_equal(a_copy3, primary) np.testing.assert_array_equal(a_copy3, primary)
a_copy3[8, 1] = 11 a_copy3[8, 1] = 11
c3want = array_copy_but_one(primary, 8, 1, 11) c3want = array_copy_but_one(primary, 8, 1, 11)
a_copy4 = a.copy_ref_const() a_copy4 = a.copy_ref_const()
assert a_copy4.flags.owndata and a_copy4.flags.writeable assert a_copy4.flags.owndata
assert a_copy4.flags.writeable
np.testing.assert_array_equal(a_copy4, primary) np.testing.assert_array_equal(a_copy4, primary)
a_copy4[8, 4] = 88 a_copy4[8, 4] = 88
c4want = array_copy_but_one(primary, 8, 4, 88) c4want = array_copy_but_one(primary, 8, 4, 88)
a_block1 = a.block(3, 3, 2, 2) a_block1 = a.block(3, 3, 2, 2)
assert not a_block1.flags.owndata and a_block1.flags.writeable assert not a_block1.flags.owndata
assert a_block1.flags.writeable
a_block1[0, 0] = 55 a_block1[0, 0] = 55
primary[3, 3] = 55 primary[3, 3] = 55
a_block2 = a.block_safe(2, 2, 3, 2) a_block2 = a.block_safe(2, 2, 3, 2)
assert not a_block2.flags.owndata and a_block2.flags.writeable assert not a_block2.flags.owndata
assert a_block2.flags.writeable
a_block2[2, 1] = -123 a_block2[2, 1] = -123
primary[4, 3] = -123 primary[4, 3] = -123
a_block3 = a.block_const(6, 7, 4, 3) a_block3 = a.block_const(6, 7, 4, 3)
assert not a_block3.flags.owndata and not a_block3.flags.writeable assert not a_block3.flags.owndata
assert not a_block3.flags.writeable
with pytest.raises(ValueError): with pytest.raises(ValueError):
a_block3[2, 2] = -44444 a_block3[2, 2] = -44444
a_copy5 = a.copy_block(2, 2, 2, 3) a_copy5 = a.copy_block(2, 2, 2, 3)
assert a_copy5.flags.owndata and a_copy5.flags.writeable assert a_copy5.flags.owndata
assert a_copy5.flags.writeable
np.testing.assert_array_equal(a_copy5, primary[2:4, 2:5]) np.testing.assert_array_equal(a_copy5, primary[2:4, 2:5])
a_copy5[1, 1] = 777 a_copy5[1, 1] = 777
c5want = array_copy_but_one(primary[2:4, 2:5], 1, 1, 777) c5want = array_copy_but_one(primary[2:4, 2:5], 1, 1, 777)
a_corn1 = a.corners() a_corn1 = a.corners()
assert not a_corn1.flags.owndata and a_corn1.flags.writeable assert not a_corn1.flags.owndata
assert a_corn1.flags.writeable
a_corn1 *= 50 a_corn1 *= 50
a_corn1[1, 1] = 999 a_corn1[1, 1] = 999
primary[0, 0] = 50 primary[0, 0] = 50
@ -343,7 +360,8 @@ def test_eigen_return_references():
primary[9, 0] = 50 primary[9, 0] = 50
primary[9, 9] = 999 primary[9, 9] = 999
a_corn2 = a.corners_const() a_corn2 = a.corners_const()
assert not a_corn2.flags.owndata and not a_corn2.flags.writeable assert not a_corn2.flags.owndata
assert not a_corn2.flags.writeable
with pytest.raises(ValueError): with pytest.raises(ValueError):
a_corn2[1, 0] = 51 a_corn2[1, 0] = 51
@ -503,10 +521,14 @@ def test_numpy_ref_mutators():
assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4 assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4
assert not zc.flags.owndata and zc.flags.writeable assert not zc.flags.owndata
assert not zr.flags.owndata and zr.flags.writeable assert zc.flags.writeable
assert not zcro.flags.owndata and not zcro.flags.writeable assert not zr.flags.owndata
assert not zrro.flags.owndata and not zrro.flags.writeable assert zr.flags.writeable
assert not zcro.flags.owndata
assert not zcro.flags.writeable
assert not zrro.flags.owndata
assert not zrro.flags.writeable
zc[1, 2] = 99 zc[1, 2] = 99
expect = np.array([[11.0, 12, 13], [21, 22, 99], [31, 32, 33]]) expect = np.array([[11.0, 12, 13], [21, 22, 99], [31, 32, 33]])
@ -530,7 +552,8 @@ def test_numpy_ref_mutators():
# the const should drop away) # the const should drop away)
y1 = np.array(m.get_cm_const_ref()) y1 = np.array(m.get_cm_const_ref())
assert y1.flags.owndata and y1.flags.writeable assert y1.flags.owndata
assert y1.flags.writeable
# We should get copies of the eigen data, which was modified above: # We should get copies of the eigen data, which was modified above:
assert y1[1, 2] == 99 assert y1[1, 2] == 99
y1[1, 2] += 12 y1[1, 2] += 12
@ -603,38 +626,38 @@ def test_nocopy_wrapper():
# All but the second should fail with m.get_elem_nocopy: # All but the second should fail with m.get_elem_nocopy:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_nocopy(int_matrix_colmajor) m.get_elem_nocopy(int_matrix_colmajor)
assert "get_elem_nocopy(): incompatible function arguments." in str( assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
excinfo.value assert ", flags.f_contiguous" in str(excinfo.value)
) and ", flags.f_contiguous" in str(excinfo.value)
assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8 assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_nocopy(int_matrix_rowmajor) m.get_elem_nocopy(int_matrix_rowmajor)
assert "get_elem_nocopy(): incompatible function arguments." in str( assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
excinfo.value assert ", flags.f_contiguous" in str(excinfo.value)
) and ", flags.f_contiguous" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_nocopy(dbl_matrix_rowmajor) m.get_elem_nocopy(dbl_matrix_rowmajor)
assert "get_elem_nocopy(): incompatible function arguments." in str( assert "get_elem_nocopy(): incompatible function arguments." in str(excinfo.value)
excinfo.value assert ", flags.f_contiguous" in str(excinfo.value)
) and ", flags.f_contiguous" in str(excinfo.value)
# For the row-major test, we take a long matrix in row-major, so only the third is allowed: # For the row-major test, we take a long matrix in row-major, so only the third is allowed:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_rm_nocopy(int_matrix_colmajor) m.get_elem_rm_nocopy(int_matrix_colmajor)
assert "get_elem_rm_nocopy(): incompatible function arguments." in str( assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
excinfo.value excinfo.value
) and ", flags.c_contiguous" in str(excinfo.value) )
assert ", flags.c_contiguous" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_rm_nocopy(dbl_matrix_colmajor) m.get_elem_rm_nocopy(dbl_matrix_colmajor)
assert "get_elem_rm_nocopy(): incompatible function arguments." in str( assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
excinfo.value excinfo.value
) and ", flags.c_contiguous" in str(excinfo.value) )
assert ", flags.c_contiguous" in str(excinfo.value)
assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8 assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.get_elem_rm_nocopy(dbl_matrix_rowmajor) m.get_elem_rm_nocopy(dbl_matrix_rowmajor)
assert "get_elem_rm_nocopy(): incompatible function arguments." in str( assert "get_elem_rm_nocopy(): incompatible function arguments." in str(
excinfo.value excinfo.value
) and ", flags.c_contiguous" in str(excinfo.value) )
assert ", flags.c_contiguous" in str(excinfo.value)
def test_eigen_ref_life_support(): def test_eigen_ref_life_support():

View File

@ -11,14 +11,15 @@ try:
submodules += [avoid.c_style, avoid.f_style] submodules += [avoid.c_style, avoid.f_style]
except ImportError as e: except ImportError as e:
# Ensure config, build, toolchain, etc. issues are not masked here: # Ensure config, build, toolchain, etc. issues are not masked here:
raise RuntimeError( msg = (
"import eigen_tensor_avoid_stl_array FAILED, while " "import eigen_tensor_avoid_stl_array FAILED, while "
"import pybind11_tests.eigen_tensor succeeded. " "import pybind11_tests.eigen_tensor succeeded. "
"Please ensure that " "Please ensure that "
"test_eigen_tensor.cpp & " "test_eigen_tensor.cpp & "
"eigen_tensor_avoid_stl_array.cpp " "eigen_tensor_avoid_stl_array.cpp "
"are built together (or both are not built if Eigen is not available)." "are built together (or both are not built if Eigen is not available)."
) from e )
raise RuntimeError(msg) from e
tensor_ref = np.empty((3, 5, 2), dtype=np.int64) tensor_ref = np.empty((3, 5, 2), dtype=np.int64)
@ -147,10 +148,7 @@ def test_bad_python_to_cpp_casts(m):
m.round_trip_tensor_noconvert(tensor_ref.astype(np.float64)) m.round_trip_tensor_noconvert(tensor_ref.astype(np.float64))
) )
if m.needed_options == "F": bad_options = "C" if m.needed_options == "F" else "F"
bad_options = "C"
else:
bad_options = "F"
# Shape, dtype and the order need to be correct for a TensorMap cast # Shape, dtype and the order need to be correct for a TensorMap cast
with pytest.raises( with pytest.raises(
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments" TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
@ -173,19 +171,19 @@ def test_bad_python_to_cpp_casts(m):
np.zeros((3, 5), dtype=np.float64, order=m.needed_options) np.zeros((3, 5), dtype=np.float64, order=m.needed_options)
) )
temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options)
with pytest.raises( with pytest.raises(
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments" TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
): ):
temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options)
m.round_trip_view_tensor( m.round_trip_view_tensor(
temp[:, ::-1, :], temp[:, ::-1, :],
) )
temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options)
temp.setflags(write=False)
with pytest.raises( with pytest.raises(
TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments" TypeError, match=r"^round_trip_view_tensor\(\): incompatible function arguments"
): ):
temp = np.zeros((3, 5, 2), dtype=np.float64, order=m.needed_options)
temp.setflags(write=False)
m.round_trip_view_tensor(temp) m.round_trip_view_tensor(temp)
@ -282,9 +280,9 @@ def test_doc_string(m, doc):
order_flag = f"flags.{m.needed_options.lower()}_contiguous" order_flag = f"flags.{m.needed_options.lower()}_contiguous"
assert doc(m.round_trip_view_tensor) == ( assert doc(m.round_trip_view_tensor) == (
f"round_trip_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}])" f"round_trip_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}])"
+ f" -> numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}]" f" -> numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}]"
) )
assert doc(m.round_trip_const_view_tensor) == ( assert doc(m.round_trip_const_view_tensor) == (
f"round_trip_const_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], {order_flag}])" f"round_trip_const_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], {order_flag}])"
+ " -> numpy.ndarray[numpy.float64[?, ?, ?]]" " -> numpy.ndarray[numpy.float64[?, ?, ?]]"
) )

View File

@ -1,3 +1,5 @@
# ruff: noqa: SIM201 SIM300 SIM202
import pytest import pytest
from pybind11_tests import enums as m from pybind11_tests import enums as m

View File

@ -94,8 +94,7 @@ def ignore_pytest_unraisable_warning(f):
if hasattr(pytest, unraisable): # Python >= 3.8 and pytest >= 6 if hasattr(pytest, unraisable): # Python >= 3.8 and pytest >= 6
dec = pytest.mark.filterwarnings(f"ignore::pytest.{unraisable}") dec = pytest.mark.filterwarnings(f"ignore::pytest.{unraisable}")
return dec(f) return dec(f)
else: return f
return f
# TODO: find out why this fails on PyPy, https://foss.heptapod.net/pypy/pypy/-/issues/3583 # TODO: find out why this fails on PyPy, https://foss.heptapod.net/pypy/pypy/-/issues/3583
@ -183,7 +182,7 @@ def test_custom(msg):
m.throws5_1() m.throws5_1()
assert msg(excinfo.value) == "MyException5 subclass" assert msg(excinfo.value) == "MyException5 subclass"
with pytest.raises(m.MyException5) as excinfo: with pytest.raises(m.MyException5) as excinfo: # noqa: PT012
try: try:
m.throws5() m.throws5()
except m.MyException5_1 as err: except m.MyException5_1 as err:
@ -212,7 +211,7 @@ def test_nested_throws(capture):
m.try_catch(m.MyException5, throw_myex) m.try_catch(m.MyException5, throw_myex)
assert str(excinfo.value) == "nested error" assert str(excinfo.value) == "nested error"
def pycatch(exctype, f, *args): def pycatch(exctype, f, *args): # noqa: ARG001
try: try:
f(*args) f(*args)
except m.MyException as e: except m.MyException as e:
@ -303,12 +302,12 @@ class FlakyException(Exception):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"exc_type, exc_value, expected_what", ("exc_type", "exc_value", "expected_what"),
( [
(ValueError, "plain_str", "ValueError: plain_str"), (ValueError, "plain_str", "ValueError: plain_str"),
(ValueError, ("tuple_elem",), "ValueError: tuple_elem"), (ValueError, ("tuple_elem",), "ValueError: tuple_elem"),
(FlakyException, ("happy",), "FlakyException: FlakyException.__str__"), (FlakyException, ("happy",), "FlakyException: FlakyException.__str__"),
), ],
) )
def test_error_already_set_what_with_happy_exceptions( def test_error_already_set_what_with_happy_exceptions(
exc_type, exc_value, expected_what exc_type, exc_value, expected_what
@ -342,10 +341,7 @@ def test_flaky_exception_failure_point_str():
) )
assert not py_err_set_after_what assert not py_err_set_after_what
lines = what.splitlines() lines = what.splitlines()
if env.PYPY and len(lines) == 3: n = 3 if env.PYPY and len(lines) == 3 else 5
n = 3 # Traceback is missing.
else:
n = 5
assert ( assert (
lines[:n] lines[:n]
== [ == [

View File

@ -96,7 +96,7 @@ def test_init_factory_signature(msg):
3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None 3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None
4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None 4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None
""" # noqa: E501 line too long """
) )

View File

@ -148,10 +148,7 @@ ALL_BASIC_TESTS_PLUS_INTENTIONAL_DEADLOCK = ALL_BASIC_TESTS + (_intentional_dead
def _run_in_process(target, *args, **kwargs): def _run_in_process(target, *args, **kwargs):
if len(args) == 0: test_fn = target if len(args) == 0 else args[0]
test_fn = target
else:
test_fn = args[0]
# Do not need to wait much, 10s should be more than enough. # Do not need to wait much, 10s should be more than enough.
timeout = 0.1 if test_fn is _intentional_deadlock else 10 timeout = 0.1 if test_fn is _intentional_deadlock else 10
process = multiprocessing.Process(target=target, args=args, kwargs=kwargs) process = multiprocessing.Process(target=target, args=args, kwargs=kwargs)
@ -178,7 +175,8 @@ def _run_in_process(target, *args, **kwargs):
elif test_fn is _intentional_deadlock: elif test_fn is _intentional_deadlock:
assert process.exitcode is None assert process.exitcode is None
return 0 return 0
elif process.exitcode is None:
if process.exitcode is None:
assert t_delta > 0.9 * timeout assert t_delta > 0.9 * timeout
msg = "DEADLOCK, most likely, exactly what this test is meant to detect." msg = "DEADLOCK, most likely, exactly what this test is meant to detect."
if env.PYPY and env.WIN: if env.PYPY and env.WIN:

View File

@ -224,9 +224,8 @@ def test_redirect(capfd):
assert stream.getvalue() == "" assert stream.getvalue() == ""
stream = StringIO() stream = StringIO()
with redirect_stdout(stream): with redirect_stdout(stream), m.ostream_redirect():
with m.ostream_redirect(): m.raw_output(msg)
m.raw_output(msg)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == "" assert stdout == ""
assert stream.getvalue() == msg assert stream.getvalue() == msg
@ -244,10 +243,9 @@ def test_redirect_err(capfd):
msg2 = "StdErr" msg2 = "StdErr"
stream = StringIO() stream = StringIO()
with redirect_stderr(stream): with redirect_stderr(stream), m.ostream_redirect(stdout=False):
with m.ostream_redirect(stdout=False): m.raw_output(msg)
m.raw_output(msg) m.raw_err(msg2)
m.raw_err(msg2)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == msg assert stdout == msg
assert stderr == "" assert stderr == ""
@ -260,11 +258,9 @@ def test_redirect_both(capfd):
stream = StringIO() stream = StringIO()
stream2 = StringIO() stream2 = StringIO()
with redirect_stdout(stream): with redirect_stdout(stream), redirect_stderr(stream2), m.ostream_redirect():
with redirect_stderr(stream2): m.raw_output(msg)
with m.ostream_redirect(): m.raw_err(msg2)
m.raw_output(msg)
m.raw_err(msg2)
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert stdout == "" assert stdout == ""
assert stderr == "" assert stderr == ""

View File

@ -25,7 +25,7 @@ def test_function_signatures(doc):
) )
def test_named_arguments(msg): def test_named_arguments():
assert m.kw_func0(5, 10) == "x=5, y=10" assert m.kw_func0(5, 10) == "x=5, y=10"
assert m.kw_func1(5, 10) == "x=5, y=10" assert m.kw_func1(5, 10) == "x=5, y=10"
@ -43,8 +43,7 @@ def test_named_arguments(msg):
# noinspection PyArgumentList # noinspection PyArgumentList
m.kw_func2(x=5, y=10, z=12) m.kw_func2(x=5, y=10, z=12)
assert excinfo.match( assert excinfo.match(
r"(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))" r"(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$)){3}$"
+ "{3}$"
) )
assert m.kw_func4() == "{13 17}" assert m.kw_func4() == "{13 17}"
@ -59,7 +58,7 @@ def test_arg_and_kwargs():
assert m.args_function(*args) == args assert m.args_function(*args) == args
args = "a1", "a2" args = "a1", "a2"
kwargs = dict(arg3="a3", arg4=4) kwargs = {"arg3": "a3", "arg4": 4}
assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs) assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs)
@ -177,7 +176,7 @@ def test_mixed_args_and_kwargs(msg):
assert ( assert (
m.args_kwonly_kwargs_defaults.__doc__ m.args_kwonly_kwargs_defaults.__doc__
== "args_kwonly_kwargs_defaults(i: int = 1, j: float = 3.14159, *args, z: int = 42, **kwargs) -> tuple\n" # noqa: E501 line too long == "args_kwonly_kwargs_defaults(i: int = 1, j: float = 3.14159, *args, z: int = 42, **kwargs) -> tuple\n"
) )
assert m.args_kwonly_kwargs_defaults() == (1, 3.14159, (), 42, {}) assert m.args_kwonly_kwargs_defaults() == (1, 3.14159, (), 42, {})
assert m.args_kwonly_kwargs_defaults(2) == (2, 3.14159, (), 42, {}) assert m.args_kwonly_kwargs_defaults(2) == (2, 3.14159, (), 42, {})
@ -233,15 +232,15 @@ def test_keyword_only_args(msg):
x.method(i=1, j=2) x.method(i=1, j=2)
assert ( assert (
m.first_arg_kw_only.__init__.__doc__ m.first_arg_kw_only.__init__.__doc__
== "__init__(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: int = 0) -> None\n" # noqa: E501 line too long == "__init__(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: int = 0) -> None\n"
) )
assert ( assert (
m.first_arg_kw_only.method.__doc__ m.first_arg_kw_only.method.__doc__
== "method(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: int = 1, j: int = 2) -> None\n" # noqa: E501 line too long == "method(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: int = 1, j: int = 2) -> None\n"
) )
def test_positional_only_args(msg): def test_positional_only_args():
assert m.pos_only_all(1, 2) == (1, 2) assert m.pos_only_all(1, 2) == (1, 2)
assert m.pos_only_all(2, 1) == (2, 1) assert m.pos_only_all(2, 1) == (2, 1)
@ -283,7 +282,7 @@ def test_positional_only_args(msg):
# Mix it with args and kwargs: # Mix it with args and kwargs:
assert ( assert (
m.args_kwonly_full_monty.__doc__ m.args_kwonly_full_monty.__doc__
== "args_kwonly_full_monty(arg0: int = 1, arg1: int = 2, /, j: float = 3.14159, *args, z: int = 42, **kwargs) -> tuple\n" # noqa: E501 line too long == "args_kwonly_full_monty(arg0: int = 1, arg1: int = 2, /, j: float = 3.14159, *args, z: int = 42, **kwargs) -> tuple\n"
) )
assert m.args_kwonly_full_monty() == (1, 2, 3.14159, (), 42, {}) assert m.args_kwonly_full_monty() == (1, 2, 3.14159, (), 42, {})
assert m.args_kwonly_full_monty(8) == (8, 2, 3.14159, (), 42, {}) assert m.args_kwonly_full_monty(8) == (8, 2, 3.14159, (), 42, {})
@ -326,18 +325,18 @@ def test_positional_only_args(msg):
# https://github.com/pybind/pybind11/pull/3402#issuecomment-963341987 # https://github.com/pybind/pybind11/pull/3402#issuecomment-963341987
assert ( assert (
m.first_arg_kw_only.pos_only.__doc__ m.first_arg_kw_only.pos_only.__doc__
== "pos_only(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, /, i: int, j: int) -> None\n" # noqa: E501 line too long == "pos_only(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, /, i: int, j: int) -> None\n"
) )
def test_signatures(): def test_signatures():
assert "kw_only_all(*, i: int, j: int) -> tuple\n" == m.kw_only_all.__doc__ assert m.kw_only_all.__doc__ == "kw_only_all(*, i: int, j: int) -> tuple\n"
assert "kw_only_mixed(i: int, *, j: int) -> tuple\n" == m.kw_only_mixed.__doc__ assert m.kw_only_mixed.__doc__ == "kw_only_mixed(i: int, *, j: int) -> tuple\n"
assert "pos_only_all(i: int, j: int, /) -> tuple\n" == m.pos_only_all.__doc__ assert m.pos_only_all.__doc__ == "pos_only_all(i: int, j: int, /) -> tuple\n"
assert "pos_only_mix(i: int, /, j: int) -> tuple\n" == m.pos_only_mix.__doc__ assert m.pos_only_mix.__doc__ == "pos_only_mix(i: int, /, j: int) -> tuple\n"
assert ( assert (
"pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple\n" m.pos_kw_only_mix.__doc__
== m.pos_kw_only_mix.__doc__ == "pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple\n"
) )

View File

@ -183,9 +183,9 @@ def test_static_properties():
# Only static attributes can be deleted # Only static attributes can be deleted
del m.TestPropertiesOverride.def_readonly_static del m.TestPropertiesOverride.def_readonly_static
assert hasattr(m.TestPropertiesOverride, "def_readonly_static")
assert ( assert (
hasattr(m.TestPropertiesOverride, "def_readonly_static") m.TestPropertiesOverride.def_readonly_static
and m.TestPropertiesOverride.def_readonly_static
is m.TestProperties.def_readonly_static is m.TestProperties.def_readonly_static
) )
assert "def_readonly_static" not in m.TestPropertiesOverride.__dict__ assert "def_readonly_static" not in m.TestPropertiesOverride.__dict__
@ -256,10 +256,7 @@ def test_no_mixed_overloads():
@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"]) @pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
def test_property_return_value_policies(access): def test_property_return_value_policies(access):
if not access.startswith("static"): obj = m.TestPropRVP() if not access.startswith("static") else m.TestPropRVP
obj = m.TestPropRVP()
else:
obj = m.TestPropRVP
ref = getattr(obj, access + "_ref") ref = getattr(obj, access + "_ref")
assert ref.value == 1 assert ref.value == 1

View File

@ -1,3 +1,5 @@
import builtins
import pytest import pytest
import env import env
@ -86,12 +88,7 @@ def test_builtin_key_type():
Previous versions of pybind11 would add a unicode key in python 2. Previous versions of pybind11 would add a unicode key in python 2.
""" """
if hasattr(__builtins__, "keys"): assert all(type(k) == str for k in dir(builtins))
keys = __builtins__.keys()
else: # this is to make pypy happy since builtins is different there.
keys = __builtins__.__dict__.keys()
assert {type(k) for k in keys} == {str}
@pytest.mark.xfail("env.PYPY", reason="PyModule_GetName()") @pytest.mark.xfail("env.PYPY", reason="PyModule_GetName()")

View File

@ -22,7 +22,7 @@ def test_dtypes():
) )
@pytest.fixture(scope="function") @pytest.fixture()
def arr(): def arr():
return np.array([[1, 2, 3], [4, 5, 6]], "=u2") return np.array([[1, 2, 3], [4, 5, 6]], "=u2")
@ -67,7 +67,7 @@ def test_array_attributes():
@pytest.mark.parametrize( @pytest.mark.parametrize(
"args, ret", [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)] ("args", "ret"), [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)]
) )
def test_index_offset(arr, args, ret): def test_index_offset(arr, args, ret):
assert m.index_at(arr, *args) == ret assert m.index_at(arr, *args) == ret
@ -93,7 +93,7 @@ def test_dim_check_fail(arr):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"args, ret", ("args", "ret"),
[ [
([], [1, 2, 3, 4, 5, 6]), ([], [1, 2, 3, 4, 5, 6]),
([1], [4, 5, 6]), ([1], [4, 5, 6]),
@ -211,12 +211,14 @@ def test_wrap():
assert b[0, 0] == 1234 assert b[0, 0] == 1234
a1 = np.array([1, 2], dtype=np.int16) a1 = np.array([1, 2], dtype=np.int16)
assert a1.flags.owndata and a1.base is None assert a1.flags.owndata
assert a1.base is None
a2 = m.wrap(a1) a2 = m.wrap(a1)
assert_references(a1, a2) assert_references(a1, a2)
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="F") a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="F")
assert a1.flags.owndata and a1.base is None assert a1.flags.owndata
assert a1.base is None
a2 = m.wrap(a1) a2 = m.wrap(a1)
assert_references(a1, a2) assert_references(a1, a2)
@ -451,13 +453,15 @@ def test_array_resize():
try: try:
m.array_resize3(a, 3, True) m.array_resize3(a, 3, True)
except ValueError as e: except ValueError as e:
assert str(e).startswith("cannot resize an array") assert str(e).startswith("cannot resize an array") # noqa: PT017
# transposed array doesn't own data # transposed array doesn't own data
b = a.transpose() b = a.transpose()
try: try:
m.array_resize3(b, 3, False) m.array_resize3(b, 3, False)
except ValueError as e: except ValueError as e:
assert str(e).startswith("cannot resize this array: it does not own its data") assert str(e).startswith( # noqa: PT017
"cannot resize this array: it does not own its data"
)
# ... but reshape should be fine # ... but reshape should be fine
m.array_reshape2(b) m.array_reshape2(b)
assert b.shape == (8, 8) assert b.shape == (8, 8)

View File

@ -130,14 +130,10 @@ def test_dtype(simple_dtype):
partial_nested_fmt(), partial_nested_fmt(),
"[('a','S3'),('b','S3')]", "[('a','S3'),('b','S3')]",
( (
"{{'names':['a','b','c','d']," "{'names':['a','b','c','d'],"
+ "'formats':[('S4',(3,)),('" f"'formats':[('S4',(3,)),('{e}i4',(2,)),('u1',(3,)),('{e}f4',(4,2))],"
+ e "'offsets':[0,12,20,24],'itemsize':56}"
+ "i4',(2,)),('u1',(3,)),('" ),
+ e
+ "f4',(4,2))],"
+ "'offsets':[0,12,20,24],'itemsize':56}}"
).format(e=e),
"[('e1','" + e + "i8'),('e2','u1')]", "[('e1','" + e + "i8'),('e2','u1')]",
"[('x','i1'),('y','" + e + "u8')]", "[('x','i1'),('y','" + e + "u8')]",
"[('cflt','" + e + "c8'),('cdbl','" + e + "c16')]", "[('cflt','" + e + "c8'),('cdbl','" + e + "c16')]",
@ -291,19 +287,17 @@ def test_array_array():
arr = m.create_array_array(3) arr = m.create_array_array(3)
assert str(arr.dtype).replace(" ", "") == ( assert str(arr.dtype).replace(" ", "") == (
"{{'names':['a','b','c','d']," "{'names':['a','b','c','d'],"
+ "'formats':[('S4',(3,)),('" f"'formats':[('S4',(3,)),('{e}i4',(2,)),('u1',(3,)),('{e}f4',(4,2))],"
+ e "'offsets':[0,12,20,24],'itemsize':56}"
+ "i4',(2,)),('u1',(3,)),('{e}f4',(4,2))]," )
+ "'offsets':[0,12,20,24],'itemsize':56}}"
).format(e=e)
assert m.print_array_array(arr) == [ assert m.print_array_array(arr) == [
"a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," "a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1},"
+ "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}", "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}",
"a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," "a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001},"
+ "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}", "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}",
"a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001}," "a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001},"
+ "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}", "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}",
] ]
assert arr["a"].tolist() == [ assert arr["a"].tolist() == [
[b"ABCD", b"KLMN", b"UVWX"], [b"ABCD", b"KLMN", b"UVWX"],

View File

@ -149,7 +149,7 @@ def test_docs(doc):
doc(m.vectorized_func) doc(m.vectorized_func)
== """ == """
vectorized_func(arg0: numpy.ndarray[numpy.int32], arg1: numpy.ndarray[numpy.float32], arg2: numpy.ndarray[numpy.float64]) -> object vectorized_func(arg0: numpy.ndarray[numpy.int32], arg1: numpy.ndarray[numpy.float32], arg2: numpy.ndarray[numpy.float64]) -> object
""" # noqa: E501 line too long """
) )

View File

@ -15,7 +15,7 @@ def test_obj_class_name():
assert m.obj_class_name([]) == "list" assert m.obj_class_name([]) == "list"
def test_handle_from_move_only_type_with_operator_PyObject(): # noqa: N802 def test_handle_from_move_only_type_with_operator_PyObject():
assert m.handle_from_move_only_type_with_operator_PyObject_ncnst() assert m.handle_from_move_only_type_with_operator_PyObject_ncnst()
assert m.handle_from_move_only_type_with_operator_PyObject_const() assert m.handle_from_move_only_type_with_operator_PyObject_const()
@ -33,7 +33,7 @@ def test_iterator(doc):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"pytype, from_iter_func", ("pytype", "from_iter_func"),
[ [
(frozenset, m.get_frozenset_from_iterable), (frozenset, m.get_frozenset_from_iterable),
(list, m.get_list_from_iterable), (list, m.get_list_from_iterable),
@ -87,7 +87,7 @@ def test_list(capture, doc):
assert doc(m.print_list) == "print_list(arg0: list) -> None" assert doc(m.print_list) == "print_list(arg0: list) -> None"
def test_none(capture, doc): def test_none(doc):
assert doc(m.get_none) == "get_none() -> None" assert doc(m.get_none) == "get_none() -> None"
assert doc(m.print_none) == "print_none(arg0: None) -> None" assert doc(m.print_none) == "print_none(arg0: None) -> None"
@ -182,10 +182,10 @@ class CustomContains:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"arg,func", ("arg", "func"),
[ [
(set(), m.anyset_contains), (set(), m.anyset_contains),
(dict(), m.dict_contains), ({}, m.dict_contains),
(CustomContains(), m.obj_contains), (CustomContains(), m.obj_contains),
], ],
) )
@ -273,7 +273,7 @@ def test_bytes(doc):
assert doc(m.bytes_from_str) == "bytes_from_str() -> bytes" assert doc(m.bytes_from_str) == "bytes_from_str() -> bytes"
def test_bytearray(doc): def test_bytearray():
assert m.bytearray_from_char_ssize_t().decode() == "$%" assert m.bytearray_from_char_ssize_t().decode() == "$%"
assert m.bytearray_from_char_size_t().decode() == "@$!" assert m.bytearray_from_char_size_t().decode() == "@$!"
assert m.bytearray_from_string().decode() == "foo" assert m.bytearray_from_string().decode() == "foo"
@ -385,7 +385,7 @@ def test_accessors():
assert d["implicit_list"] == [1, 2, 3] assert d["implicit_list"] == [1, 2, 3]
assert all(x in TestObject.__dict__ for x in d["implicit_dict"]) assert all(x in TestObject.__dict__ for x in d["implicit_dict"])
assert m.tuple_accessor(tuple()) == (0, 1, 2) assert m.tuple_accessor(()) == (0, 1, 2)
d = m.accessor_assignment() d = m.accessor_assignment()
assert d["get"] == 0 assert d["get"] == 0
@ -593,7 +593,7 @@ def test_issue2361():
@pytest.mark.parametrize( @pytest.mark.parametrize(
"method, args, fmt, expected_view", ("method", "args", "fmt", "expected_view"),
[ [
(m.test_memoryview_object, (b"red",), "B", b"red"), (m.test_memoryview_object, (b"red",), "B", b"red"),
(m.test_memoryview_buffer_info, (b"green",), "B", b"green"), (m.test_memoryview_buffer_info, (b"green",), "B", b"green"),
@ -651,7 +651,7 @@ def test_memoryview_from_memory():
def test_builtin_functions(): def test_builtin_functions():
assert m.get_len([i for i in range(42)]) == 42 assert m.get_len(list(range(42))) == 42
with pytest.raises(TypeError) as exc_info: with pytest.raises(TypeError) as exc_info:
m.get_len(i for i in range(42)) m.get_len(i for i in range(42))
assert str(exc_info.value) in [ assert str(exc_info.value) in [
@ -695,7 +695,7 @@ def test_pass_bytes_or_unicode_to_string_types():
@pytest.mark.parametrize( @pytest.mark.parametrize(
"create_weakref, create_weakref_with_callback", ("create_weakref", "create_weakref_with_callback"),
[ [
(m.weakref_from_handle, m.weakref_from_handle_and_function), (m.weakref_from_handle, m.weakref_from_handle_and_function),
(m.weakref_from_object, m.weakref_from_object_and_function), (m.weakref_from_object, m.weakref_from_object_and_function),
@ -710,7 +710,7 @@ def test_weakref(create_weakref, create_weakref_with_callback):
callback_called = False callback_called = False
def callback(wr): def callback(_):
nonlocal callback_called nonlocal callback_called
callback_called = True callback_called = True
@ -730,7 +730,7 @@ def test_weakref(create_weakref, create_weakref_with_callback):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"create_weakref, has_callback", ("create_weakref", "has_callback"),
[ [
(m.weakref_from_handle, False), (m.weakref_from_handle, False),
(m.weakref_from_object, False), (m.weakref_from_object, False),
@ -748,10 +748,7 @@ def test_weakref_err(create_weakref, has_callback):
ob = C() ob = C()
# Should raise TypeError on CPython # Should raise TypeError on CPython
with pytest.raises(TypeError) if not env.PYPY else contextlib.nullcontext(): with pytest.raises(TypeError) if not env.PYPY else contextlib.nullcontext():
if has_callback: _ = create_weakref(ob, callback) if has_callback else create_weakref(ob)
_ = create_weakref(ob, callback)
else:
_ = create_weakref(ob)
def test_cpp_iterators(): def test_cpp_iterators():
@ -814,33 +811,36 @@ def test_populate_obj_str_attrs():
@pytest.mark.parametrize( @pytest.mark.parametrize(
"a,b", [("foo", "bar"), (1, 2), (1.0, 2.0), (list(range(3)), list(range(3, 6)))] ("a", "b"),
[("foo", "bar"), (1, 2), (1.0, 2.0), (list(range(3)), list(range(3, 6)))],
) )
def test_inplace_append(a, b): def test_inplace_append(a, b):
expected = a + b expected = a + b
assert m.inplace_append(a, b) == expected assert m.inplace_append(a, b) == expected
@pytest.mark.parametrize("a,b", [(3, 2), (3.0, 2.0), (set(range(3)), set(range(2)))]) @pytest.mark.parametrize(
("a", "b"), [(3, 2), (3.0, 2.0), (set(range(3)), set(range(2)))]
)
def test_inplace_subtract(a, b): def test_inplace_subtract(a, b):
expected = a - b expected = a - b
assert m.inplace_subtract(a, b) == expected assert m.inplace_subtract(a, b) == expected
@pytest.mark.parametrize("a,b", [(3, 2), (3.0, 2.0), ([1], 3)]) @pytest.mark.parametrize(("a", "b"), [(3, 2), (3.0, 2.0), ([1], 3)])
def test_inplace_multiply(a, b): def test_inplace_multiply(a, b):
expected = a * b expected = a * b
assert m.inplace_multiply(a, b) == expected assert m.inplace_multiply(a, b) == expected
@pytest.mark.parametrize("a,b", [(6, 3), (6.0, 3.0)]) @pytest.mark.parametrize(("a", "b"), [(6, 3), (6.0, 3.0)])
def test_inplace_divide(a, b): def test_inplace_divide(a, b):
expected = a / b expected = a / b
assert m.inplace_divide(a, b) == expected assert m.inplace_divide(a, b) == expected
@pytest.mark.parametrize( @pytest.mark.parametrize(
"a,b", ("a", "b"),
[ [
(False, True), (False, True),
( (
@ -857,7 +857,7 @@ def test_inplace_or(a, b):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"a,b", ("a", "b"),
[ [
(True, False), (True, False),
( (
@ -873,13 +873,13 @@ def test_inplace_and(a, b):
assert m.inplace_and(a, b) == expected assert m.inplace_and(a, b) == expected
@pytest.mark.parametrize("a,b", [(8, 1), (-3, 2)]) @pytest.mark.parametrize(("a", "b"), [(8, 1), (-3, 2)])
def test_inplace_lshift(a, b): def test_inplace_lshift(a, b):
expected = a << b expected = a << b
assert m.inplace_lshift(a, b) == expected assert m.inplace_lshift(a, b) == expected
@pytest.mark.parametrize("a,b", [(8, 1), (-2, 2)]) @pytest.mark.parametrize(("a", "b"), [(8, 1), (-2, 2)])
def test_inplace_rshift(a, b): def test_inplace_rshift(a, b):
expected = a >> b expected = a >> b
assert m.inplace_rshift(a, b) == expected assert m.inplace_rshift(a, b) == expected

View File

@ -1,5 +1,5 @@
import pytest import pytest
from pytest import approx from pytest import approx # noqa: PT013
from pybind11_tests import ConstructorStats from pybind11_tests import ConstructorStats
from pybind11_tests import sequences_and_iterators as m from pybind11_tests import sequences_and_iterators as m
@ -103,7 +103,8 @@ def test_sequence():
assert "Sequence" in repr(s) assert "Sequence" in repr(s)
assert len(s) == 5 assert len(s) == 5
assert s[0] == 0 and s[3] == 0 assert s[0] == 0
assert s[3] == 0
assert 12.34 not in s assert 12.34 not in s
s[0], s[3] = 12.34, 56.78 s[0], s[3] = 12.34, 56.78
assert 12.34 in s assert 12.34 in s
@ -245,7 +246,7 @@ def test_iterator_rvp():
def test_carray_iterator(): def test_carray_iterator():
"""#4100: Check for proper iterator overload with C-Arrays""" """#4100: Check for proper iterator overload with C-Arrays"""
args_gt = list(float(i) for i in range(3)) args_gt = [float(i) for i in range(3)]
arr_h = m.CArrayHolder(*args_gt) arr_h = m.CArrayHolder(*args_gt)
args = list(arr_h) args = list(arr_h)
assert args_gt == args assert args_gt == args

View File

@ -14,7 +14,7 @@ def test_vector(doc):
assert m.cast_bool_vector() == [True, False] assert m.cast_bool_vector() == [True, False]
assert m.load_bool_vector([True, False]) assert m.load_bool_vector([True, False])
assert m.load_bool_vector(tuple([True, False])) assert m.load_bool_vector((True, False))
assert doc(m.cast_vector) == "cast_vector() -> List[int]" assert doc(m.cast_vector) == "cast_vector() -> List[int]"
assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool" assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool"
@ -23,7 +23,7 @@ def test_vector(doc):
assert m.cast_ptr_vector() == ["lvalue", "lvalue"] assert m.cast_ptr_vector() == ["lvalue", "lvalue"]
def test_deque(doc): def test_deque():
"""std::deque <-> list""" """std::deque <-> list"""
lst = m.cast_deque() lst = m.cast_deque()
assert lst == [1] assert lst == [1]
@ -95,7 +95,8 @@ def test_recursive_casting():
# Issue #853 test case: # Issue #853 test case:
z = m.cast_unique_ptr_vector() z = m.cast_unique_ptr_vector()
assert z[0].value == 7 and z[1].value == 42 assert z[0].value == 7
assert z[1].value == 42
def test_move_out_container(): def test_move_out_container():

View File

@ -186,9 +186,9 @@ def test_map_string_double():
um["ua"] = 1.1 um["ua"] = 1.1
um["ub"] = 2.6 um["ub"] = 2.6
assert sorted(list(um)) == ["ua", "ub"] assert sorted(um) == ["ua", "ub"]
assert list(um.keys()) == list(um) assert list(um.keys()) == list(um)
assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)] assert sorted(um.items()) == [("ua", 1.1), ("ub", 2.6)]
assert list(zip(um.keys(), um.values())) == list(um.items()) assert list(zip(um.keys(), um.values())) == list(um.items())
assert "UnorderedMapStringDouble" in str(um) assert "UnorderedMapStringDouble" in str(um)
@ -304,11 +304,11 @@ def test_map_delitem():
um["ua"] = 1.1 um["ua"] = 1.1
um["ub"] = 2.6 um["ub"] = 2.6
assert sorted(list(um)) == ["ua", "ub"] assert sorted(um) == ["ua", "ub"]
assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)] assert sorted(um.items()) == [("ua", 1.1), ("ub", 2.6)]
del um["ua"] del um["ua"]
assert sorted(list(um)) == ["ub"] assert sorted(um) == ["ub"]
assert sorted(list(um.items())) == [("ub", 2.6)] assert sorted(um.items()) == [("ub", 2.6)]
def test_map_view_types(): def test_map_view_types():

View File

@ -192,8 +192,7 @@ def test_move_support():
class NCVirtExt(m.NCVirt): class NCVirtExt(m.NCVirt):
def get_noncopyable(self, a, b): def get_noncopyable(self, a, b):
# Constructs and returns a new instance: # Constructs and returns a new instance:
nc = m.NonCopyable(a * a, b * b) return m.NonCopyable(a * a, b * b)
return nc
def get_movable(self, a, b): def get_movable(self, a, b):
# Return a referenced copy # Return a referenced copy
@ -256,7 +255,7 @@ def test_dispatch_issue(msg):
assert m.dispatch_issue_go(b) == "Yay.." assert m.dispatch_issue_go(b) == "Yay.."
def test_recursive_dispatch_issue(msg): def test_recursive_dispatch_issue():
"""#3357: Recursive dispatch fails to find python function override""" """#3357: Recursive dispatch fails to find python function override"""
class Data(m.Data): class Data(m.Data):
@ -269,7 +268,7 @@ def test_recursive_dispatch_issue(msg):
# lambda is a workaround, which adds extra frame to the # lambda is a workaround, which adds extra frame to the
# current CPython thread. Removing lambda reveals the bug # current CPython thread. Removing lambda reveals the bug
# [https://github.com/pybind/pybind11/issues/3357] # [https://github.com/pybind/pybind11/issues/3357]
(lambda: visitor(Data(first.value + second.value)))() (lambda: visitor(Data(first.value + second.value)))() # noqa: PLC3002
class StoreResultVisitor: class StoreResultVisitor:
def __init__(self): def __init__(self):

View File

@ -17,14 +17,18 @@ def run(args: List[str]) -> None:
assert len(args) == 1, "codespell_errors.txt" assert len(args) == 1, "codespell_errors.txt"
cache = {} cache = {}
done = set() done = set()
for line in sorted(open(args[0]).read().splitlines()): with open(args[0]) as f:
lines = f.read().splitlines()
for line in sorted(lines):
i = line.find(" ==> ") i = line.find(" ==> ")
if i > 0: if i > 0:
flds = line[:i].split(":") flds = line[:i].split(":")
if len(flds) >= 2: if len(flds) >= 2:
filename, line_num = flds[:2] filename, line_num = flds[:2]
if filename not in cache: if filename not in cache:
cache[filename] = open(filename).read().splitlines() with open(filename) as f:
cache[filename] = f.read().splitlines()
supp = cache[filename][int(line_num) - 1] supp = cache[filename][int(line_num) - 1]
if supp not in done: if supp not in done:
print(supp) print(supp)