diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 985b2de85..77a4596c8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -83,6 +83,7 @@ repos: hooks: - id: python-check-blanket-noqa - id: python-check-blanket-type-ignore + exclude: ubench/holder_comparison.py - id: python-no-log-warn - id: python-use-type-annotations - id: rst-backticks diff --git a/include/pybind11/detail/smart_holder_type_casters.h b/include/pybind11/detail/smart_holder_type_casters.h index 9ff79e7b1..482090e39 100644 --- a/include/pybind11/detail/smart_holder_type_casters.h +++ b/include/pybind11/detail/smart_holder_type_casters.h @@ -49,7 +49,6 @@ inline void replace_all(std::string& str, const std::string& from, char to) { // The modified_type_caster_generic_load_impl could replace type_caster_generic::load_impl but not // vice versa. The main difference is that the original code only propagates a reference to the // held value, while the modified implementation propagates value_and_holder. -// clang-format off class modified_type_caster_generic_load_impl { public: PYBIND11_NOINLINE explicit modified_type_caster_generic_load_impl(const std::type_info &type_info) @@ -76,12 +75,15 @@ public: vptr = type->operator_new(type->type_size); } else { #if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912) - if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) { vptr = ::operator new(type->type_size, std::align_val_t(type->type_align)); - else + } else { + vptr = ::operator new(type->type_size); + } + #else + vptr = ::operator new(type->type_size); #endif - vptr = ::operator new(type->type_size); } } // type_caster_generic::load_value END @@ -182,7 +184,8 @@ public: } loaded_v_h = foreign_loader->loaded_v_h; loaded_v_h_cpptype = foreign_loader->loaded_v_h_cpptype; - implicit_casts = foreign_loader->implicit_casts; // SMART_HOLDER_WIP: should this be a copy or move? + // SMART_HOLDER_WIP: should this be a copy or move? + implicit_casts = foreign_loader->implicit_casts; return true; } return false; @@ -297,7 +300,6 @@ public: // set/reset this value in ctor/dtor, mark volatile. std::size_t local_load_safety_guard = 1887406645; // 32-bit compatible value for portability. }; -// clang-format on struct smart_holder_type_caster_class_hooks : smart_holder_type_caster_base_tag { static decltype(&modified_type_caster_generic_load_impl::local_load) @@ -595,19 +597,15 @@ struct smart_holder_type_caster : smart_holder_type_caster_load, static handle cast(T &&src, return_value_policy /*policy*/, handle parent) { // type_caster_base BEGIN - // clang-format off return cast(&src, return_value_policy::move, parent); - // clang-format on // type_caster_base END } static handle cast(T const &src, return_value_policy policy, handle parent) { // type_caster_base BEGIN - // clang-format off if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) policy = return_value_policy::copy; return cast(&src, policy, parent); - // clang-format on // type_caster_base END } @@ -630,12 +628,6 @@ struct smart_holder_type_caster : smart_holder_type_caster_load, return cast(const_cast(src), policy, parent); // Mutbl2Const } -#if defined(_MSC_VER) && _MSC_VER < 1910 - // Working around MSVC 2015 bug. const-correctness is lost. - // SMART_HOLDER_WIP: IMPROVABLE: make common code work with MSVC 2015. - template - using cast_op_type = detail::cast_op_type; -#else template using cast_op_type = conditional_t< std::is_same, T const *>::value, @@ -643,7 +635,6 @@ struct smart_holder_type_caster : smart_holder_type_caster_load, conditional_t, T *>::value, T *, conditional_t::value, T const &, T &>>>; -#endif // The const operators here prove that the existing type_caster mechanism already supports // const-correctness. However, fully implementing const-correctness inside this type_caster diff --git a/tests/test_class_sh_disowning_mi.py b/tests/test_class_sh_disowning_mi.py index 80c938f21..dcc100673 100644 --- a/tests/test_class_sh_disowning_mi.py +++ b/tests/test_class_sh_disowning_mi.py @@ -147,8 +147,7 @@ class MI8b(B3, MI6): MI6.__init__(self, i) -@pytest.mark.skipif("env.PYPY and env.PY2") -@pytest.mark.xfail("env.PYPY and not env.PY2") +@pytest.mark.xfail("env.PYPY") def test_multiple_inheritance_python(): # Based on test_multiple_inheritance.py:test_multiple_inheritance_python. # Exercises values_and_holders with 2 value_and_holder instances. @@ -203,8 +202,7 @@ DISOWN_CLS_I_J_V_LIST = [ ] -@pytest.mark.skipif("env.PYPY and env.PY2") -@pytest.mark.xfail("env.PYPY and not env.PY2", strict=False) +@pytest.mark.xfail("env.PYPY", strict=False) @pytest.mark.parametrize("cls, i, j, v", DISOWN_CLS_I_J_V_LIST) def test_disown_base1_first(cls, i, j, v): obj = cls(i, j) @@ -218,8 +216,7 @@ def test_disown_base1_first(cls, i, j, v): assert obj.v() == v -@pytest.mark.skipif("env.PYPY and env.PY2") -@pytest.mark.xfail("env.PYPY and not env.PY2", strict=False) +@pytest.mark.xfail("env.PYPY", strict=False) @pytest.mark.parametrize("cls, i, j, v", DISOWN_CLS_I_J_V_LIST) def test_disown_base2_first(cls, i, j, v): obj = cls(i, j) @@ -233,8 +230,7 @@ def test_disown_base2_first(cls, i, j, v): assert obj.v() == v -@pytest.mark.skipif("env.PYPY and env.PY2") -@pytest.mark.xfail("env.PYPY and not env.PY2", strict=False) +@pytest.mark.xfail("env.PYPY", strict=False) @pytest.mark.parametrize( "cls, j, v", [ diff --git a/tests/test_class_sh_trampoline_shared_from_this.py b/tests/test_class_sh_trampoline_shared_from_this.py index 18e341c8d..e64468e08 100644 --- a/tests/test_class_sh_trampoline_shared_from_this.py +++ b/tests/test_class_sh_trampoline_shared_from_this.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import sys import weakref import pytest @@ -213,7 +214,7 @@ def test_multiple_registered_instances_for_same_pointee_recursive(): # As of 2021-07-10 the pybind11 GitHub Actions valgrind build uses Python 3.9. -WORKAROUND_ENABLING_ROLLBACK_OF_PR3068 = env.LINUX and env.PY[:2] == (3, 9) +WORKAROUND_ENABLING_ROLLBACK_OF_PR3068 = env.LINUX and sys.version_info == (3, 9) def test_std_make_shared_factory(): diff --git a/ubench/holder_comparison.py b/ubench/holder_comparison.py index 0fb328902..10f80469c 100644 --- a/ubench/holder_comparison.py +++ b/ubench/holder_comparison.py @@ -2,25 +2,24 @@ """Simple comparison of holder performances, relative to unique_ptr holder.""" from __future__ import absolute_import, division, print_function - import collections import sys import time +from typing import Any, Callable, Dict, List -import pybind11_ubench_holder_comparison as m +import pybind11_ubench_holder_comparison as m # type: ignore number_bucket_pc = None -def pflush(*args, **kwargs): - result = print(*args, **kwargs) +def pflush(*args: Any, **kwargs: Any) -> None: + print(*args, **kwargs) # Using "file" here because it is the name of the built-in keyword argument. file = kwargs.get("file", sys.stdout) # pylint: disable=redefined-builtin file.flush() # file object must have a flush method. - return result -def run(args): +def run(args: List[str]) -> None: if not args: size_exponent_min = 0 size_exponent_max = 16 @@ -55,12 +54,12 @@ def run(args): pflush("sizeof_smart_holder:", m.sizeof_smart_holder()) def find_call_repetitions( - callable, - time_delta_floor=1.0e-6, - target_elapsed_secs_multiplier=1.05, # Empirical. - target_elapsed_secs_tolerance=0.05, - max_iterations=100, - ): + callable: Callable[[int], float], + time_delta_floor: float = 1.0e-6, + target_elapsed_secs_multiplier: float = 1.05, # Empirical. + target_elapsed_secs_tolerance: float = 0.05, + max_iterations: int = 100, + ) -> int: td_target = ( call_repetitions_target_elapsed_secs * target_elapsed_secs_multiplier ) @@ -77,7 +76,7 @@ def run(args): ): data_size = 2 ** size_exponent pflush(data_size, "data_size") - ratios = collections.defaultdict(list) + ratios: Dict[str, List[float]] = collections.defaultdict(list) call_repetitions = None for _ in range(num_samples): row_0 = None @@ -92,17 +91,17 @@ def run(args): continue if selected_holder_type != "all" and nb_label != selected_holder_type: continue - nb1 = nb_type(data_size) - nb2 = nb_type(data_size) + nb1 = nb_type(data_size) # type: ignore + nb2 = nb_type(data_size) # type: ignore - def many_sum(call_repetitions): + def many_sum(call_repetitions: int) -> float: assert int(round(nb1.sum())) == data_size t0 = time.time() for _ in range(call_repetitions): nb1.sum() return time.time() - t0 - def many_add(call_repetitions): + def many_add(call_repetitions: int) -> float: assert nb1.add(nb2) == data_size t0 = time.time() for _ in range(call_repetitions): diff --git a/ubench/holder_comparison_extract_sheet_data.py b/ubench/holder_comparison_extract_sheet_data.py index bae11b9a6..83601fee0 100644 --- a/ubench/holder_comparison_extract_sheet_data.py +++ b/ubench/holder_comparison_extract_sheet_data.py @@ -4,9 +4,10 @@ from __future__ import absolute_import, division, print_function import sys +from typing import List, Optional -def run(args): +def run(args: List[str]) -> None: assert len(args) == 1, "log_holder_comparison.txt" log_lines = open(args[0]).read().splitlines() @@ -16,9 +17,9 @@ def run(args): header = None header_row = None data_row = None - data_row_buffer = [] + data_row_buffer: List[List[str]] = [] - def show(): + def show() -> Optional[List[str]]: if header_row: if header is None: print(",".join(header_row)) @@ -39,6 +40,8 @@ def run(args): elif line.endswith(" call_repetitions"): flds = line.split() assert len(flds) == 2 + assert header_row is not None + assert data_row is not None header_row.append("calls") data_row.append(flds[0]) header_row.append("up") @@ -46,10 +49,13 @@ def run(args): elif line[2:].startswith(ratx): flds = line.split() assert len(flds) == 4 + assert header_row is not None + assert data_row is not None header_row.append(line[:2]) data_row.append(flds[2]) show() + assert header_row is not None print("Scaled to last column:") print(",".join(header_row)) for data_row in data_row_buffer: