mirror of
https://github.com/pybind/pybind11.git
synced 2026-03-14 20:27:47 +00:00
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: Henry Schreiner <henryschreineriii@gmail.com> Co-authored-by: Aaron Gokaslan <skylion.aaron@gmail.com>
This commit is contained in:
committed by
GitHub
parent
46dcd9bc75
commit
6493f496e3
@@ -1,11 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import env
|
||||
import env # noqa: F401
|
||||
from pybind11_tests import debug_enabled
|
||||
from pybind11_tests import pytypes as m
|
||||
|
||||
@@ -123,7 +120,6 @@ def test_tuple():
|
||||
assert m.get_tuple() == (42, None, "spam")
|
||||
|
||||
|
||||
@pytest.mark.skipif("env.PY2")
|
||||
def test_simple_namespace():
|
||||
ns = m.get_simple_namespace()
|
||||
assert ns.attr == 42
|
||||
@@ -140,7 +136,7 @@ def test_str(doc):
|
||||
|
||||
assert doc(m.str_from_bytes) == "str_from_bytes() -> str"
|
||||
|
||||
class A(object):
|
||||
class A:
|
||||
def __str__(self):
|
||||
return "this is a str"
|
||||
|
||||
@@ -158,24 +154,14 @@ def test_str(doc):
|
||||
malformed_utf8 = b"\x80"
|
||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||
assert m.str_from_object(malformed_utf8) is malformed_utf8
|
||||
elif env.PY2:
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
m.str_from_object(malformed_utf8)
|
||||
else:
|
||||
assert m.str_from_object(malformed_utf8) == "b'\\x80'"
|
||||
if env.PY2:
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
m.str_from_handle(malformed_utf8)
|
||||
else:
|
||||
assert m.str_from_handle(malformed_utf8) == "b'\\x80'"
|
||||
assert m.str_from_handle(malformed_utf8) == "b'\\x80'"
|
||||
|
||||
assert m.str_from_string_from_str("this is a str") == "this is a str"
|
||||
ucs_surrogates_str = u"\udcc3"
|
||||
if env.PY2:
|
||||
assert u"\udcc3" == m.str_from_string_from_str(ucs_surrogates_str)
|
||||
else:
|
||||
with pytest.raises(UnicodeEncodeError):
|
||||
m.str_from_string_from_str(ucs_surrogates_str)
|
||||
ucs_surrogates_str = "\udcc3"
|
||||
with pytest.raises(UnicodeEncodeError):
|
||||
m.str_from_string_from_str(ucs_surrogates_str)
|
||||
|
||||
|
||||
def test_bytes(doc):
|
||||
@@ -184,9 +170,7 @@ def test_bytes(doc):
|
||||
assert m.bytes_from_string().decode() == "foo"
|
||||
assert m.bytes_from_str().decode() == "bar"
|
||||
|
||||
assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format(
|
||||
"str" if env.PY2 else "bytes"
|
||||
)
|
||||
assert doc(m.bytes_from_str) == "bytes_from_str() -> bytes"
|
||||
|
||||
|
||||
def test_bytearray(doc):
|
||||
@@ -278,11 +262,6 @@ def test_constructors():
|
||||
"""C++ default and converting constructors are equivalent to type calls in Python"""
|
||||
types = [bytes, bytearray, str, bool, int, float, tuple, list, dict, set]
|
||||
expected = {t.__name__: t() for t in types}
|
||||
if env.PY2:
|
||||
# Note that bytes.__name__ == 'str' in Python 2.
|
||||
# pybind11::str is unicode even under Python 2.
|
||||
expected["bytes"] = bytes()
|
||||
expected["str"] = unicode() # noqa: F821
|
||||
assert m.default_constructors() == expected
|
||||
|
||||
data = {
|
||||
@@ -300,11 +279,6 @@ def test_constructors():
|
||||
}
|
||||
inputs = {k.__name__: v for k, v in data.items()}
|
||||
expected = {k.__name__: k(v) for k, v in data.items()}
|
||||
if env.PY2: # Similar to the above. See comments above.
|
||||
inputs["bytes"] = b"41"
|
||||
inputs["str"] = 42
|
||||
expected["bytes"] = b"41"
|
||||
expected["str"] = u"42"
|
||||
|
||||
assert m.converting_constructors(inputs) == expected
|
||||
assert m.cast_functions(inputs) == expected
|
||||
@@ -340,46 +314,39 @@ def test_non_converting_constructors():
|
||||
def test_pybind11_str_raw_str():
|
||||
# specifically to exercise pybind11::str::raw_str
|
||||
cvt = m.convert_to_pybind11_str
|
||||
assert cvt(u"Str") == u"Str"
|
||||
assert cvt(b"Bytes") == u"Bytes" if env.PY2 else "b'Bytes'"
|
||||
assert cvt(None) == u"None"
|
||||
assert cvt(False) == u"False"
|
||||
assert cvt(True) == u"True"
|
||||
assert cvt(42) == u"42"
|
||||
assert cvt(2 ** 65) == u"36893488147419103232"
|
||||
assert cvt(-1.50) == u"-1.5"
|
||||
assert cvt(()) == u"()"
|
||||
assert cvt((18,)) == u"(18,)"
|
||||
assert cvt([]) == u"[]"
|
||||
assert cvt([28]) == u"[28]"
|
||||
assert cvt({}) == u"{}"
|
||||
assert cvt({3: 4}) == u"{3: 4}"
|
||||
assert cvt(set()) == u"set([])" if env.PY2 else "set()"
|
||||
assert cvt({3, 3}) == u"set([3])" if env.PY2 else "{3}"
|
||||
assert cvt("Str") == "Str"
|
||||
assert cvt(b"Bytes") == "b'Bytes'"
|
||||
assert cvt(None) == "None"
|
||||
assert cvt(False) == "False"
|
||||
assert cvt(True) == "True"
|
||||
assert cvt(42) == "42"
|
||||
assert cvt(2**65) == "36893488147419103232"
|
||||
assert cvt(-1.50) == "-1.5"
|
||||
assert cvt(()) == "()"
|
||||
assert cvt((18,)) == "(18,)"
|
||||
assert cvt([]) == "[]"
|
||||
assert cvt([28]) == "[28]"
|
||||
assert cvt({}) == "{}"
|
||||
assert cvt({3: 4}) == "{3: 4}"
|
||||
assert cvt(set()) == "set()"
|
||||
assert cvt({3, 3}) == "{3}"
|
||||
|
||||
valid_orig = u"DZ"
|
||||
valid_orig = "DZ"
|
||||
valid_utf8 = valid_orig.encode("utf-8")
|
||||
valid_cvt = cvt(valid_utf8)
|
||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||
assert valid_cvt is valid_utf8
|
||||
else:
|
||||
assert type(valid_cvt) is unicode if env.PY2 else str # noqa: F821
|
||||
if env.PY2:
|
||||
assert valid_cvt == valid_orig
|
||||
else:
|
||||
assert valid_cvt == "b'\\xc7\\xb1'"
|
||||
assert type(valid_cvt) is str
|
||||
assert valid_cvt == "b'\\xc7\\xb1'"
|
||||
|
||||
malformed_utf8 = b"\x80"
|
||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||
assert cvt(malformed_utf8) is malformed_utf8
|
||||
else:
|
||||
if env.PY2:
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
cvt(malformed_utf8)
|
||||
else:
|
||||
malformed_cvt = cvt(malformed_utf8)
|
||||
assert type(malformed_cvt) is str
|
||||
assert malformed_cvt == "b'\\x80'"
|
||||
malformed_cvt = cvt(malformed_utf8)
|
||||
assert type(malformed_cvt) is str
|
||||
assert malformed_cvt == "b'\\x80'"
|
||||
|
||||
|
||||
def test_implicit_casting():
|
||||
@@ -428,14 +395,14 @@ def test_print(capture):
|
||||
|
||||
|
||||
def test_hash():
|
||||
class Hashable(object):
|
||||
class Hashable:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __hash__(self):
|
||||
return self.value
|
||||
|
||||
class Unhashable(object):
|
||||
class Unhashable:
|
||||
__hash__ = None
|
||||
|
||||
assert m.hash_function(Hashable(42)) == 42
|
||||
@@ -493,12 +460,7 @@ def test_memoryview(method, args, fmt, expected_view):
|
||||
view = method(*args)
|
||||
assert isinstance(view, memoryview)
|
||||
assert view.format == fmt
|
||||
if isinstance(expected_view, bytes) or not env.PY2:
|
||||
view_as_list = list(view)
|
||||
else:
|
||||
# Using max to pick non-zero byte (big-endian vs little-endian).
|
||||
view_as_list = [max(ord(c) for c in s) for s in view]
|
||||
assert view_as_list == list(expected_view)
|
||||
assert list(view) == list(expected_view)
|
||||
|
||||
|
||||
@pytest.mark.xfail("env.PYPY", reason="getrefcount is not available")
|
||||
@@ -522,12 +484,7 @@ def test_memoryview_from_buffer_empty_shape():
|
||||
view = m.test_memoryview_from_buffer_empty_shape()
|
||||
assert isinstance(view, memoryview)
|
||||
assert view.format == "B"
|
||||
if env.PY2:
|
||||
# Python 2 behavior is weird, but Python 3 (the future) is fine.
|
||||
# PyPy3 has <memoryview, while CPython 2 has <memory
|
||||
assert bytes(view).startswith(b"<memory")
|
||||
else:
|
||||
assert bytes(view) == b""
|
||||
assert bytes(view) == b""
|
||||
|
||||
|
||||
def test_test_memoryview_from_buffer_invalid_strides():
|
||||
@@ -536,14 +493,10 @@ def test_test_memoryview_from_buffer_invalid_strides():
|
||||
|
||||
|
||||
def test_test_memoryview_from_buffer_nullptr():
|
||||
if env.PY2:
|
||||
with pytest.raises(ValueError):
|
||||
m.test_memoryview_from_buffer_nullptr()
|
||||
else:
|
||||
with pytest.raises(ValueError):
|
||||
m.test_memoryview_from_buffer_nullptr()
|
||||
|
||||
|
||||
@pytest.mark.skipif("env.PY2")
|
||||
def test_memoryview_from_memory():
|
||||
view = m.test_memoryview_from_memory()
|
||||
assert isinstance(view, memoryview)
|
||||
@@ -563,9 +516,9 @@ def test_builtin_functions():
|
||||
|
||||
def test_isinstance_string_types():
|
||||
assert m.isinstance_pybind11_bytes(b"")
|
||||
assert not m.isinstance_pybind11_bytes(u"")
|
||||
assert not m.isinstance_pybind11_bytes("")
|
||||
|
||||
assert m.isinstance_pybind11_str(u"")
|
||||
assert m.isinstance_pybind11_str("")
|
||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||
assert m.isinstance_pybind11_str(b"")
|
||||
else:
|
||||
@@ -575,24 +528,21 @@ def test_isinstance_string_types():
|
||||
def test_pass_bytes_or_unicode_to_string_types():
|
||||
assert m.pass_to_pybind11_bytes(b"Bytes") == 5
|
||||
with pytest.raises(TypeError):
|
||||
m.pass_to_pybind11_bytes(u"Str")
|
||||
m.pass_to_pybind11_bytes("Str")
|
||||
|
||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE") or env.PY2:
|
||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||
assert m.pass_to_pybind11_str(b"Bytes") == 5
|
||||
else:
|
||||
with pytest.raises(TypeError):
|
||||
m.pass_to_pybind11_str(b"Bytes")
|
||||
assert m.pass_to_pybind11_str(u"Str") == 3
|
||||
assert m.pass_to_pybind11_str("Str") == 3
|
||||
|
||||
assert m.pass_to_std_string(b"Bytes") == 5
|
||||
assert m.pass_to_std_string(u"Str") == 3
|
||||
assert m.pass_to_std_string("Str") == 3
|
||||
|
||||
malformed_utf8 = b"\x80"
|
||||
if hasattr(m, "PYBIND11_STR_LEGACY_PERMISSIVE"):
|
||||
assert m.pass_to_pybind11_str(malformed_utf8) == 1
|
||||
elif env.PY2:
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
m.pass_to_pybind11_str(malformed_utf8)
|
||||
else:
|
||||
with pytest.raises(TypeError):
|
||||
m.pass_to_pybind11_str(malformed_utf8)
|
||||
@@ -609,12 +559,14 @@ def test_weakref(create_weakref, create_weakref_with_callback):
|
||||
from weakref import getweakrefcount
|
||||
|
||||
# Apparently, you cannot weakly reference an object()
|
||||
class WeaklyReferenced(object):
|
||||
class WeaklyReferenced:
|
||||
pass
|
||||
|
||||
callback_called = False
|
||||
|
||||
def callback(wr):
|
||||
# No `nonlocal` in Python 2
|
||||
callback.called = True
|
||||
nonlocal callback_called
|
||||
callback_called = True
|
||||
|
||||
obj = WeaklyReferenced()
|
||||
assert getweakrefcount(obj) == 0
|
||||
@@ -623,13 +575,12 @@ def test_weakref(create_weakref, create_weakref_with_callback):
|
||||
|
||||
obj = WeaklyReferenced()
|
||||
assert getweakrefcount(obj) == 0
|
||||
callback.called = False
|
||||
wr = create_weakref_with_callback(obj, callback) # noqa: F841
|
||||
assert getweakrefcount(obj) == 1
|
||||
assert not callback.called
|
||||
assert not callback_called
|
||||
del obj
|
||||
pytest.gc_collect()
|
||||
assert callback.called
|
||||
assert callback_called
|
||||
|
||||
|
||||
def test_cpp_iterators():
|
||||
|
||||
Reference in New Issue
Block a user