Unverified Commit 6493f496 authored by Ralf W. Grosse-Kunstleve's avatar Ralf W. Grosse-Kunstleve Committed by GitHub
Browse files

Python 2 removal part 1: tests (C++ code is intentionally ~untouched) (#3688)



* `#error BYE_BYE_GOLDEN_SNAKE`

* Removing everything related to 2.7 from ci.yml

* Commenting-out Centos7

* Removing `PYTHON: 27` from .appveyor.yml

* "PY2" removal, mainly from tests. C++ code is not touched.

* Systematic removal of `u` prefix from `u"..."` and `u'...'` literals. Collateral cleanup of a couple minor other things.

* Cleaning up around case-insensitive hits for `[^a-z]py.*2` in tests/.

* Removing obsolete Python 2 mention in compiling.rst

* Proper `#error` for Python 2.

* Using PY_VERSION_HEX to guard `#error "PYTHON 2 IS NO LONGER SUPPORTED.`

* chore: bump pre-commit

* style: run pre-commit for pyupgrade 3+

* tests: use sys.version_info, not PY

* chore: more Python 2 removal

* Uncommenting Centos7 block (PR #3691 showed that it is working again).

* Update pre-commit hooks

* Fix pre-commit hook

* refactor: remove Python 2 from CMake

* refactor: remove Python 2 from setup code

* refactor: simplify, better static typing

* feat: fail with nice messages

* refactor: drop Python 2 C++ code

* docs: cleanup for Python 3

* revert: intree

revert: intree

* docs: minor touchup to py2 statement
Co-authored-by: default avatarHenry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: default avatarAaron Gokaslan <skylion.aaron@gmail.com>
parent 46dcd9bc
# -*- coding: utf-8 -*-
"""pytest configuration """pytest configuration
Extends output capture as needed by pybind11: ignore constructors, optional unordered lines. Extends output capture as needed by pybind11: ignore constructors, optional unordered lines.
Adds docstring and exceptions message sanitizers: ignore Python 2 vs 3 differences. Adds docstring and exceptions message sanitizers.
""" """
import contextlib import contextlib
...@@ -13,19 +12,14 @@ import textwrap ...@@ -13,19 +12,14 @@ import textwrap
import pytest import pytest
import env
# Early diagnostic for failed imports # Early diagnostic for failed imports
import pybind11_tests # noqa: F401 import pybind11_tests # noqa: F401
_unicode_marker = re.compile(r"u(\'[^\']*\')")
_long_marker = re.compile(r"([0-9])L") _long_marker = re.compile(r"([0-9])L")
_hexadecimal = re.compile(r"0x[0-9a-fA-F]+") _hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
# Avoid collecting Python3 only files # Avoid collecting Python3 only files
collect_ignore = [] collect_ignore = []
if env.PY2:
collect_ignore.append("test_async.py")
def _strip_and_dedent(s): def _strip_and_dedent(s):
...@@ -45,7 +39,7 @@ def _make_explanation(a, b): ...@@ -45,7 +39,7 @@ def _make_explanation(a, b):
] ]
class Output(object): class Output:
"""Basic output post-processing and comparison""" """Basic output post-processing and comparison"""
def __init__(self, string): def __init__(self, string):
...@@ -83,7 +77,7 @@ class Unordered(Output): ...@@ -83,7 +77,7 @@ class Unordered(Output):
return False return False
class Capture(object): class Capture:
def __init__(self, capfd): def __init__(self, capfd):
self.capfd = capfd self.capfd = capfd
self.out = "" self.out = ""
...@@ -126,7 +120,7 @@ def capture(capsys): ...@@ -126,7 +120,7 @@ def capture(capsys):
return Capture(capsys) return Capture(capsys)
class SanitizedString(object): class SanitizedString:
def __init__(self, sanitizer): def __init__(self, sanitizer):
self.sanitizer = sanitizer self.sanitizer = sanitizer
self.string = "" self.string = ""
...@@ -149,9 +143,7 @@ class SanitizedString(object): ...@@ -149,9 +143,7 @@ class SanitizedString(object):
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 = s.replace("unicode", "str")
s = _long_marker.sub(r"\1", s) s = _long_marker.sub(r"\1", s)
s = _unicode_marker.sub(r"\1", s)
return s return s
......
...@@ -25,31 +25,14 @@ void gil_acquire() { py::gil_scoped_acquire gil; } ...@@ -25,31 +25,14 @@ void gil_acquire() { py::gil_scoped_acquire gil; }
constexpr char kModuleName[] = "cross_module_gil_utils"; constexpr char kModuleName[] = "cross_module_gil_utils";
#if PY_MAJOR_VERSION >= 3
struct PyModuleDef moduledef struct PyModuleDef moduledef
= {PyModuleDef_HEAD_INIT, kModuleName, NULL, 0, NULL, NULL, NULL, NULL, NULL}; = {PyModuleDef_HEAD_INIT, kModuleName, NULL, 0, NULL, NULL, NULL, NULL, NULL};
#else
PyMethodDef module_methods[] = {{NULL, NULL, 0, NULL}};
#endif
} // namespace } // namespace
extern "C" PYBIND11_EXPORT extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() {
#if PY_MAJOR_VERSION >= 3
PyObject *
PyInit_cross_module_gil_utils()
#else
void
initcross_module_gil_utils()
#endif
{
PyObject *m = PyObject *m = PyModule_Create(&moduledef);
#if PY_MAJOR_VERSION >= 3
PyModule_Create(&moduledef);
#else
Py_InitModule(kModuleName, module_methods);
#endif
if (m != NULL) { if (m != NULL) {
static_assert(sizeof(&gil_acquire) == sizeof(void *), static_assert(sizeof(&gil_acquire) == sizeof(void *),
...@@ -58,7 +41,5 @@ extern "C" PYBIND11_EXPORT ...@@ -58,7 +41,5 @@ extern "C" PYBIND11_EXPORT
m, "gil_acquire_funcaddr", PyLong_FromVoidPtr(reinterpret_cast<void *>(&gil_acquire))); m, "gil_acquire_funcaddr", PyLong_FromVoidPtr(reinterpret_cast<void *>(&gil_acquire)));
} }
#if PY_MAJOR_VERSION >= 3
return m; return m;
#endif
} }
# -*- coding: utf-8 -*-
import platform import platform
import sys import sys
...@@ -11,10 +10,6 @@ WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin") ...@@ -11,10 +10,6 @@ WIN = sys.platform.startswith("win32") or sys.platform.startswith("cygwin")
CPYTHON = platform.python_implementation() == "CPython" CPYTHON = platform.python_implementation() == "CPython"
PYPY = platform.python_implementation() == "PyPy" PYPY = platform.python_implementation() == "PyPy"
PY2 = sys.version_info.major == 2
PY = sys.version_info
def deprecated_call(): def deprecated_call():
""" """
......
# -*- coding: utf-8 -*-
import contextlib import contextlib
import os import os
import string import string
...@@ -64,11 +63,9 @@ py_files = { ...@@ -64,11 +63,9 @@ py_files = {
"__init__.py", "__init__.py",
"__main__.py", "__main__.py",
"_version.py", "_version.py",
"_version.pyi",
"commands.py", "commands.py",
"py.typed", "py.typed",
"setup_helpers.py", "setup_helpers.py",
"setup_helpers.pyi",
} }
headers = main_headers | detail_headers | stl_headers headers = main_headers | detail_headers | stl_headers
......
# -*- coding: utf-8 -*-
import os import os
import subprocess import subprocess
import sys import sys
...@@ -19,7 +18,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std): ...@@ -19,7 +18,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
(tmpdir / "setup.py").write_text( (tmpdir / "setup.py").write_text(
dedent( dedent(
u"""\ """\
import sys import sys
sys.path.append({MAIN_DIR!r}) sys.path.append({MAIN_DIR!r})
...@@ -58,7 +57,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std): ...@@ -58,7 +57,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
(tmpdir / "main.cpp").write_text( (tmpdir / "main.cpp").write_text(
dedent( dedent(
u"""\ """\
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
int f(int x) { int f(int x) {
...@@ -96,7 +95,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std): ...@@ -96,7 +95,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std):
(tmpdir / "test.py").write_text( (tmpdir / "test.py").write_text(
dedent( dedent(
u"""\ """\
import simple_setup import simple_setup
assert simple_setup.f(3) == 9 assert simple_setup.f(3) == 9
""" """
...@@ -121,10 +120,11 @@ def test_intree_extensions(monkeypatch, tmpdir): ...@@ -121,10 +120,11 @@ def test_intree_extensions(monkeypatch, tmpdir):
subdir.ensure_dir() subdir.ensure_dir()
src = subdir / "ext.cpp" src = subdir / "ext.cpp"
src.ensure() src.ensure()
(ext,) = intree_extensions([src.relto(tmpdir)]) relpath = src.relto(tmpdir)
(ext,) = intree_extensions([relpath])
assert ext.name == "ext" assert ext.name == "ext"
subdir.ensure("__init__.py") subdir.ensure("__init__.py")
(ext,) = intree_extensions([src.relto(tmpdir)]) (ext,) = intree_extensions([relpath])
assert ext.name == "dir.ext" assert ext.name == "dir.ext"
......
# -*- coding: utf-8 -*-
import pytest import pytest
asyncio = pytest.importorskip("asyncio") asyncio = pytest.importorskip("asyncio")
......
# -*- coding: utf-8 -*-
import ctypes import ctypes
import io import io
import struct import struct
...@@ -93,16 +92,16 @@ def test_pointer_to_member_fn(): ...@@ -93,16 +92,16 @@ def test_pointer_to_member_fn():
def test_readonly_buffer(): def test_readonly_buffer():
buf = m.BufferReadOnly(0x64) buf = m.BufferReadOnly(0x64)
view = memoryview(buf) view = memoryview(buf)
assert view[0] == b"d" if env.PY2 else 0x64 assert view[0] == 0x64
assert view.readonly assert view.readonly
with pytest.raises(TypeError): with pytest.raises(TypeError):
view[0] = b"\0" if env.PY2 else 0 view[0] = 0
def test_selective_readonly_buffer(): def test_selective_readonly_buffer():
buf = m.BufferReadOnlySelect() buf = m.BufferReadOnlySelect()
memoryview(buf)[0] = b"d" if env.PY2 else 0x64 memoryview(buf)[0] = 0x64
assert buf.value == 0x64 assert buf.value == 0x64
io.BytesIO(b"A").readinto(buf) io.BytesIO(b"A").readinto(buf)
...@@ -110,7 +109,7 @@ def test_selective_readonly_buffer(): ...@@ -110,7 +109,7 @@ def test_selective_readonly_buffer():
buf.readonly = True buf.readonly = True
with pytest.raises(TypeError): with pytest.raises(TypeError):
memoryview(buf)[0] = b"\0" if env.PY2 else 0 memoryview(buf)[0] = 0
with pytest.raises(TypeError): with pytest.raises(TypeError):
io.BytesIO(b"1").readinto(buf) io.BytesIO(b"1").readinto(buf)
...@@ -145,9 +144,6 @@ def test_ctypes_array_2d(): ...@@ -145,9 +144,6 @@ def test_ctypes_array_2d():
assert not info.readonly assert not info.readonly
@pytest.mark.skipif(
"env.PYPY and env.PY2", reason="PyPy2 bytes buffer not reported as readonly"
)
def test_ctypes_from_buffer(): def test_ctypes_from_buffer():
test_pystr = b"0123456789" test_pystr = b"0123456789"
for pyarray in (test_pystr, bytearray(test_pystr)): for pyarray in (test_pystr, bytearray(test_pystr)):
......
...@@ -110,8 +110,7 @@ TEST_SUBMODULE(builtin_casters, m) { ...@@ -110,8 +110,7 @@ TEST_SUBMODULE(builtin_casters, m) {
"def"); "def");
}); });
m.def("bad_utf16_string", [=]() { return std::u16string({b16, char16_t(0xd800), z16}); }); m.def("bad_utf16_string", [=]() { return std::u16string({b16, char16_t(0xd800), z16}); });
#if PY_MAJOR_VERSION >= 3 // Under Python 2.7, invalid unicode UTF-32 characters didn't appear to trigger
// Under Python 2.7, invalid unicode UTF-32 characters don't appear to trigger
// UnicodeDecodeError // UnicodeDecodeError
m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); }); m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(wchar_t) == 2)) { if (PYBIND11_SILENCE_MSVC_C4127(sizeof(wchar_t) == 2)) {
...@@ -119,7 +118,6 @@ TEST_SUBMODULE(builtin_casters, m) { ...@@ -119,7 +118,6 @@ TEST_SUBMODULE(builtin_casters, m) {
return std::wstring({wchar_t(0x61), wchar_t(0xd800)}); return std::wstring({wchar_t(0x61), wchar_t(0xd800)});
}); });
} }
#endif
m.def("u8_Z", []() -> char { return 'Z'; }); m.def("u8_Z", []() -> char { return 'Z'; });
m.def("u8_eacute", []() -> char { return '\xe9'; }); m.def("u8_eacute", []() -> char { return '\xe9'; });
m.def("u16_ibang", [=]() -> char16_t { return ib16; }); m.def("u16_ibang", [=]() -> char16_t { return ib16; });
...@@ -198,12 +196,10 @@ TEST_SUBMODULE(builtin_casters, m) { ...@@ -198,12 +196,10 @@ TEST_SUBMODULE(builtin_casters, m) {
[]() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); }); []() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); });
m.def("string_view_from_bytes", m.def("string_view_from_bytes",
[](const py::bytes &b) { return [](std::string_view s) { return s; }(b); }); [](const py::bytes &b) { return [](std::string_view s) { return s; }(b); });
# if PY_MAJOR_VERSION >= 3
m.def("string_view_memoryview", []() { m.def("string_view_memoryview", []() {
static constexpr auto val = "Have some \360\237\216\202"sv; static constexpr auto val = "Have some \360\237\216\202"sv;
return py::memoryview::from_memory(val); return py::memoryview::from_memory(val);
}); });
# endif
# ifdef PYBIND11_HAS_U8STRING # ifdef PYBIND11_HAS_U8STRING
m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); }); m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
......
# -*- coding: utf-8 -*- import sys
import pytest import pytest
import env import env
...@@ -12,12 +13,12 @@ def test_simple_string(): ...@@ -12,12 +13,12 @@ def test_simple_string():
def test_unicode_conversion(): def test_unicode_conversion():
"""Tests unicode conversion and error reporting.""" """Tests unicode conversion and error reporting."""
assert m.good_utf8_string() == u"Say utf8‽ 🎂 𝐀" assert m.good_utf8_string() == "Say utf8‽ 🎂 𝐀"
assert m.good_utf16_string() == u"b‽🎂𝐀z" assert m.good_utf16_string() == "b‽🎂𝐀z"
assert m.good_utf32_string() == u"a𝐀🎂‽z" assert m.good_utf32_string() == "a𝐀🎂‽z"
assert m.good_wchar_string() == u"a⸘𝐀z" assert m.good_wchar_string() == "a⸘𝐀z"
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
assert m.good_utf8_u8string() == u"Say utf8‽ 🎂 𝐀" assert m.good_utf8_u8string() == "Say utf8‽ 🎂 𝐀"
with pytest.raises(UnicodeDecodeError): with pytest.raises(UnicodeDecodeError):
m.bad_utf8_string() m.bad_utf8_string()
...@@ -25,7 +26,7 @@ def test_unicode_conversion(): ...@@ -25,7 +26,7 @@ def test_unicode_conversion():
with pytest.raises(UnicodeDecodeError): with pytest.raises(UnicodeDecodeError):
m.bad_utf16_string() m.bad_utf16_string()
# These are provided only if they actually fail (they don't when 32-bit and under Python 2.7) # These are provided only if they actually fail (they don't when 32-bit)
if hasattr(m, "bad_utf32_string"): if hasattr(m, "bad_utf32_string"):
with pytest.raises(UnicodeDecodeError): with pytest.raises(UnicodeDecodeError):
m.bad_utf32_string() m.bad_utf32_string()
...@@ -37,10 +38,10 @@ def test_unicode_conversion(): ...@@ -37,10 +38,10 @@ def test_unicode_conversion():
m.bad_utf8_u8string() m.bad_utf8_u8string()
assert m.u8_Z() == "Z" assert m.u8_Z() == "Z"
assert m.u8_eacute() == u"é" assert m.u8_eacute() == "é"
assert m.u16_ibang() == u"‽" assert m.u16_ibang() == "‽"
assert m.u32_mathbfA() == u"𝐀" assert m.u32_mathbfA() == "𝐀"
assert m.wchar_heart() == u"♥" assert m.wchar_heart() == "♥"
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
assert m.u8_char8_Z() == "Z" assert m.u8_char8_Z() == "Z"
...@@ -53,68 +54,68 @@ def test_single_char_arguments(): ...@@ -53,68 +54,68 @@ def test_single_char_arguments():
toolong_message = "Expected a character, but multi-character string found" toolong_message = "Expected a character, but multi-character string found"
assert m.ord_char(u"a") == 0x61 # simple ASCII assert m.ord_char("a") == 0x61 # simple ASCII
assert m.ord_char_lv(u"b") == 0x62 assert m.ord_char_lv("b") == 0x62
assert ( assert (
m.ord_char(u"é") == 0xE9 m.ord_char("é") == 0xE9
) # requires 2 bytes in utf-8, but can be stuffed in a char ) # requires 2 bytes in utf-8, but can be stuffed in a char
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
assert m.ord_char(u"Ā") == 0x100 # requires 2 bytes, doesn't fit in a char assert m.ord_char("Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
assert str(excinfo.value) == toobig_message(0x100) assert str(excinfo.value) == toobig_message(0x100)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
assert m.ord_char(u"ab") assert m.ord_char("ab")
assert str(excinfo.value) == toolong_message assert str(excinfo.value) == toolong_message
assert m.ord_char16(u"a") == 0x61 assert m.ord_char16("a") == 0x61
assert m.ord_char16(u"é") == 0xE9 assert m.ord_char16("é") == 0xE9
assert m.ord_char16_lv(u"ê") == 0xEA assert m.ord_char16_lv("ê") == 0xEA
assert m.ord_char16(u"Ā") == 0x100 assert m.ord_char16("Ā") == 0x100
assert m.ord_char16(u"‽") == 0x203D assert m.ord_char16("‽") == 0x203D
assert m.ord_char16(u"♥") == 0x2665 assert m.ord_char16("♥") == 0x2665
assert m.ord_char16_lv(u"♡") == 0x2661 assert m.ord_char16_lv("♡") == 0x2661
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
assert m.ord_char16(u"🎂") == 0x1F382 # requires surrogate pair assert m.ord_char16("🎂") == 0x1F382 # requires surrogate pair
assert str(excinfo.value) == toobig_message(0x10000) assert str(excinfo.value) == toobig_message(0x10000)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
assert m.ord_char16(u"aa") assert m.ord_char16("aa")
assert str(excinfo.value) == toolong_message assert str(excinfo.value) == toolong_message
assert m.ord_char32(u"a") == 0x61 assert m.ord_char32("a") == 0x61
assert m.ord_char32(u"é") == 0xE9 assert m.ord_char32("é") == 0xE9
assert m.ord_char32(u"Ā") == 0x100 assert m.ord_char32("Ā") == 0x100
assert m.ord_char32(u"‽") == 0x203D assert m.ord_char32("‽") == 0x203D
assert m.ord_char32(u"♥") == 0x2665 assert m.ord_char32("♥") == 0x2665
assert m.ord_char32(u"🎂") == 0x1F382 assert m.ord_char32("🎂") == 0x1F382
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
assert m.ord_char32(u"aa") assert m.ord_char32("aa")
assert str(excinfo.value) == toolong_message assert str(excinfo.value) == toolong_message
assert m.ord_wchar(u"a") == 0x61 assert m.ord_wchar("a") == 0x61
assert m.ord_wchar(u"é") == 0xE9 assert m.ord_wchar("é") == 0xE9
assert m.ord_wchar(u"Ā") == 0x100 assert m.ord_wchar("Ā") == 0x100
assert m.ord_wchar(u"‽") == 0x203D assert m.ord_wchar("‽") == 0x203D
assert m.ord_wchar(u"♥") == 0x2665 assert m.ord_wchar("♥") == 0x2665
if m.wchar_size == 2: if m.wchar_size == 2:
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
assert m.ord_wchar(u"🎂") == 0x1F382 # requires surrogate pair assert m.ord_wchar("🎂") == 0x1F382 # requires surrogate pair
assert str(excinfo.value) == toobig_message(0x10000) assert str(excinfo.value) == toobig_message(0x10000)
else: else:
assert m.ord_wchar(u"🎂") == 0x1F382 assert m.ord_wchar("🎂") == 0x1F382
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
assert m.ord_wchar(u"aa") assert m.ord_wchar("aa")
assert str(excinfo.value) == toolong_message assert str(excinfo.value) == toolong_message
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
assert m.ord_char8(u"a") == 0x61 # simple ASCII assert m.ord_char8("a") == 0x61 # simple ASCII
assert m.ord_char8_lv(u"b") == 0x62 assert m.ord_char8_lv("b") == 0x62
assert ( assert (
m.ord_char8(u"é") == 0xE9 m.ord_char8("é") == 0xE9
) # requires 2 bytes in utf-8, but can be stuffed in a char ) # requires 2 bytes in utf-8, but can be stuffed in a char
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
assert m.ord_char8(u"Ā") == 0x100 # requires 2 bytes, doesn't fit in a char assert m.ord_char8("Ā") == 0x100 # requires 2 bytes, doesn't fit in a char
assert str(excinfo.value) == toobig_message(0x100) assert str(excinfo.value) == toobig_message(0x100)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
assert m.ord_char8(u"ab") assert m.ord_char8("ab")
assert str(excinfo.value) == toolong_message assert str(excinfo.value) == toolong_message
...@@ -123,18 +124,13 @@ def test_bytes_to_string(): ...@@ -123,18 +124,13 @@ def test_bytes_to_string():
one-way: the only way to return bytes to Python is via the pybind11::bytes class.""" one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
# Issue #816 # Issue #816
def to_bytes(s): assert m.strlen(b"hi") == 2
b = s if env.PY2 else s.encode("utf8") assert m.string_length(b"world") == 5
assert isinstance(b, bytes) assert m.string_length("a\x00b".encode()) == 3
return b assert m.strlen("a\x00b".encode()) == 1 # C-string limitation
assert m.strlen(to_bytes("hi")) == 2
assert m.string_length(to_bytes("world")) == 5
assert m.string_length(to_bytes("a\x00b")) == 3
assert m.strlen(to_bytes("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(u"💩".encode("utf8")) == 4 assert m.string_length("💩".encode()) == 4
@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>") @pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>")
...@@ -142,26 +138,26 @@ def test_string_view(capture): ...@@ -142,26 +138,26 @@ def test_string_view(capture):
"""Tests support for C++17 string_view arguments and return values""" """Tests support for C++17 string_view arguments and return values"""
assert m.string_view_chars("Hi") == [72, 105] assert m.string_view_chars("Hi") == [72, 105]
assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82] assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
assert m.string_view16_chars(u"Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82] assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xD83C, 0xDF82]
assert m.string_view32_chars(u"Hi 🎂") == [72, 105, 32, 127874] assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874]
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
assert m.string_view8_chars("Hi") == [72, 105] assert m.string_view8_chars("Hi") == [72, 105]
assert m.string_view8_chars(u"Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82] assert m.string_view8_chars("Hi 🎂") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82]
assert m.string_view_return() == u"utf8 secret 🎂" assert m.string_view_return() == "utf8 secret 🎂"
assert m.string_view16_return() == u"utf16 secret 🎂" assert m.string_view16_return() == "utf16 secret 🎂"
assert m.string_view32_return() == u"utf32 secret 🎂" assert m.string_view32_return() == "utf32 secret 🎂"
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
assert m.string_view8_return() == u"utf8 secret 🎂" assert m.string_view8_return() == "utf8 secret 🎂"
with capture: with capture:
m.string_view_print("Hi") m.string_view_print("Hi")
m.string_view_print("utf8 🎂") m.string_view_print("utf8 🎂")
m.string_view16_print(u"utf16 🎂") m.string_view16_print("utf16 🎂")
m.string_view32_print(u"utf32 🎂") m.string_view32_print("utf32 🎂")
assert ( assert (
capture capture
== u""" == """
Hi 2 Hi 2
utf8 🎂 9 utf8 🎂 9
utf16 🎂 8 utf16 🎂 8
...@@ -171,10 +167,10 @@ def test_string_view(capture): ...@@ -171,10 +167,10 @@ def test_string_view(capture):
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
with capture: with capture:
m.string_view8_print("Hi") m.string_view8_print("Hi")
m.string_view8_print(u"utf8 🎂") m.string_view8_print("utf8 🎂")
assert ( assert (
capture capture
== u""" == """
Hi 2 Hi 2
utf8 🎂 9 utf8 🎂 9
""" """
...@@ -183,11 +179,11 @@ def test_string_view(capture): ...@@ -183,11 +179,11 @@ def test_string_view(capture):
with capture: with capture:
m.string_view_print("Hi, ascii") m.string_view_print("Hi, ascii")
m.string_view_print("Hi, utf8 🎂") m.string_view_print("Hi, utf8 🎂")
m.string_view16_print(u"Hi, utf16 🎂") m.string_view16_print("Hi, utf16 🎂")
m.string_view32_print(u"Hi, utf32 🎂") m.string_view32_print("Hi, utf32 🎂")
assert ( assert (
capture capture
== u""" == """
Hi, ascii 9 Hi, ascii 9
Hi, utf8 🎂 13 Hi, utf8 🎂 13
Hi, utf16 🎂 12 Hi, utf16 🎂 12
...@@ -197,22 +193,21 @@ def test_string_view(capture): ...@@ -197,22 +193,21 @@ def test_string_view(capture):
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
with capture: with capture:
m.string_view8_print("Hi, ascii") m.string_view8_print("Hi, ascii")
m.string_view8_print(u"Hi, utf8 🎂") m.string_view8_print("Hi, utf8 🎂")
assert ( assert (
capture capture
== u""" == """
Hi, ascii 9 Hi, ascii 9
Hi, utf8 🎂 13 Hi, utf8 🎂 13
""" """
) )
assert m.string_view_bytes() == b"abc \x80\x80 def" assert m.string_view_bytes() == b"abc \x80\x80 def"
assert m.string_view_str() == u"abc ‽ def" assert m.string_view_str() == "abc ‽ def"
assert m.string_view_from_bytes(u"abc ‽ def".encode("utf-8")) == u"abc ‽ def" assert m.string_view_from_bytes("abc ‽ def".encode()) == "abc ‽ def"
if hasattr(m, "has_u8string"): if hasattr(m, "has_u8string"):
assert m.string_view8_str() == u"abc ‽ def" assert m.string_view8_str() == "abc ‽ def"
if not env.PY2: assert m.string_view_memoryview() == "Have some 🎂".encode()
assert m.string_view_memoryview() == "Have some 🎂".encode()
assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success" assert m.bytes_from_type_with_both_operator_string_and_string_view() == b"success"
assert m.str_from_type_with_both_operator_string_and_string_view() == "success" assert m.str_from_type_with_both_operator_string_and_string_view() == "success"
...@@ -224,20 +219,8 @@ def test_integer_casting(): ...@@ -224,20 +219,8 @@ def test_integer_casting():
assert m.i64_str(-1) == "-1" assert m.i64_str(-1) == "-1"
assert m.i32_str(2000000000) == "2000000000" assert m.i32_str(2000000000) == "2000000000"
assert m.u32_str(2000000000) == "2000000000" assert m.u32_str(2000000000) == "2000000000"
if env.PY2: assert m.i64_str(-999999999999) == "-999999999999"
assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long' assert m.u64_str(999999999999) == "999999999999"
assert m.i64_str(long(-1)) == "-1" # noqa: F821 undefined name 'long'
assert (
m.i64_str(long(-999999999999)) # noqa: F821 undefined name 'long'
== "-999999999999"
)
assert (
m.u64_str(long(999999999999)) # noqa: F821 undefined name 'long'
== "999999999999"
)
else:
assert m.i64_str(-999999999999) == "-999999999999"
assert m.u64_str(999999999999) == "999999999999"
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
m.u32_str(-1) m.u32_str(-1)
...@@ -252,46 +235,38 @@ def test_integer_casting(): ...@@ -252,46 +235,38 @@ def test_integer_casting():
m.i32_str(3000000000) m.i32_str(3000000000)
assert "incompatible function arguments" in str(excinfo.value) assert "incompatible function arguments" in str(excinfo.value)
if env.PY2:
with pytest.raises(TypeError) as excinfo:
m.u32_str(long(-1)) # noqa: F821 undefined name 'long'
assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo:
m.u64_str(long(-1)) # noqa: F821 undefined name 'long'
assert "incompatible function arguments" in str(excinfo.value)
def test_int_convert(): def test_int_convert():
class Int(object): class Int:
def __int__(self): def __int__(self):
return 42 return 42
class NotInt(object): class NotInt:
pass pass
class Float(object): class Float:
def __float__(self): def __float__(self):
return 41.99999 return 41.99999
class Index(object): class Index:
def __index__(self): def __index__(self):
return 42 return 42
class IntAndIndex(object): class IntAndIndex:
def __int__(self): def __int__(self):
return 42 return 42
def __index__(self): def __index__(self):
return 0 return 0
class RaisingTypeErrorOnIndex(object): class RaisingTypeErrorOnIndex:
def __index__(self): def __index__(self):
raise TypeError raise TypeError
def __int__(self): def __int__(self):
return 42 return 42
class RaisingValueErrorOnIndex(object): class RaisingValueErrorOnIndex:
def __index__(self): def __index__(self):
raise ValueError raise ValueError
...@@ -311,7 +286,7 @@ def test_int_convert(): ...@@ -311,7 +286,7 @@ def test_int_convert():
cant_convert(3.14159) cant_convert(3.14159)
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar) # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7) # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
if (3, 8) <= env.PY < (3, 10) and env.CPYTHON: if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
with env.deprecated_call(): with env.deprecated_call():
assert convert(Int()) == 42 assert convert(Int()) == 42
else: else:
...@@ -348,7 +323,7 @@ def test_numpy_int_convert(): ...@@ -348,7 +323,7 @@ def test_numpy_int_convert():
# TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar) # TODO: Avoid DeprecationWarning in `PyLong_AsLong` (and similar)
# TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7) # TODO: PyPy 3.8 does not behave like CPython 3.8 here yet (7.3.7)
# https://github.com/pybind/pybind11/issues/3408 # https://github.com/pybind/pybind11/issues/3408
if (3, 8) <= env.PY < (3, 10) and env.CPYTHON: if (3, 8) <= sys.version_info < (3, 10) and env.CPYTHON:
with env.deprecated_call(): with env.deprecated_call():
assert convert(np.float32(3.14159)) == 3 assert convert(np.float32(3.14159)) == 3
else: else:
...@@ -475,7 +450,7 @@ def test_bool_caster(): ...@@ -475,7 +450,7 @@ def test_bool_caster():
require_implicit(None) require_implicit(None)
assert convert(None) is False assert convert(None) is False
class A(object): class A:
def __init__(self, x): def __init__(self, x):
self.x = x self.x = x
...@@ -485,7 +460,7 @@ def test_bool_caster(): ...@@ -485,7 +460,7 @@ def test_bool_caster():
def __bool__(self): def __bool__(self):
return self.x return self.x
class B(object): class B:
pass pass
# Arbitrary objects are not accepted # Arbitrary objects are not accepted
...@@ -515,17 +490,9 @@ def test_numpy_bool(): ...@@ -515,17 +490,9 @@ def test_numpy_bool():
def test_int_long(): def test_int_long():
"""In Python 2, a C++ int should return a Python int rather than long
if possible: longs are not always accepted where ints are used (such
as the argument to sys.exit()). A C++ long long is always a Python
long."""
import sys
must_be_long = type(getattr(sys, "maxint", 1) + 1)
assert isinstance(m.int_cast(), int) assert isinstance(m.int_cast(), int)
assert isinstance(m.long_cast(), int) assert isinstance(m.long_cast(), int)
assert isinstance(m.longlong_cast(), must_be_long) assert isinstance(m.longlong_cast(), int)
def test_void_caster_2(): def test_void_caster_2():
......
# -*- coding: utf-8 -*-
import pytest import pytest
import env # noqa: F401 import env # noqa: F401
......
# -*- coding: utf-8 -*-
import time import time
from threading import Thread from threading import Thread
......
# -*- coding: utf-8 -*-
import datetime import datetime
import pytest import pytest
......
# -*- coding: utf-8 -*-
import pytest import pytest
import env # noqa: F401 import env # noqa: F401
...@@ -7,7 +6,6 @@ from pybind11_tests import class_ as m ...@@ -7,7 +6,6 @@ from pybind11_tests import class_ as m
def test_repr(): def test_repr():
# In Python 3.3+, repr() accesses __qualname__
assert "pybind11_type" in repr(type(UserType)) assert "pybind11_type" in repr(type(UserType))
assert "UserType" in repr(UserType) assert "UserType" in repr(UserType)
...@@ -103,8 +101,8 @@ def test_docstrings(doc): ...@@ -103,8 +101,8 @@ def test_docstrings(doc):
def test_qualname(doc): def test_qualname(doc):
"""Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we """Tests that a properly qualified name is set in __qualname__ and that
backport the attribute) and that generated docstrings properly use it and the module name""" generated docstrings properly use it and the module name"""
assert m.NestBase.__qualname__ == "NestBase" assert m.NestBase.__qualname__ == "NestBase"
assert m.NestBase.Nested.__qualname__ == "NestBase.Nested" assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
...@@ -130,13 +128,13 @@ def test_qualname(doc): ...@@ -130,13 +128,13 @@ def test_qualname(doc):
doc(m.NestBase.Nested.fn) doc(m.NestBase.Nested.fn)
== """ == """
fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
""" # noqa: E501 line too long """
) )
assert ( assert (
doc(m.NestBase.Nested.fa) doc(m.NestBase.Nested.fa)
== """ == """
fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
""" # noqa: E501 line too long """
) )
assert m.NestBase.__module__ == "pybind11_tests.class_" assert m.NestBase.__module__ == "pybind11_tests.class_"
assert m.NestBase.Nested.__module__ == "pybind11_tests.class_" assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
......
# -*- coding: utf-8 -*-
import sys import sys
import test_cmake_build import test_cmake_build
if str is not bytes: # If not Python2 assert isinstance(__file__, str) # Test this is properly set
assert isinstance(__file__, str) # Test this is properly set
assert test_cmake_build.add(1, 2) == 3 assert test_cmake_build.add(1, 2) == 3
print("{} imports, runs, and adds: 1 + 2 = 3".format(sys.argv[1])) print("{} imports, runs, and adds: 1 + 2 = 3".format(sys.argv[1]))
# -*- coding: utf-8 -*-
import pytest import pytest
import env
from pybind11_tests import const_name as m from pybind11_tests import const_name as m
...@@ -25,7 +23,7 @@ from pybind11_tests import const_name as m ...@@ -25,7 +23,7 @@ from pybind11_tests import const_name as m
), ),
) )
def test_const_name(func, selector, expected): def test_const_name(func, selector, expected):
if isinstance(func, type(u"") if env.PY2 else str): if isinstance(func, str):
pytest.skip(func) pytest.skip(func)
text = func(selector) text = func(selector)
assert text == expected assert text == expected
# -*- coding: utf-8 -*-
import pytest import pytest
m = pytest.importorskip("pybind11_tests.constants_and_functions") m = pytest.importorskip("pybind11_tests.constants_and_functions")
......
# -*- coding: utf-8 -*-
import pytest import pytest
from pybind11_tests import copy_move_policies as m from pybind11_tests import copy_move_policies as m
......
# -*- coding: utf-8 -*-
import pytest import pytest
from pybind11_tests import custom_type_casters as m from pybind11_tests import custom_type_casters as m
...@@ -19,7 +18,7 @@ def test_noconvert_args(msg): ...@@ -19,7 +18,7 @@ def test_noconvert_args(msg):
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
13 13
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
""" # noqa: E501 line too long """
) )
assert ( assert (
msg(a.g("this is a", "this is b", 42)) msg(a.g("this is a", "this is b", 42))
...@@ -28,7 +27,7 @@ def test_noconvert_args(msg): ...@@ -28,7 +27,7 @@ def test_noconvert_args(msg):
loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b
42 42
loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2)
""" # noqa: E501 line too long """
) )
assert ( assert (
msg(a.g("this is a", "this is b", 42, "this is d")) msg(a.g("this is a", "this is b", 42, "this is d"))
...@@ -76,7 +75,7 @@ def test_noconvert_args(msg): ...@@ -76,7 +75,7 @@ def test_noconvert_args(msg):
1. (i: int) -> int 1. (i: int) -> int
Invoked with: 4.0 Invoked with: 4.0
""" # noqa: E501 line too long """
) )
assert m.ints_only(4) == 2 assert m.ints_only(4) == 2
......
# -*- coding: utf-8 -*-
import gc import gc
import weakref import weakref
......
# -*- coding: utf-8 -*-
from pybind11_tests import docstring_options as m from pybind11_tests import docstring_options as m
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment