diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 11901c099e..b9256955ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,9 +84,6 @@ jobs: - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - # TEMPORARILY pin version because 3.26.0-rc1 is failing under macOS: - with: - cmake-version: '3.25.2' - name: Cache wheels if: runner.os == 'macOS' @@ -1075,9 +1072,6 @@ jobs: - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - # TEMPORARILY pin version because 3.26.0-rc1 is failing under macOS: - with: - cmake-version: '3.25.2' - name: Run pip installs run: | diff --git a/.github/workflows/ci_sh_def.yml b/.github/workflows/ci_sh_def.yml index a799012d08..508665e24b 100644 --- a/.github/workflows/ci_sh_def.yml +++ b/.github/workflows/ci_sh_def.yml @@ -96,9 +96,6 @@ jobs: - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - # TEMPORARILY pin version because 3.26.0-rc1 is failing under macOS: - with: - cmake-version: '3.25.2' - name: Cache wheels if: runner.os == 'macOS' @@ -1101,9 +1098,6 @@ jobs: - name: Update CMake uses: jwlawson/actions-setup-cmake@v1.13 - # TEMPORARILY pin version because 3.26.0-rc1 is failing under macOS: - with: - cmake-version: '3.25.2' - name: Run pip installs run: | diff --git a/.github/workflows/ci_sh_def.yml.patch b/.github/workflows/ci_sh_def.yml.patch index d780bee9c5..655f551d73 100644 --- a/.github/workflows/ci_sh_def.yml.patch +++ b/.github/workflows/ci_sh_def.yml.patch @@ -1,5 +1,5 @@ ---- ci.yml 2023-02-07 23:54:04.279545875 -0800 -+++ ci_sh_def.yml 2023-02-07 23:54:24.677604204 -0800 +--- ci.yml 2023-02-16 15:01:55.421851299 -0800 ++++ ci_sh_def.yml 2023-02-16 15:03:24.958936294 -0800 @@ -1,4 +1,16 @@ -name: CI +# PLEASE KEEP THIS GROUP OF FILES IN SYNC AT ALL TIMES: @@ -27,7 +27,7 @@ cancel-in-progress: true env: -@@ -117,6 +129,7 @@ +@@ -114,6 +126,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=11 @@ -35,7 +35,7 @@ ${{ matrix.args }} - name: Build C++11 -@@ -146,6 +159,7 @@ +@@ -143,6 +156,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 @@ -43,7 +43,7 @@ ${{ matrix.args }} - name: Build -@@ -167,6 +181,7 @@ +@@ -164,6 +178,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 @@ -51,7 +51,7 @@ -DPYBIND11_INTERNALS_VERSION=10000000 "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp" ${{ matrix.args }} -@@ -254,6 +269,7 @@ +@@ -251,6 +266,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 @@ -59,7 +59,7 @@ - name: Build run: cmake --build build -j 2 -@@ -319,6 +335,7 @@ +@@ -316,6 +332,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} @@ -67,7 +67,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build -@@ -348,7 +365,7 @@ +@@ -345,7 +362,7 @@ run: apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y cmake git python3-dev python3-pytest python3-numpy - name: Configure @@ -76,7 +76,7 @@ - name: Build run: cmake --build build -j2 --verbose -@@ -428,7 +445,7 @@ +@@ -425,7 +442,7 @@ cmake3 -S . -B build -DDOWNLOAD_CATCH=ON \ -DCMAKE_CXX_STANDARD=11 \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \ @@ -85,7 +85,7 @@ -DPYBIND11_TEST_FILTER="test_smart_ptr.cpp" # Building before installing Pip should produce a warning but not an error -@@ -487,6 +504,7 @@ +@@ -484,6 +501,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} @@ -93,7 +93,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build -@@ -542,6 +560,7 @@ +@@ -539,6 +557,7 @@ -DDOWNLOAD_CATCH=ON \ -DDOWNLOAD_EIGEN=OFF \ -DCMAKE_CXX_STANDARD=11 \ @@ -101,7 +101,7 @@ -DCMAKE_CXX_COMPILER=$(which icpc) \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") -@@ -574,6 +593,7 @@ +@@ -571,6 +590,7 @@ -DDOWNLOAD_CATCH=ON \ -DDOWNLOAD_EIGEN=OFF \ -DCMAKE_CXX_STANDARD=17 \ @@ -109,7 +109,7 @@ -DCMAKE_CXX_COMPILER=$(which icpc) \ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") -@@ -641,6 +661,7 @@ +@@ -638,6 +658,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=11 @@ -117,7 +117,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") - name: Build -@@ -691,6 +712,7 @@ +@@ -688,6 +709,7 @@ cmake ../pybind11-tests -DDOWNLOAD_CATCH=ON -DPYBIND11_WERROR=ON @@ -125,7 +125,7 @@ -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") working-directory: /build-tests -@@ -786,6 +808,7 @@ +@@ -783,6 +805,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON @@ -133,7 +133,7 @@ ${{ matrix.args }} - name: Build C++11 run: cmake --build build -j 2 -@@ -840,6 +863,7 @@ +@@ -837,6 +860,7 @@ -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON @@ -141,7 +141,7 @@ ${{ matrix.args }} - name: Build C++11 run: cmake --build build --config Debug -j 2 -@@ -880,6 +904,7 @@ +@@ -877,6 +901,7 @@ -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=20 @@ -149,7 +149,7 @@ - name: Build C++20 run: cmake --build build -j 2 -@@ -927,7 +952,7 @@ +@@ -924,7 +949,7 @@ - name: Configure C++11 # LTO leads to many undefined reference like # `pybind11::detail::function_call::function_call(pybind11::detail::function_call&&) @@ -158,7 +158,7 @@ - name: Build C++11 run: cmake --build build -j 2 -@@ -945,7 +970,7 @@ +@@ -942,7 +967,7 @@ run: git clean -fdx - name: Configure C++14 @@ -167,7 +167,7 @@ - name: Build C++14 run: cmake --build build2 -j 2 -@@ -963,7 +988,7 @@ +@@ -960,7 +985,7 @@ run: git clean -fdx - name: Configure C++17 @@ -176,7 +176,7 @@ - name: Build C++17 run: cmake --build build3 -j 2 -@@ -1030,6 +1055,7 @@ +@@ -1027,6 +1052,7 @@ -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_STANDARD=17 @@ -184,7 +184,7 @@ - name: Build run: cmake --build . -j 2 -@@ -1098,6 +1124,7 @@ +@@ -1092,6 +1118,7 @@ -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_STANDARD=17 diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml new file mode 100644 index 0000000000..73c89bb4d8 --- /dev/null +++ b/.github/workflows/pip.yml @@ -0,0 +1,111 @@ +name: Pip + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + - stable + - smart_holder + - v* + release: + types: + - published + +env: + PIP_ONLY_BINARY: numpy + +jobs: + # This builds the sdists and wheels and makes sure the files are exactly as + # expected. Using Windows and Python 3.6, since that is often the most + # challenging matrix element. + test-packaging: + name: 🐍 3.6 • 📦 tests • windows-latest + runs-on: windows-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup 🐍 3.6 + uses: actions/setup-python@v4 + with: + python-version: 3.6 + + - name: Prepare env + run: | + python -m pip install -r tests/requirements.txt + + - name: Python Packaging tests + run: pytest tests/extra_python_package/ + + + # This runs the packaging tests and also builds and saves the packages as + # artifacts. + packaging: + name: 🐍 3.8 • 📦 & 📦 tests • ubuntu-latest + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup 🐍 3.8 + uses: actions/setup-python@v4 + with: + python-version: 3.8 + + - name: Prepare env + run: | + python -m pip install -r tests/requirements.txt build twine + + - name: Python Packaging tests + run: pytest tests/extra_python_package/ + + - name: Build SDist and wheels + run: | + python -m build + PYBIND11_GLOBAL_SDIST=1 python -m build + + - name: Check metadata + run: twine check dist/* + + - name: Save standard package + uses: actions/upload-artifact@v3 + with: + name: standard + path: dist/pybind11-* + + - name: Save global package + uses: actions/upload-artifact@v3 + with: + name: global + path: dist/pybind11_global-* + + + + # When a GitHub release is made, upload the artifacts to PyPI + upload: + name: Upload to PyPI + runs-on: ubuntu-latest + if: github.event_name == 'release' && github.event.action == 'published' + needs: [packaging] + + steps: + - uses: actions/setup-python@v4 + with: + python-version: "3.x" + + # Downloads all to directories matching the artifact names + - uses: actions/download-artifact@v3 + + - name: Publish standard package + uses: pypa/gh-action-pypi-publish@v1.6.4 + with: + password: ${{ secrets.pypi_password }} + packages_dir: standard/ + + - name: Publish global package + uses: pypa/gh-action-pypi-publish@v1.6.4 + with: + password: ${{ secrets.pypi_password_global }} + packages_dir: global/ diff --git a/MANIFEST.in b/MANIFEST.in index 6a45f31203..6c24185a99 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,4 @@ +prune tests prune ubench include README_smart_holder.rst recursive-include pybind11/include/pybind11 *.h diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 09e70b5c10..e8139da20e 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1059,11 +1059,14 @@ make_caster_for_intrinsic &load_type(make_caster_for_intrinsic &conv, cons "Internal error: type_caster should only be used for C++ types"); if (!conv.load(handle, true)) { #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) - throw cast_error("Unable to cast Python instance to C++ type (#define " - "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); + throw cast_error( + "Unable to cast Python instance of type " + + str(type::handle_of(handle)).cast() + + " to C++ type '?' (#define " + "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); #else throw cast_error("Unable to cast Python instance of type " - + (std::string) str(type::handle_of(handle)) + " to C++ type '" + + str(type::handle_of(handle)).cast() + " to C++ type '" + type_id() + "'"); #endif } @@ -1127,12 +1130,13 @@ detail::enable_if_t::value, T> move(object &&obj) { if (obj.ref_count() > 1) { #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) throw cast_error( - "Unable to cast Python instance to C++ rvalue: instance has multiple references" - " (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); + "Unable to cast Python " + str(type::handle_of(obj)).cast() + + " instance to C++ rvalue: instance has multiple references" + " (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); #else - throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj)) - + " instance to C++ " + type_id() - + " instance: instance has multiple references"); + throw cast_error("Unable to move from Python " + + str(type::handle_of(obj)).cast() + " instance to C++ " + + type_id() + " instance: instance has multiple references"); #endif } @@ -1237,9 +1241,10 @@ PYBIND11_NAMESPACE_END(detail) // The overloads could coexist, i.e. the #if is not strictly speaking needed, // but it is an easy minor optimization. #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) -inline cast_error cast_error_unable_to_convert_call_arg() { - return cast_error("Unable to convert call argument to Python object (#define " - "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); +inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name) { + return cast_error("Unable to convert call argument '" + name + + "' to Python object (#define " + "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"); } #else inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name, @@ -1262,7 +1267,7 @@ tuple make_tuple(Args &&...args_) { for (size_t i = 0; i < args.size(); i++) { if (!args[i]) { #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) - throw cast_error_unable_to_convert_call_arg(); + throw cast_error_unable_to_convert_call_arg(std::to_string(i)); #else std::array argtypes{{type_id()...}}; throw cast_error_unable_to_convert_call_arg(std::to_string(i), argtypes[i]); @@ -1552,7 +1557,7 @@ class unpacking_collector { detail::make_caster::cast(std::forward(x), policy, {})); if (!o) { #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) - throw cast_error_unable_to_convert_call_arg(); + throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size())); #else throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()), type_id()); @@ -1584,7 +1589,7 @@ class unpacking_collector { } if (!a.value) { #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) - throw cast_error_unable_to_convert_call_arg(); + throw cast_error_unable_to_convert_call_arg(a.name); #else throw cast_error_unable_to_convert_call_arg(a.name, a.type); #endif diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 567d876999..ac06a76e31 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -1249,8 +1249,9 @@ constexpr #endif // Pybind offers detailed error messages by default for all builts that are debug (through the -// negation of ndebug). This can also be manually enabled by users, for any builds, through -// defining PYBIND11_DETAILED_ERROR_MESSAGES. +// negation of NDEBUG). This can also be manually enabled by users, for any builds, through +// defining PYBIND11_DETAILED_ERROR_MESSAGES. This information is primarily useful for those +// who are writing (as opposed to merely using) libraries that use pybind11. #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) && !defined(NDEBUG) # define PYBIND11_DETAILED_ERROR_MESSAGES #endif diff --git a/pybind11/setup_helpers.py b/pybind11/setup_helpers.py index 1db4795327..4c14498f6f 100644 --- a/pybind11/setup_helpers.py +++ b/pybind11/setup_helpers.py @@ -174,7 +174,9 @@ def cxx_std(self) -> int: @cxx_std.setter def cxx_std(self, level: int) -> None: if self._cxx_level: - warnings.warn("You cannot safely change the cxx_level after setting it!") + warnings.warn( + "You cannot safely change the cxx_level after setting it!", stacklevel=1 + ) # MSVC 2015 Update 3 and later only have 14 (and later 17) modes, so # force a valid flag here. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 562c49e9c0..3a1ce8949d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -191,7 +191,7 @@ if(PYBIND11_TEST_OVERRIDE) # This allows the override to be done with extensions, preserving backwards compatibility. foreach(test_name ${TEST_FILES_NO_EXT}) if(NOT ${test_name} IN_LIST TEST_OVERRIDE_NO_EXT - )# If not in the whitelist, add to be filtered out. + )# If not in the allowlist, add to be filtered out. list(APPEND PYBIND11_TEST_FILTER ${test_name}) endif() endforeach() diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index 57b6599880..4a652f53e8 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -5,6 +5,7 @@ import env # noqa: F401 from pybind11_tests import callbacks as m +from pybind11_tests import detailed_error_messages_enabled def test_callbacks(): @@ -70,11 +71,20 @@ def f(*args, **kwargs): with pytest.raises(RuntimeError) as excinfo: m.test_arg_conversion_error1(f) - assert "Unable to convert call argument" in str(excinfo.value) + assert str(excinfo.value) == "Unable to convert call argument " + ( + "'1' of type 'UnregisteredType' to Python object" + if detailed_error_messages_enabled + else "'1' to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)" + ) with pytest.raises(RuntimeError) as excinfo: m.test_arg_conversion_error2(f) - assert "Unable to convert call argument" in str(excinfo.value) + assert str(excinfo.value) == "Unable to convert call argument " + ( + "'expected_name' of type 'UnregisteredType' to Python object" + if detailed_error_messages_enabled + else "'expected_name' to Python object " + "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)" + ) def test_lambda_closure_cleanup(): diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp index f57e095068..854c7e6f76 100644 --- a/tests/test_exceptions.cpp +++ b/tests/test_exceptions.cpp @@ -339,4 +339,9 @@ TEST_SUBMODULE(exceptions, m) { } return py::str("UNEXPECTED"); }); + + m.def("test_fn_cast_int", [](const py::function &fn) { + // function returns None instead of int, should give a useful error message + fn().cast(); + }); } diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 0d2c808143..8bcefe3de6 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -381,3 +381,12 @@ def test_pypy_oserror_normalization(): # https://github.com/pybind/pybind11/issues/4075 what = m.test_pypy_oserror_normalization() assert "this_filename_must_not_exist" in what + + +def test_fn_cast_int_exception(): + with pytest.raises(RuntimeError) as excinfo: + m.test_fn_cast_int(lambda: None) + + assert str(excinfo.value).startswith( + "Unable to cast Python instance of type to C++ type" + ) diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 8f9f2987e9..a1a80a2933 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -536,7 +536,7 @@ def test_print(capture): assert str(excinfo.value) == "Unable to convert call argument " + ( "'1' of type 'UnregisteredType' to Python object" if detailed_error_messages_enabled - else "to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)" + else "'1' to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)" ) diff --git a/tools/FindCatch.cmake b/tools/FindCatch.cmake index 57bba58b30..5d3fcbfb13 100644 --- a/tools/FindCatch.cmake +++ b/tools/FindCatch.cmake @@ -36,10 +36,14 @@ endfunction() function(_download_catch version destination_dir) message(STATUS "Downloading catch v${version}...") set(url https://github.com/philsquared/Catch/releases/download/v${version}/catch.hpp) - file(DOWNLOAD ${url} "${destination_dir}/catch.hpp" STATUS status) + file( + DOWNLOAD ${url} "${destination_dir}/catch.hpp" + STATUS status + LOG log) list(GET status 0 error) if(error) - message(FATAL_ERROR "Could not download ${url}") + string(REPLACE "\n" "\n " log " ${log}") + message(FATAL_ERROR "Could not download URL:\n" " ${url}\n" "Log:\n" "${log}") endif() set(CATCH_INCLUDE_DIR "${destination_dir}"