diff --git a/pybind11/.clang-format b/pybind11/.clang-format index 8e0fd8b..b477a16 100644 --- a/pybind11/.clang-format +++ b/pybind11/.clang-format @@ -3,17 +3,36 @@ # clang-format --style=llvm --dump-config BasedOnStyle: LLVM AccessModifierOffset: -4 +AllowShortLambdasOnASingleLine: true AlwaysBreakTemplateDeclarations: Yes BinPackArguments: false BinPackParameters: false BreakBeforeBinaryOperators: All BreakConstructorInitializers: BeforeColon ColumnLimit: 99 +CommentPragmas: 'NOLINT:.*|^ IWYU pragma:' +IncludeBlocks: Regroup IndentCaseLabels: true IndentPPDirectives: AfterHash IndentWidth: 4 Language: Cpp SpaceAfterCStyleCast: true Standard: Cpp11 +StatementMacros: ['PyObject_HEAD'] TabWidth: 4 +IncludeCategories: + - Regex: '' + Priority: 4 + - Regex: '.*' + Priority: 5 ... diff --git a/pybind11/.clang-tidy b/pybind11/.clang-tidy index dbe85a8..d01ca35 100644 --- a/pybind11/.clang-tidy +++ b/pybind11/.clang-tidy @@ -2,9 +2,12 @@ FormatStyle: file Checks: ' *bugprone*, +clang-analyzer-optin.performance.Padding, +clang-analyzer-optin.cplusplus.VirtualCall, cppcoreguidelines-init-variables, +cppcoreguidelines-prefer-member-initializer, +cppcoreguidelines-pro-type-static-cast-downcast, cppcoreguidelines-slicing, -clang-analyzer-optin.cplusplus.VirtualCall, google-explicit-constructor, llvm-namespace-comment, misc-misplaced-const, @@ -31,14 +34,17 @@ modernize-use-override, modernize-use-using, *performance*, readability-avoid-const-params-in-decls, +readability-braces-around-statements, readability-const-return-type, readability-container-size-empty, readability-delete-null-pointer, readability-else-after-return, readability-implicit-bool-conversion, +readability-inconsistent-declaration-parameter-name, readability-make-member-function-const, readability-misplaced-array-index, readability-non-const-parameter, +readability-qualified-auto, readability-redundant-function-ptr-dereference, readability-redundant-smartptr-get, readability-redundant-string-cstr, @@ -46,6 +52,7 @@ readability-simplify-subscript-expr, readability-static-accessed-through-instance, readability-static-definition-in-anonymous-namespace, readability-string-compare, +readability-suspicious-call-argument, readability-uniqueptr-delete-release, -bugprone-exception-escape, -bugprone-reserved-identifier, diff --git a/pybind11/.github/CONTRIBUTING.md b/pybind11/.github/CONTRIBUTING.md index 39c32b2..e8294c8 100644 --- a/pybind11/.github/CONTRIBUTING.md +++ b/pybind11/.github/CONTRIBUTING.md @@ -120,7 +120,7 @@ The valid options are: * `-DPYBIND11_NOPYTHON=ON`: Disable all Python searching (disables tests) * `-DBUILD_TESTING=ON`: Enable the tests * `-DDOWNLOAD_CATCH=ON`: Download catch to build the C++ tests -* `-DOWNLOAD_EIGEN=ON`: Download Eigen for the NumPy tests +* `-DDOWNLOAD_EIGEN=ON`: Download Eigen for the NumPy tests * `-DPYBIND11_INSTALL=ON/OFF`: Enable the install target (on by default for the master project) * `-DUSE_PYTHON_INSTALL_DIR=ON`: Try to install into the python dir @@ -159,8 +159,9 @@ tests with these targets: * `test_cmake_build`: Install / subdirectory tests If you want to build just a subset of tests, use -`-DPYBIND11_TEST_OVERRIDE="test_callbacks.cpp;test_pickling.cpp"`. If this is -empty, all tests will be built. +`-DPYBIND11_TEST_OVERRIDE="test_callbacks;test_pickling"`. If this is +empty, all tests will be built. Tests are specified without an extension if they need both a .py and +.cpp file. You may also pass flags to the `pytest` target by editing `tests/pytest.ini` or by using the `PYTEST_ADDOPTS` environment variable diff --git a/pybind11/.github/workflows/ci.yml b/pybind11/.github/workflows/ci.yml index 6843a92..c244a5e 100644 --- a/pybind11/.github/workflows/ci.yml +++ b/pybind11/.github/workflows/ci.yml @@ -9,6 +9,13 @@ on: - stable - v* +concurrency: + group: test-${{ github.ref }} + cancel-in-progress: true + +env: + PIP_ONLY_BINARY: numpy + jobs: # This is the "main" test suite, which tests a large number of different # versions of default compilers and Python versions in GitHub Actions. @@ -16,44 +23,39 @@ jobs: strategy: fail-fast: false matrix: - runs-on: [ubuntu-latest, windows-latest, macos-latest] + runs-on: [ubuntu-latest, windows-2022, macos-latest] python: - - 2.7 - - 3.5 - - 3.6 - - 3.9 - - 3.10-dev - - pypy2 - - pypy3 + - '2.7' + - '3.5' + - '3.6' + - '3.9' + - '3.10' + - 'pypy-3.7' + - 'pypy-3.8' # Items in here will either be added to the build matrix (if not # present), or add new keys to an existing matrix element if all the # existing keys match. # - # We support three optional keys: args (both build), args1 (first - # build), and args2 (second build). + # We support an optional key: args, for cmake args include: # Just add a key - runs-on: ubuntu-latest - python: 3.6 + python: '3.6' args: > -DPYBIND11_FINDPYTHON=ON + -DCMAKE_CXX_FLAGS="-D_=1" - runs-on: windows-latest - python: 3.6 + python: '3.6' args: > -DPYBIND11_FINDPYTHON=ON - - # These items will be removed from the build matrix, keys must match. - exclude: - # Currently 32bit only, and we build 64bit - - runs-on: windows-latest - python: pypy2 - - runs-on: windows-latest - python: pypy3 - - # TODO: PyPy2 7.3.3 segfaults, while 7.3.2 was fine. - - runs-on: ubuntu-latest - python: pypy2 + - runs-on: macos-latest + python: 'pypy-2.7' + # Inject a couple Windows 2019 runs + - runs-on: windows-2019 + python: '3.9' + - runs-on: windows-2019 + python: '2.7' name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • x64 ${{ matrix.args }}" runs-on: ${{ matrix.runs-on }} @@ -67,7 +69,8 @@ jobs: python-version: ${{ matrix.python }} - name: Setup Boost (Linux) - if: runner.os == 'Linux' + # Can't use boost + define _ + if: runner.os == 'Linux' && matrix.python != '3.6' run: sudo apt-get install libboost-dev - name: Setup Boost (macOS) @@ -75,7 +78,7 @@ jobs: run: brew install boost - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.11 + uses: jwlawson/actions-setup-cmake@v1.12 - name: Cache wheels if: runner.os == 'macOS' @@ -89,7 +92,8 @@ jobs: key: ${{ runner.os }}-pip-${{ matrix.python }}-x64-${{ hashFiles('tests/requirements.txt') }} - name: Prepare env - run: python -m pip install -r tests/requirements.txt --prefer-binary + run: | + python -m pip install -r tests/requirements.txt - name: Setup annotations on Linux if: runner.os == 'Linux' @@ -113,7 +117,7 @@ jobs: - name: C++11 tests # TODO: Figure out how to load the DLL on Python 3.8+ - if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10-dev'))" + if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10' || matrix.python == '3.11-dev' || matrix.python == 'pypy-3.8'))" run: cmake --build . --target cpptest -j 2 - name: Interface test C++11 @@ -123,7 +127,7 @@ jobs: run: git clean -fdx # Second build - C++17 mode and in a build directory - - name: Configure ${{ matrix.args2 }} + - name: Configure C++17 run: > cmake -S . -B build2 -DPYBIND11_WERROR=ON @@ -131,7 +135,6 @@ jobs: -DDOWNLOAD_EIGEN=ON -DCMAKE_CXX_STANDARD=17 ${{ matrix.args }} - ${{ matrix.args2 }} - name: Build run: cmake --build build2 -j 2 @@ -141,7 +144,7 @@ jobs: - name: C++ tests # TODO: Figure out how to load the DLL on Python 3.8+ - if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10-dev'))" + if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10' || matrix.python == '3.11-dev' || matrix.python == 'pypy-3.8'))" run: cmake --build build2 --target cpptest # Third build - C++17 mode with unstable ABI @@ -169,7 +172,7 @@ jobs: # MSVC, but for now, this action works: - name: Prepare compiler environment for Windows 🐍 2.7 if: matrix.python == 2.7 && runner.os == 'Windows' - uses: ilammy/msvc-dev-cmd@v1.9.0 + uses: ilammy/msvc-dev-cmd@v1.10.0 with: arch: x64 @@ -185,6 +188,7 @@ jobs: # setuptools - name: Setuptools helpers test run: pytest tests/extra_setuptools + if: "!(matrix.python == '3.5' && matrix.runs-on == 'windows-2022')" deadsnakes: @@ -192,11 +196,12 @@ jobs: fail-fast: false matrix: include: - - python-version: 3.9 + # TODO: Fails on 3.10, investigate + - python-version: "3.9" python-debug: true valgrind: true - - python-version: 3.10-dev - python-debug: false + # - python-version: "3.11-dev" + # python-debug: false name: "🐍 ${{ matrix.python-version }}${{ matrix.python-debug && '-dbg' || '' }} (deadsnakes)${{ matrix.valgrind && ' • Valgrind' || '' }} • x64" runs-on: ubuntu-latest @@ -211,7 +216,7 @@ jobs: debug: ${{ matrix.python-debug }} - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.11 + uses: jwlawson/actions-setup-cmake@v1.12 - name: Valgrind cache if: matrix.valgrind @@ -240,9 +245,12 @@ jobs: sudo apt-get install libc6-dbg # Needed by Valgrind - name: Prepare env - run: python -m pip install -r tests/requirements.txt --prefer-binary + run: | + python -m pip install -r tests/requirements.txt - name: Configure + env: + SETUPTOOLS_USE_DISTUTILS: stdlib run: > cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug @@ -463,7 +471,7 @@ jobs: run: python3 -m pip install --upgrade pip - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.11 + uses: jwlawson/actions-setup-cmake@v1.12 - name: Configure shell: bash @@ -517,7 +525,7 @@ jobs: - name: Install dependencies run: | set +e; source /opt/intel/oneapi/setvars.sh; set -e - python3 -m pip install -r tests/requirements.txt --prefer-binary + python3 -m pip install -r tests/requirements.txt - name: Configure C++11 run: | @@ -592,11 +600,11 @@ jobs: fail-fast: false matrix: centos: - - 7 # GCC 4.8 - - 8 + - centos7 # GCC 4.8 + - stream8 name: "🐍 3 • CentOS ${{ matrix.centos }} • x64" - container: "centos:${{ matrix.centos }}" + container: "quay.io/centos/centos:${{ matrix.centos }}" steps: - uses: actions/checkout@v2 @@ -608,24 +616,14 @@ jobs: run: python3 -m pip install --upgrade pip - name: Install dependencies - run: python3 -m pip install cmake -r tests/requirements.txt --prefer-binary - - - name: VAR_BUILD_TYPE 7 - if: matrix.centos == 7 - run: echo MinSizeRel > VAR_BUILD_TYPE - - # Using Release to avoid segfault that appeared around 2021-06-04, - # apparently when the gcc version changed from 8.3 to 8.4. - - name: VAR_BUILD_TYPE 8 - if: matrix.centos == 8 - run: echo Release > VAR_BUILD_TYPE + run: | + python3 -m pip install cmake -r tests/requirements.txt - # Temporally disabling EIGEN due to SSL issue in CentOS 7 - name: Configure shell: bash run: > cmake -S . -B build - -DCMAKE_BUILD_TYPE=$(cat VAR_BUILD_TYPE) + -DCMAKE_BUILD_TYPE=MinSizeRel -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -DDOWNLOAD_EIGEN=ON @@ -702,14 +700,11 @@ jobs: - name: Install Doxygen run: sudo apt-get install -y doxygen librsvg2-bin # Changed to rsvg-convert in 20.04 - - name: Install docs & setup requirements - run: python3 -m pip install -r docs/requirements.txt - - name: Build docs - run: python3 -m sphinx -W -b html docs docs/.build + run: pipx run nox -s docs - name: Make SDist - run: python3 setup.py sdist + run: pipx run nox -s build -- --sdist - run: git status --ignored @@ -721,7 +716,7 @@ jobs: - name: Compare Dists (headers only) working-directory: include run: | - python3 -m pip install --user -U ../dist/* + python3 -m pip install --user -U ../dist/*.tar.gz installed=$(python3 -c "import pybind11; print(pybind11.get_include() + '/pybind11')") diff -rq $installed ./pybind11 @@ -735,8 +730,7 @@ jobs: - 3.7 - 3.8 - 3.9 - - pypy3 - # TODO: fix hang on pypy2 + - pypy-3.6 include: - python: 3.9 @@ -757,15 +751,16 @@ jobs: architecture: x86 - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.11 + uses: jwlawson/actions-setup-cmake@v1.12 - name: Prepare MSVC - uses: ilammy/msvc-dev-cmd@v1.9.0 + uses: ilammy/msvc-dev-cmd@v1.10.0 with: arch: x86 - name: Prepare env - run: python -m pip install -r tests/requirements.txt --prefer-binary + run: | + python -m pip install -r tests/requirements.txt # First build - C++11 mode and inplace - name: Configure ${{ matrix.args }} @@ -803,15 +798,16 @@ jobs: python-version: ${{ matrix.python }} - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.11 + uses: jwlawson/actions-setup-cmake@v1.12 - name: Prepare MSVC - uses: ilammy/msvc-dev-cmd@v1.9.0 + uses: ilammy/msvc-dev-cmd@v1.10.0 with: toolset: 14.0 - name: Prepare env - run: python -m pip install -r tests/requirements.txt --prefer-binary + run: | + python -m pip install -r tests/requirements.txt # First build - C++11 mode and inplace - name: Configure @@ -847,6 +843,10 @@ jobs: std: 17 args: > -DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR" + - python: 3.7 + std: 17 + args: > + -DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR" steps: - uses: actions/checkout@v2 @@ -857,10 +857,11 @@ jobs: python-version: ${{ matrix.python }} - name: Update CMake - uses: jwlawson/actions-setup-cmake@v1.11 + uses: jwlawson/actions-setup-cmake@v1.12 - name: Prepare env - run: python -m pip install -r tests/requirements.txt --prefer-binary + run: | + python -m pip install -r tests/requirements.txt # First build - C++11 mode and inplace - name: Configure @@ -913,7 +914,7 @@ jobs: - name: Configure C++11 # LTO leads to many undefined reference like # `pybind11::detail::function_call::function_call(pybind11::detail::function_call&&) - run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=11 -S . -B build + run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=11 -DDOWNLOAD_CATCH=ON -S . -B build - name: Build C++11 run: cmake --build build -j 2 @@ -922,16 +923,16 @@ jobs: run: cmake --build build --target pytest -j 2 - name: C++11 tests - run: cmake --build build --target cpptest -j 2 + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target cpptest -j 2 - name: Interface test C++11 - run: cmake --build build --target test_cmake_build + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build --target test_cmake_build - name: Clean directory run: git clean -fdx - name: Configure C++14 - run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -S . -B build2 + run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -DDOWNLOAD_CATCH=ON -S . -B build2 - name: Build C++14 run: cmake --build build2 -j 2 @@ -940,16 +941,16 @@ jobs: run: cmake --build build2 --target pytest -j 2 - name: C++14 tests - run: cmake --build build2 --target cpptest -j 2 + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target cpptest -j 2 - name: Interface test C++14 - run: cmake --build build2 --target test_cmake_build + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build2 --target test_cmake_build - name: Clean directory run: git clean -fdx - name: Configure C++17 - run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -S . -B build3 + run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DDOWNLOAD_CATCH=ON -S . -B build3 - name: Build C++17 run: cmake --build build3 -j 2 @@ -958,7 +959,7 @@ jobs: run: cmake --build build3 --target pytest -j 2 - name: C++17 tests - run: cmake --build build3 --target cpptest -j 2 + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target cpptest -j 2 - name: Interface test C++17 - run: cmake --build build3 --target test_cmake_build + run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target test_cmake_build diff --git a/pybind11/.github/workflows/configure.yml b/pybind11/.github/workflows/configure.yml index d60025e..66ab0e3 100644 --- a/pybind11/.github/workflows/configure.yml +++ b/pybind11/.github/workflows/configure.yml @@ -55,7 +55,7 @@ jobs: # An action for adding a specific version of CMake: # https://github.com/jwlawson/actions-setup-cmake - name: Setup CMake ${{ matrix.cmake }} - uses: jwlawson/actions-setup-cmake@v1.11 + uses: jwlawson/actions-setup-cmake@v1.12 with: cmake-version: ${{ matrix.cmake }} diff --git a/pybind11/.github/workflows/pip.yml b/pybind11/.github/workflows/pip.yml index 5547a5e..f74b79f 100644 --- a/pybind11/.github/workflows/pip.yml +++ b/pybind11/.github/workflows/pip.yml @@ -12,6 +12,9 @@ on: 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 2.7, since that is often the most @@ -29,7 +32,8 @@ jobs: python-version: 2.7 - name: Prepare env - run: python -m pip install -r tests/requirements.txt --prefer-binary + run: | + python -m pip install -r tests/requirements.txt - name: Python Packaging tests run: pytest tests/extra_python_package/ @@ -50,7 +54,8 @@ jobs: python-version: 3.8 - name: Prepare env - run: python -m pip install -r tests/requirements.txt build twine --prefer-binary + run: | + python -m pip install -r tests/requirements.txt build twine - name: Python Packaging tests run: pytest tests/extra_python_package/ @@ -91,13 +96,13 @@ jobs: - uses: actions/download-artifact@v2 - name: Publish standard package - uses: pypa/gh-action-pypi-publish@v1.4.2 + uses: pypa/gh-action-pypi-publish@v1.5.0 with: password: ${{ secrets.pypi_password }} packages_dir: standard/ - name: Publish global package - uses: pypa/gh-action-pypi-publish@v1.4.2 + uses: pypa/gh-action-pypi-publish@v1.5.0 with: password: ${{ secrets.pypi_password_global }} packages_dir: global/ diff --git a/pybind11/.github/workflows/upstream.yml b/pybind11/.github/workflows/upstream.yml new file mode 100644 index 0000000..138c9ad --- /dev/null +++ b/pybind11/.github/workflows/upstream.yml @@ -0,0 +1,112 @@ + +name: Upstream + +on: + workflow_dispatch: + pull_request: + +concurrency: + group: upstream-${{ github.ref }} + cancel-in-progress: true + +env: + PIP_ONLY_BINARY: numpy + +jobs: + standard: + name: "🐍 3.11 dev • ubuntu-latest • x64" + runs-on: ubuntu-latest + if: "contains(github.event.pull_request.labels.*.name, 'python dev')" + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python 3.11 + uses: actions/setup-python@v2 + with: + python-version: "3.11-dev" + + - name: Setup Boost (Linux) + if: runner.os == 'Linux' + run: sudo apt-get install libboost-dev + + - name: Update CMake + uses: jwlawson/actions-setup-cmake@v1.12 + + - name: Prepare env + run: | + python -m pip install -r tests/requirements.txt + + - name: Setup annotations on Linux + if: runner.os == 'Linux' + run: python -m pip install pytest-github-actions-annotate-failures + + # First build - C++11 mode and inplace + - name: Configure C++11 + run: > + cmake -S . -B . + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DDOWNLOAD_EIGEN=ON + -DCMAKE_CXX_STANDARD=11 + + - name: Build C++11 + run: cmake --build . -j 2 + + - name: Python tests C++11 + run: cmake --build . --target pytest -j 2 + + - name: C++11 tests + run: cmake --build . --target cpptest -j 2 + + - name: Interface test C++11 + run: cmake --build . --target test_cmake_build + + - name: Clean directory + run: git clean -fdx + + # Second build - C++17 mode and in a build directory + - name: Configure C++17 + run: > + cmake -S . -B build2 + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DDOWNLOAD_EIGEN=ON + -DCMAKE_CXX_STANDARD=17 + ${{ matrix.args }} + ${{ matrix.args2 }} + + - name: Build + run: cmake --build build2 -j 2 + + - name: Python tests + run: cmake --build build2 --target pytest + + - name: C++ tests + run: cmake --build build2 --target cpptest + + # Third build - C++17 mode with unstable ABI + - name: Configure (unstable ABI) + run: > + cmake -S . -B build3 + -DPYBIND11_WERROR=ON + -DDOWNLOAD_CATCH=ON + -DDOWNLOAD_EIGEN=ON + -DCMAKE_CXX_STANDARD=17 + -DPYBIND11_INTERNALS_VERSION=10000000 + "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp" + ${{ matrix.args }} + + - name: Build (unstable ABI) + run: cmake --build build3 -j 2 + + - name: Python tests (unstable ABI) + run: cmake --build build3 --target pytest + + - name: Interface test + run: cmake --build build2 --target test_cmake_build + + # This makes sure the setup_helpers module can build packages using + # setuptools + - name: Setuptools helpers test + run: pytest tests/extra_setuptools diff --git a/pybind11/.pre-commit-config.yaml b/pybind11/.pre-commit-config.yaml index 2df3146..c31cab7 100644 --- a/pybind11/.pre-commit-config.yaml +++ b/pybind11/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: # Standard hooks - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.1.0 hooks: - id: check-added-large-files - id: check-case-conflict @@ -33,27 +33,27 @@ repos: exclude: ^noxfile.py$ - repo: https://github.com/asottile/pyupgrade - rev: v2.29.0 + rev: v2.31.0 hooks: - id: pyupgrade - repo: https://github.com/PyCQA/isort - rev: 5.9.3 + rev: 5.10.1 hooks: - id: isort # Black, the code formatter, natively supports pre-commit - repo: https://github.com/psf/black - rev: 21.9b0 # Keep in sync with blacken-docs + rev: 21.12b0 # Keep in sync with blacken-docs hooks: - id: black - repo: https://github.com/asottile/blacken-docs - rev: v1.11.0 + rev: v1.12.0 hooks: - id: blacken-docs additional_dependencies: - - black==21.9b0 # keep in sync with black hook + - black==21.12b0 # keep in sync with black hook # Changes tabs to spaces - repo: https://github.com/Lucas-C/pre-commit-hooks @@ -63,18 +63,36 @@ repos: # Autoremoves unused imports - repo: https://github.com/hadialqattan/pycln - rev: v1.0.3 + rev: v1.1.0 hooks: - id: pycln +- repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.9.0 + hooks: + - id: python-check-blanket-noqa + - id: python-check-blanket-type-ignore + - id: python-no-log-warn + - id: rst-backticks + - id: rst-directive-colons + - id: rst-inline-touching-normal + # Flake8 also supports pre-commit natively (same author) - repo: https://github.com/PyCQA/flake8 - rev: 3.9.2 + rev: 4.0.1 hooks: - id: flake8 - additional_dependencies: [flake8-bugbear, pep8-naming] + additional_dependencies: &flake8_dependencies + - flake8-bugbear + - pep8-naming exclude: ^(docs/.*|tools/.*)$ +- repo: https://github.com/asottile/yesqa + rev: v1.3.0 + hooks: + - id: yesqa + additional_dependencies: *flake8_dependencies + # CMake formatting - repo: https://github.com/cheshirekow/cmake-format-precommit rev: v0.6.13 @@ -86,12 +104,9 @@ repos: # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.910 + rev: v0.931 hooks: - id: mypy - # The default Python type ignores .pyi files, so let's rerun if detected - types: [text] - files: ^pybind11.*\.pyi?$ # Running per-file misbehaves a bit, so just run on all files, it's fast pass_filenames: false additional_dependencies: [typed_ast] @@ -113,7 +128,7 @@ repos: args: ["-L", "nd,ot,thist"] - repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.7.2.1 + rev: v0.8.0.3 hooks: - id: shellcheck @@ -126,11 +141,7 @@ repos: entry: PyBind|Numpy|Cmake|CCache|PyTest exclude: .pre-commit-config.yaml -- repo: local +- repo: https://github.com/pre-commit/mirrors-clang-format + rev: "v13.0.0" hooks: - - id: check-style - name: Classic check-style - language: system - types: - - c++ - entry: ./tools/check-style.sh + - id: clang-format diff --git a/pybind11/CMakeLists.txt b/pybind11/CMakeLists.txt index 25cfcec..3787982 100644 --- a/pybind11/CMakeLists.txt +++ b/pybind11/CMakeLists.txt @@ -7,13 +7,18 @@ cmake_minimum_required(VERSION 3.4) -# The `cmake_minimum_required(VERSION 3.4...3.21)` syntax does not work with +# The `cmake_minimum_required(VERSION 3.4...3.22)` syntax does not work with # some versions of VS that have a patched CMake 3.11. This forces us to emulate # the behavior using the following workaround: -if(${CMAKE_VERSION} VERSION_LESS 3.21) +if(${CMAKE_VERSION} VERSION_LESS 3.22) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() - cmake_policy(VERSION 3.21) + cmake_policy(VERSION 3.22) +endif() + +# Avoid infinite recursion if tests include this as a subdirectory +if(DEFINED PYBIND11_MASTER_PROJECT) + return() endif() # Extract project version from source @@ -45,13 +50,8 @@ if(NOT pybind11_FIND_QUIETLY) message(STATUS "pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}") endif() -# Avoid infinite recursion if tests include this as a subdirectory -if(DEFINED PYBIND11_MASTER_PROJECT) - set(PYBIND11_TEST OFF) -endif() - # Check if pybind11 is being used directly or via add_subdirectory -if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR AND NOT DEFINED PYBIND11_MASTER_PROJECT) +if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) ### Warn if not an out-of-source builds if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) set(lines @@ -80,6 +80,8 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR AND NOT DEFINED PYBIND11_MASTER_ endif() set(pybind11_system "") + + set_property(GLOBAL PROPERTY USE_FOLDERS ON) else() set(PYBIND11_MASTER_PROJECT OFF) set(pybind11_system SYSTEM) diff --git a/pybind11/README.rst b/pybind11/README.rst index 7ce57b0..45c4af5 100644 --- a/pybind11/README.rst +++ b/pybind11/README.rst @@ -106,7 +106,7 @@ goodies: - Binaries are generally smaller by a factor of at least 2 compared to equivalent bindings generated by Boost.Python. A recent pybind11 conversion of PyRosetta, an enormous Boost.Python binding project, - `reported `_ + `reported `_ a binary size reduction of **5.4x** and compile time reduction by **5.8x**. diff --git a/pybind11/docs/Doxyfile b/pybind11/docs/Doxyfile index c856295..62c2675 100644 --- a/pybind11/docs/Doxyfile +++ b/pybind11/docs/Doxyfile @@ -18,6 +18,5 @@ ALIASES += "endrst=\endverbatim" QUIET = YES WARNINGS = YES WARN_IF_UNDOCUMENTED = NO -PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS \ - PY_MAJOR_VERSION=3 \ +PREDEFINED = PY_MAJOR_VERSION=3 \ PYBIND11_NOINLINE diff --git a/pybind11/docs/advanced/cast/custom.rst b/pybind11/docs/advanced/cast/custom.rst index 19b9353..1df4d3e 100644 --- a/pybind11/docs/advanced/cast/custom.rst +++ b/pybind11/docs/advanced/cast/custom.rst @@ -46,7 +46,7 @@ type is explicitly allowed. * function signatures and declares a local variable * 'value' of type inty */ - PYBIND11_TYPE_CASTER(inty, _("inty")); + PYBIND11_TYPE_CASTER(inty, const_name("inty")); /** * Conversion part 1 (Python->C++): convert a PyObject into a inty diff --git a/pybind11/docs/advanced/cast/eigen.rst b/pybind11/docs/advanced/cast/eigen.rst index 80f1013..a5c11a3 100644 --- a/pybind11/docs/advanced/cast/eigen.rst +++ b/pybind11/docs/advanced/cast/eigen.rst @@ -52,7 +52,7 @@ can be mapped *and* if the numpy array is writeable (that is the passed variable will be transparently carried out directly on the ``numpy.ndarray``. -This means you can can write code such as the following and have it work as +This means you can write code such as the following and have it work as expected: .. code-block:: cpp diff --git a/pybind11/docs/advanced/cast/overview.rst b/pybind11/docs/advanced/cast/overview.rst index 6341fce..6a834a3 100644 --- a/pybind11/docs/advanced/cast/overview.rst +++ b/pybind11/docs/advanced/cast/overview.rst @@ -75,96 +75,96 @@ The following basic data types are supported out of the box (some may require an additional extension header to be included). To pass other data structures as arguments and return values, refer to the section on binding :ref:`classes`. -+------------------------------------+---------------------------+-------------------------------+ -| Data type | Description | Header file | -+====================================+===========================+===============================+ -| ``int8_t``, ``uint8_t`` | 8-bit integers | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``int16_t``, ``uint16_t`` | 16-bit integers | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``int32_t``, ``uint32_t`` | 32-bit integers | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``int64_t``, ``uint64_t`` | 64-bit integers | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``ssize_t``, ``size_t`` | Platform-dependent size | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``float``, ``double`` | Floating point types | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``bool`` | Two-state Boolean type | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``char`` | Character literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``char16_t`` | UTF-16 character literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``char32_t`` | UTF-32 character literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``wchar_t`` | Wide character literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``const char *`` | UTF-8 string literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``const char16_t *`` | UTF-16 string literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``const char32_t *`` | UTF-32 string literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``const wchar_t *`` | Wide string literal | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::string`` | STL dynamic UTF-8 string | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::u16string`` | STL dynamic UTF-16 string | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::u32string`` | STL dynamic UTF-32 string | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` | -| ``std::u16string_view``, etc. | | | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::pair`` | Pair of two custom types | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::reference_wrapper<...>`` | Reference type wrapper | :file:`pybind11/pybind11.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::complex`` | Complex numbers | :file:`pybind11/complex.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::array`` | STL static array | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::vector`` | STL dynamic array | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::deque`` | STL double-ended queue | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::valarray`` | STL value array | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::list`` | STL linked list | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::map`` | STL ordered map | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::unordered_map`` | STL unordered map | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::set`` | STL ordered set | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::unordered_set`` | STL unordered set | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::optional`` | STL optional type (C++17) | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::experimental::optional`` | STL optional type (exp.) | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::filesystem::path`` | STL path (C++17) [#]_ | :file:`pybind11/stl.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::chrono::duration<...>`` | STL time duration | :file:`pybind11/chrono.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``std::chrono::time_point<...>`` | STL date/time | :file:`pybind11/chrono.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``Eigen::Matrix<...>`` | Eigen: dense matrix | :file:`pybind11/eigen.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``Eigen::Map<...>`` | Eigen: mapped memory | :file:`pybind11/eigen.h` | -+------------------------------------+---------------------------+-------------------------------+ -| ``Eigen::SparseMatrix<...>`` | Eigen: sparse matrix | :file:`pybind11/eigen.h` | -+------------------------------------+---------------------------+-------------------------------+ ++------------------------------------+---------------------------+-----------------------------------+ +| Data type | Description | Header file | ++====================================+===========================+===================================+ +| ``int8_t``, ``uint8_t`` | 8-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``int16_t``, ``uint16_t`` | 16-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``int32_t``, ``uint32_t`` | 32-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``int64_t``, ``uint64_t`` | 64-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``ssize_t``, ``size_t`` | Platform-dependent size | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``float``, ``double`` | Floating point types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``bool`` | Two-state Boolean type | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``char`` | Character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``char16_t`` | UTF-16 character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``char32_t`` | UTF-32 character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``wchar_t`` | Wide character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``const char *`` | UTF-8 string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``const char16_t *`` | UTF-16 string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``const char32_t *`` | UTF-32 string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``const wchar_t *`` | Wide string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::string`` | STL dynamic UTF-8 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::u16string`` | STL dynamic UTF-16 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::u32string`` | STL dynamic UTF-32 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` | +| ``std::u16string_view``, etc. | | | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::pair`` | Pair of two custom types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::reference_wrapper<...>`` | Reference type wrapper | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::complex`` | Complex numbers | :file:`pybind11/complex.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::array`` | STL static array | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::vector`` | STL dynamic array | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::deque`` | STL double-ended queue | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::valarray`` | STL value array | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::list`` | STL linked list | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::map`` | STL ordered map | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::unordered_map`` | STL unordered map | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::set`` | STL ordered set | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::unordered_set`` | STL unordered set | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::optional`` | STL optional type (C++17) | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::experimental::optional`` | STL optional type (exp.) | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::variant<...>`` | Type-safe union (C++17) | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::filesystem::path`` | STL path (C++17) [#]_ | :file:`pybind11/stl/filesystem.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::chrono::duration<...>`` | STL time duration | :file:`pybind11/chrono.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``std::chrono::time_point<...>`` | STL date/time | :file:`pybind11/chrono.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``Eigen::Matrix<...>`` | Eigen: dense matrix | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``Eigen::Map<...>`` | Eigen: mapped memory | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-----------------------------------+ +| ``Eigen::SparseMatrix<...>`` | Eigen: sparse matrix | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-----------------------------------+ .. [#] ``std::filesystem::path`` is converted to ``pathlib.Path`` and ``os.PathLike`` is converted to ``std::filesystem::path``, but this requires diff --git a/pybind11/docs/advanced/classes.rst b/pybind11/docs/advanced/classes.rst index 5f01a2f..f333933 100644 --- a/pybind11/docs/advanced/classes.rst +++ b/pybind11/docs/advanced/classes.rst @@ -9,7 +9,7 @@ that you are already familiar with the basics from :doc:`/classes`. Overriding virtual functions in Python ====================================== -Suppose that a C++ class or interface has a virtual function that we'd like to +Suppose that a C++ class or interface has a virtual function that we'd like to override from within Python (we'll focus on the class ``Animal``; ``Dog`` is given as a specific example of how one would do this with traditional C++ code). @@ -1161,6 +1161,58 @@ error: .. versionadded:: 2.6 +Binding classes with template parameters +======================================== + +pybind11 can also wrap classes that have template parameters. Consider these classes: + +.. code-block:: cpp + + struct Cat {}; + struct Dog {}; + + template + struct Cage { + Cage(PetType& pet); + PetType& get(); + }; + +C++ templates may only be instantiated at compile time, so pybind11 can only +wrap instantiated templated classes. You cannot wrap a non-instantiated template: + +.. code-block:: cpp + + // BROKEN (this will not compile) + py::class_(m, "Cage"); + .def("get", &Cage::get); + +You must explicitly specify each template/type combination that you want to +wrap separately. + +.. code-block:: cpp + + // ok + py::class_>(m, "CatCage") + .def("get", &Cage::get); + + // ok + py::class_>(m, "DogCage") + .def("get", &Cage::get); + +If your class methods have template parameters you can wrap those as well, +but once again each instantiation must be explicitly specified: + +.. code-block:: cpp + + typename + struct MyClass { + template + T fn(V v); + }; + + py::class>(m, "MyClassT") + .def("fn", &MyClass::fn); + Custom automatic downcasters ============================ @@ -1266,7 +1318,7 @@ Custom type setup ================= For advanced use cases, such as enabling garbage collection support, you may -wish to directly manipulate the `PyHeapTypeObject` corresponding to a +wish to directly manipulate the ``PyHeapTypeObject`` corresponding to a ``py::class_`` definition. You can do that using ``py::custom_type_setup``: diff --git a/pybind11/docs/advanced/embedding.rst b/pybind11/docs/advanced/embedding.rst index a435b8a..dd980d4 100644 --- a/pybind11/docs/advanced/embedding.rst +++ b/pybind11/docs/advanced/embedding.rst @@ -40,15 +40,15 @@ The essential structure of the ``main.cpp`` file looks like this: } The interpreter must be initialized before using any Python API, which includes -all the functions and classes in pybind11. The RAII guard class `scoped_interpreter` +all the functions and classes in pybind11. The RAII guard class ``scoped_interpreter`` takes care of the interpreter lifetime. After the guard is destroyed, the interpreter shuts down and clears its memory. No Python functions can be called after this. Executing Python code ===================== -There are a few different ways to run Python code. One option is to use `eval`, -`exec` or `eval_file`, as explained in :ref:`eval`. Here is a quick example in +There are a few different ways to run Python code. One option is to use ``eval``, +``exec`` or ``eval_file``, as explained in :ref:`eval`. Here is a quick example in the context of an executable with an embedded interpreter: .. code-block:: cpp @@ -108,7 +108,7 @@ The two approaches can also be combined: Importing modules ================= -Python modules can be imported using `module_::import()`: +Python modules can be imported using ``module_::import()``: .. code-block:: cpp @@ -134,7 +134,7 @@ embedding the interpreter. This makes it easy to import local Python files: int n = result.cast(); assert(n == 3); -Modules can be reloaded using `module_::reload()` if the source is modified e.g. +Modules can be reloaded using ``module_::reload()`` if the source is modified e.g. by an external process. This can be useful in scenarios where the application imports a user defined data processing script which needs to be updated after changes by the user. Note that this function does not reload modules recursively. @@ -144,7 +144,7 @@ changes by the user. Note that this function does not reload modules recursively Adding embedded modules ======================= -Embedded binary modules can be added using the `PYBIND11_EMBEDDED_MODULE` macro. +Embedded binary modules can be added using the ``PYBIND11_EMBEDDED_MODULE`` macro. Note that the definition must be placed at global scope. They can be imported like any other module. @@ -170,7 +170,7 @@ like any other module. Unlike extension modules where only a single binary module can be created, on the embedded side an unlimited number of modules can be added using multiple -`PYBIND11_EMBEDDED_MODULE` definitions (as long as they have unique names). +``PYBIND11_EMBEDDED_MODULE`` definitions (as long as they have unique names). These modules are added to Python's list of builtins, so they can also be imported in pure Python files loaded by the interpreter. Everything interacts @@ -216,9 +216,9 @@ naturally: Interpreter lifetime ==================== -The Python interpreter shuts down when `scoped_interpreter` is destroyed. After +The Python interpreter shuts down when ``scoped_interpreter`` is destroyed. After this, creating a new instance will restart the interpreter. Alternatively, the -`initialize_interpreter` / `finalize_interpreter` pair of functions can be used +``initialize_interpreter`` / ``finalize_interpreter`` pair of functions can be used to directly set the state at any time. Modules created with pybind11 can be safely re-initialized after the interpreter @@ -230,8 +230,8 @@ global data. All the details can be found in the CPython documentation. .. warning:: - Creating two concurrent `scoped_interpreter` guards is a fatal error. So is - calling `initialize_interpreter` for a second time after the interpreter + Creating two concurrent ``scoped_interpreter`` guards is a fatal error. So is + calling ``initialize_interpreter`` for a second time after the interpreter has already been initialized. Do not use the raw CPython API functions ``Py_Initialize`` and @@ -242,7 +242,7 @@ global data. All the details can be found in the CPython documentation. Sub-interpreter support ======================= -Creating multiple copies of `scoped_interpreter` is not possible because it +Creating multiple copies of ``scoped_interpreter`` is not possible because it represents the main Python interpreter. Sub-interpreters are something different and they do permit the existence of multiple interpreters. This is an advanced feature of the CPython API and should be handled with care. pybind11 does not @@ -258,5 +258,5 @@ We'll just mention a couple of caveats the sub-interpreters support in pybind11: 2. Managing multiple threads, multiple interpreters and the GIL can be challenging and there are several caveats here, even within the pure CPython API (please refer to the Python docs for details). As for - pybind11, keep in mind that `gil_scoped_release` and `gil_scoped_acquire` + pybind11, keep in mind that ``gil_scoped_release`` and ``gil_scoped_acquire`` do not take sub-interpreters into account. diff --git a/pybind11/docs/advanced/exceptions.rst b/pybind11/docs/advanced/exceptions.rst index 2aaa0ad..7cd8447 100644 --- a/pybind11/docs/advanced/exceptions.rst +++ b/pybind11/docs/advanced/exceptions.rst @@ -56,13 +56,15 @@ at its exception handler. +--------------------------------------+--------------------------------------+ | :class:`pybind11::buffer_error` | ``BufferError`` | +--------------------------------------+--------------------------------------+ -| :class:`pybind11::import_error` | ``import_error`` | +| :class:`pybind11::import_error` | ``ImportError`` | ++--------------------------------------+--------------------------------------+ +| :class:`pybind11::attribute_error` | ``AttributeError`` | +--------------------------------------+--------------------------------------+ | Any other exception | ``RuntimeError`` | +--------------------------------------+--------------------------------------+ Exception translation is not bidirectional. That is, *catching* the C++ -exceptions defined above above will not trap exceptions that originate from +exceptions defined above will not trap exceptions that originate from Python. For that, catch :class:`pybind11::error_already_set`. See :ref:`below ` for further details. @@ -96,18 +98,18 @@ A matching function is available for registering a local exception translator: It is possible to specify base class for the exception using the third -parameter, a `handle`: +parameter, a ``handle``: .. code-block:: cpp py::register_exception(module, "PyExp", PyExc_RuntimeError); py::register_local_exception(module, "PyExp", PyExc_RuntimeError); -Then `PyExp` can be caught both as `PyExp` and `RuntimeError`. +Then ``PyExp`` can be caught both as ``PyExp`` and ``RuntimeError``. The class objects of the built-in Python exceptions are listed in the Python documentation on `Standard Exceptions `_. -The default base class is `PyExc_Exception`. +The default base class is ``PyExc_Exception``. When more advanced exception translation is needed, the functions ``py::register_exception_translator(translator)`` and diff --git a/pybind11/docs/advanced/functions.rst b/pybind11/docs/advanced/functions.rst index 1178d07..bf5b5fa 100644 --- a/pybind11/docs/advanced/functions.rst +++ b/pybind11/docs/advanced/functions.rst @@ -120,7 +120,7 @@ targeted arguments can be passed through the :class:`cpp_function` constructor: .. code-block:: cpp class_(m, "MyClass") - .def_property("data" + .def_property("data", py::cpp_function(&MyClass::getData, py::return_value_policy::copy), py::cpp_function(&MyClass::setData) ); @@ -232,7 +232,7 @@ is equivalent to the following pseudocode: }); The only requirement is that ``T`` is default-constructible, but otherwise any -scope guard will work. This is very useful in combination with `gil_scoped_release`. +scope guard will work. This is very useful in combination with ``gil_scoped_release``. See :ref:`gil`. Multiple guards can also be specified as ``py::call_guard``. The @@ -306,8 +306,9 @@ The class ``py::args`` derives from ``py::tuple`` and ``py::kwargs`` derives from ``py::dict``. You may also use just one or the other, and may combine these with other -arguments as long as the ``py::args`` and ``py::kwargs`` arguments are the last -arguments accepted by the function. +arguments. Note, however, that ``py::kwargs`` must always be the last argument +of the function, and ``py::args`` implies that any further arguments are +keyword-only (see :ref:`keyword_only_arguments`). Please refer to the other examples for details on how to iterate over these, and on how to cast their entries into C++ objects. A demonstration is also @@ -366,6 +367,8 @@ like so: py::class_("MyClass") .def("myFunction", py::arg("arg") = static_cast(nullptr)); +.. _keyword_only_arguments: + Keyword-only arguments ====================== @@ -397,6 +400,15 @@ feature does *not* require Python 3 to work. .. versionadded:: 2.6 +As of pybind11 2.9, a ``py::args`` argument implies that any following arguments +are keyword-only, as if ``py::kw_only()`` had been specified in the same +relative location of the argument list as the ``py::args`` argument. The +``py::kw_only()`` may be included to be explicit about this, but is not +required. (Prior to 2.9 ``py::args`` may only occur at the end of the argument +list, or immediately before a ``py::kwargs`` argument at the end). + +.. versionadded:: 2.9 + Positional-only arguments ========================= @@ -566,3 +578,38 @@ prefers earlier-defined overloads to later-defined ones. .. versionadded:: 2.6 The ``py::prepend()`` tag. + +Binding functions with template parameters +========================================== + +You can bind functions that have template parameters. Here's a function: + +.. code-block:: cpp + + template + void set(T t); + +C++ templates cannot be instantiated at runtime, so you cannot bind the +non-instantiated function: + +.. code-block:: cpp + + // BROKEN (this will not compile) + m.def("set", &set); + +You must bind each instantiated function template separately. You may bind +each instantiation with the same name, which will be treated the same as +an overloaded function: + +.. code-block:: cpp + + m.def("set", &set); + m.def("set", &set); + +Sometimes it's more clear to bind them with separate names, which is also +an option: + +.. code-block:: cpp + + m.def("setInt", &set); + m.def("setString", &set); diff --git a/pybind11/docs/advanced/misc.rst b/pybind11/docs/advanced/misc.rst index b3f3b22..edab15f 100644 --- a/pybind11/docs/advanced/misc.rst +++ b/pybind11/docs/advanced/misc.rst @@ -84,7 +84,7 @@ could be realized as follows (important changes highlighted): }); } -The ``call_go`` wrapper can also be simplified using the `call_guard` policy +The ``call_go`` wrapper can also be simplified using the ``call_guard`` policy (see :ref:`call_policies`) which yields the same result: .. code-block:: cpp diff --git a/pybind11/docs/advanced/pycpp/object.rst b/pybind11/docs/advanced/pycpp/object.rst index 8bffb83..93e1a94 100644 --- a/pybind11/docs/advanced/pycpp/object.rst +++ b/pybind11/docs/advanced/pycpp/object.rst @@ -41,24 +41,17 @@ A tuple of python objects can be instantiated using :func:`py::make_tuple`: Each element is converted to a supported Python type. A `simple namespace`_ can be instantiated using -:func:`py::make_simple_namespace`: .. code-block:: cpp - using namespace pybind11::literals; // to bring in the `_a` literal - py::object ns = py::make_simple_namespace("spam"_a=py::none(), "eggs"_a=42); + using namespace pybind11::literals; // to bring in the `_a` literal + py::object SimpleNamespace = py::module_::import("types").attr("SimpleNamespace"); + py::object ns = SimpleNamespace("spam"_a=py::none(), "eggs"_a=42); Attributes on a namespace can be modified with the :func:`py::delattr`, :func:`py::getattr`, and :func:`py::setattr` functions. Simple namespaces can be useful as lightweight stand-ins for class instances. -.. note:: - - ``make_simple_namespace`` is not available in Python 2. - -.. versionchanged:: 2.8 - ``make_simple_namespace`` added. - .. _simple namespace: https://docs.python.org/3/library/types.html#types.SimpleNamespace .. _casting_back_and_forth: diff --git a/pybind11/docs/advanced/pycpp/utilities.rst b/pybind11/docs/advanced/pycpp/utilities.rst index bf90a62..af0f9cb 100644 --- a/pybind11/docs/advanced/pycpp/utilities.rst +++ b/pybind11/docs/advanced/pycpp/utilities.rst @@ -28,7 +28,7 @@ Capturing standard output from ostream Often, a library will use the streams ``std::cout`` and ``std::cerr`` to print, but this does not play well with Python's standard ``sys.stdout`` and ``sys.stderr`` -redirection. Replacing a library's printing with `py::print ` may not +redirection. Replacing a library's printing with ``py::print `` may not be feasible. This can be fixed using a guard around the library function that redirects output to the corresponding Python streams: @@ -62,9 +62,9 @@ This method respects flushes on the output streams and will flush if needed when the scoped guard is destroyed. This allows the output to be redirected in real time, such as to a Jupyter notebook. The two arguments, the C++ stream and the Python output, are optional, and default to standard output if not given. An -extra type, `py::scoped_estream_redirect `, is identical +extra type, ``py::scoped_estream_redirect ``, is identical except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful with -`py::call_guard`, which allows multiple items, but uses the default constructor: +``py::call_guard``, which allows multiple items, but uses the default constructor: .. code-block:: cpp @@ -74,7 +74,7 @@ except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful wi py::scoped_estream_redirect>()); The redirection can also be done in Python with the addition of a context -manager, using the `py::add_ostream_redirect() ` function: +manager, using the ``py::add_ostream_redirect() `` function: .. code-block:: cpp @@ -103,7 +103,7 @@ arguments to disable one of the streams if needed. Evaluating Python expressions from strings and files ==================================================== -pybind11 provides the `eval`, `exec` and `eval_file` functions to evaluate +pybind11 provides the ``eval``, ``exec`` and ``eval_file`` functions to evaluate Python expressions and statements. The following example illustrates how they can be used. diff --git a/pybind11/docs/basics.rst b/pybind11/docs/basics.rst index 0b1d85c..e0479b2 100644 --- a/pybind11/docs/basics.rst +++ b/pybind11/docs/basics.rst @@ -109,7 +109,7 @@ a file named :file:`example.cpp` with the following contents: PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring - m.def("add", &add, "A function which adds two numbers"); + m.def("add", &add, "A function that adds two numbers"); } .. [#f1] In practice, implementation and binding code will generally be located diff --git a/pybind11/docs/changelog.rst b/pybind11/docs/changelog.rst index 4a58f2d..e96db74 100644 --- a/pybind11/docs/changelog.rst +++ b/pybind11/docs/changelog.rst @@ -6,6 +6,293 @@ Changelog Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. +Changes will be added here periodically from the "Suggested changelog entry" +block in pull request descriptions. + +IN DEVELOPMENT +-------------- + +Removed support for Python 2.7, Python 3.5, and MSVC 2015. Support for MSVC +2017 is limited due to availability of CI runners; we highly recommend MSVC +2019 or 2022 be used. + +New features: + +* ``type_caster`` was added. ``std::monostate`` is a tag type + that allows ``std::variant`` to act as an optional, or allows default + construction of a ``std::variant`` holding a non-default constructible type. + `#3818 `_ + +* Support bytearray casting to string. + `#3707 `_ + +Changes: + +* Python 2 support was removed completely. + `#3688 `_ + +* The minimum version for MSVC is now 2017. + `#3722 `_ + +* Improve exception handling in python ``str`` bindings. + `#3826 `_ + +* The bindings for capsules now have more consistent exception handling. + `#3825 `_ + +* Fix exception handling when ``pybind11::weakref()`` fails. + `#3739 `_ + + +Bug fixes: + +* ``PYBIND11_OBJECT_CVT`` and ``PYBIND11_OBJECT_CVT_DEFAULT`` macro can be used + to define classes in namespaces other than pybind11. + `#3797 `_ + +Build system improvements: + +* Add MSVC builds in debug mode to CI. + `#3784 `_ + +* MSVC 2022 C++20 coverage was added to GitHub Actions, including Eigen. + `#3732 `_, + `#3741 `_ + +* Avoid ``setup.py `` usage in internal tests. + `#3734 `_ + + +Backend and tidying up: + +* Remove idioms in code comments. Use inclusive language. + `#3809 `_ + + +Version 2.9.2 (Mar 29, 2022) +---------------------------- + +Changes: + +* Enum now has an ``__index__`` method on Python <3.8 too. + `#3700 `_ + +* Local internals are now cleared after finalizing the interpreter. + `#3744 `_ + +Bug fixes: + +* Better support for Python 3.11 alphas. + `#3694 `_ + +* ``PYBIND11_TYPE_CASTER`` now uses fully qualified symbols, so it can be used + outside of ``pybind11::detail``. + `#3758 `_ + +* Some fixes for PyPy 3.9. + `#3768 `_ + +* Fixed a potential memleak in PyPy in ``get_type_override``. + `#3774 `_ + +* Fix usage of ``VISIBILITY_INLINES_HIDDEN``. + `#3721 `_ + + +Build system improvements: + +* Uses ``sysconfig`` module to determine installation locations on Python >= + 3.10, instead of ``distutils`` which has been deprecated. + `#3764 `_ + +* Support Catch 2.13.5+ (supporting GLIBC 2.34+). + `#3679 `_ + +* Fix test failures with numpy 1.22 by ignoring whitespace when comparing + ``str()`` of dtypes. + `#3682 `_ + + +Backend and tidying up: + +* clang-tidy: added ``readability-qualified-auto``, + ``readability-braces-around-statements``, + ``cppcoreguidelines-prefer-member-initializer``, + ``clang-analyzer-optin.performance.Padding``, + ``cppcoreguidelines-pro-type-static-cast-downcast``, and + ``readability-inconsistent-declaration-parameter-name``. + `#3702 `_, + `#3699 `_, + `#3716 `_, + `#3709 `_ + +* clang-format was added to the pre-commit actions, and the entire code base + automatically reformatted (after several iterations preparing for this leap). + `#3713 `_ + + +Version 2.9.1 (Feb 2, 2022) +--------------------------- + +Changes: + +* If possible, attach Python exception with ``py::raise_from`` to ``TypeError`` + when casting from C++ to Python. This will give additional info if Python + exceptions occur in the caster. Adds a test case of trying to convert a set + from C++ to Python when the hash function is not defined in Python. + `#3605 `_ + +* Add a mapping of C++11 nested exceptions to their Python exception + equivalent using ``py::raise_from``. This attaches the nested exceptions in + Python using the ``__cause__`` field. + `#3608 `_ + +* Propagate Python exception traceback using ``raise_from`` if a pybind11 + function runs out of overloads. + `#3671 `_ + +* ``py::multiple_inheritance`` is now only needed when C++ bases are hidden + from pybind11. + `#3650 `_ and + `#3659 `_ + + +Bug fixes: + +* Remove a boolean cast in ``numpy.h`` that causes MSVC C4800 warnings when + compiling against Python 3.10 or newer. + `#3669 `_ + +* Render ``py::bool_`` and ``py::float_`` as ``bool`` and ``float`` + respectively. + `#3622 `_ + +Build system improvements: + +* Fix CMake extension suffix computation on Python 3.10+. + `#3663 `_ + +* Allow ``CMAKE_ARGS`` to override CMake args in pybind11's own ``setup.py``. + `#3577 `_ + +* Remove a few deprecated c-headers. + `#3610 `_ + +* More uniform handling of test targets. + `#3590 `_ + +* Add clang-tidy readability check to catch potentially swapped function args. + `#3611 `_ + + +Version 2.9.0 (Dec 28, 2021) +---------------------------- + +This is the last version to support Python 2.7 and 3.5. + +New Features: + +* Allow ``py::args`` to be followed by other arguments; the remaining arguments + are implicitly keyword-only, as if a ``py::kw_only{}`` annotation had been + used. + `#3402 `_ + +Changes: + +* Make str/bytes/memoryview more interoperable with ``std::string_view``. + `#3521 `_ + +* Replace ``_`` with ``const_name`` in internals, avoid defining ``pybind::_`` + if ``_`` defined as macro (common gettext usage) + `#3423 `_ + + +Bug fixes: + +* Fix a rare warning about extra copy in an Eigen constructor. + `#3486 `_ + +* Fix caching of the C++ overrides. + `#3465 `_ + +* Add missing ``std::forward`` calls to some ``cpp_function`` overloads. + `#3443 `_ + +* Support PyPy 7.3.7 and the PyPy3.8 beta. Test python-3.11 on PRs with the + ``python dev`` label. + `#3419 `_ + +* Replace usage of deprecated ``Eigen::MappedSparseMatrix`` with + ``Eigen::Map>`` for Eigen 3.3+. + `#3499 `_ + +* Tweaks to support Microsoft Visual Studio 2022. + `#3497 `_ + +Build system improvements: + +* Nicer CMake printout and IDE organisation for pybind11's own tests. + `#3479 `_ + +* CMake: report version type as part of the version string to avoid a spurious + space in the package status message. + `#3472 `_ + +* Flags starting with ``-g`` in ``$CFLAGS`` and ``$CPPFLAGS`` are no longer + overridden by ``.Pybind11Extension``. + `#3436 `_ + +* Ensure ThreadPool is closed in ``setup_helpers``. + `#3548 `_ + +* Avoid LTS on ``mips64`` and ``ppc64le`` (reported broken). + `#3557 `_ + + +v2.8.1 (Oct 27, 2021) +--------------------- + +Changes and additions: + +* The simple namespace creation shortcut added in 2.8.0 was deprecated due to + usage of CPython internal API, and will be removed soon. Use + ``py::module_::import("types").attr("SimpleNamespace")``. + `#3374 `_ + +* Add C++ Exception type to throw and catch ``AttributeError``. Useful for + defining custom ``__setattr__`` and ``__getattr__`` methods. + `#3387 `_ + +Fixes: + +* Fixed the potential for dangling references when using properties with + ``std::optional`` types. + `#3376 `_ + +* Modernize usage of ``PyCodeObject`` on Python 3.9+ (moving toward support for + Python 3.11a1) + `#3368 `_ + +* A long-standing bug in ``eigen.h`` was fixed (originally PR #3343). The bug + was unmasked by newly added ``static_assert``'s in the Eigen 3.4.0 release. + `#3352 `_ + +* Support multiple raw inclusion of CMake helper files (Conan.io does this for + multi-config generators). + `#3420 `_ + +* Fix harmless warning on upcoming CMake 3.22. + `#3368 `_ + +* Fix 2.8.0 regression with MSVC 2017 + C++17 mode + Python 3. + `#3407 `_ + +* Fix 2.8.0 regression that caused undefined behavior (typically + segfaults) in ``make_key_iterator``/``make_value_iterator`` if dereferencing + the iterator returned a temporary value instead of a reference. + `#3348 `_ + + v2.8.0 (Oct 4, 2021) -------------------- @@ -19,10 +306,10 @@ New features: ``register_local_exception_translator(ExceptionTranslator&& translator)`` instead of ``register_exception_translator(ExceptionTranslator&& translator)`` to keep your exception remapping code local to the module. - `#2650 `_ + `#2650 `_ * Add ``make_simple_namespace`` function for instantiating Python - ``SimpleNamespace`` objects. + ``SimpleNamespace`` objects. **Deprecated in 2.8.1.** `#2840 `_ * ``pybind11::scoped_interpreter`` and ``initialize_interpreter`` have new @@ -47,9 +334,10 @@ New features: `#3293 `_ * Improve the classes generated by ``bind_map``: `#3310 `_ - * Change ``.items`` from an iterator to a dictionary view. - * Add ``.keys`` and ``.values`` (both dictionary views). - * Allow ``__contains__`` to take any object. + + * Change ``.items`` from an iterator to a dictionary view. + * Add ``.keys`` and ``.values`` (both dictionary views). + * Allow ``__contains__`` to take any object. * ``pybind11::custom_type_setup`` was added, for customizing the ``PyHeapTypeObject`` corresponding to a class, which may be useful for @@ -244,8 +532,8 @@ New features: Changes: -* ``py::str`` changed to exclusively hold `PyUnicodeObject`. Previously - ``py::str`` could also hold `bytes`, which is probably surprising, was +* ``py::str`` changed to exclusively hold ``PyUnicodeObject``. Previously + ``py::str`` could also hold ``bytes``, which is probably surprising, was never documented, and can mask bugs (e.g. accidental use of ``py::str`` instead of ``py::bytes``). `#2409 `_ @@ -1398,7 +1686,7 @@ v2.2.0 (August 31, 2017) * Intel C++ compiler compatibility fixes. `#937 `_. -* Fixed implicit conversion of `py::enum_` to integer types on Python 2.7. +* Fixed implicit conversion of ``py::enum_`` to integer types on Python 2.7. `#821 `_. * Added ``py::hash`` to fetch the hash value of Python objects, and diff --git a/pybind11/docs/compiling.rst b/pybind11/docs/compiling.rst index 75608bd..25adb9f 100644 --- a/pybind11/docs/compiling.rst +++ b/pybind11/docs/compiling.rst @@ -475,7 +475,7 @@ available in all modes. The targets provided are: Everything for extension modules - ``pybind11::pybind11`` + ``Python::Module`` (FindPython CMake 3.15+) or ``pybind11::python_link_helper`` ``pybind11::embed`` - Everything for embedding the Python interpreter - ``pybind11::pybind11`` + ``Python::Embed`` (FindPython) or Python libs + Everything for embedding the Python interpreter - ``pybind11::pybind11`` + ``Python::Python`` (FindPython) or Python libs ``pybind11::lto`` / ``pybind11::thin_lto`` An alternative to `INTERPROCEDURAL_OPTIMIZATION` for adding link-time optimization. diff --git a/pybind11/docs/release.rst b/pybind11/docs/release.rst index e4f3d19..e761cdf 100644 --- a/pybind11/docs/release.rst +++ b/pybind11/docs/release.rst @@ -22,11 +22,15 @@ the version just below. To release a new version of pybind11: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +If you don't have nox, you should either use ``pipx run nox`` instead, or use +``pipx install nox`` or ``brew install nox`` (Unix). + - Update the version number - Update ``PYBIND11_VERSION_MAJOR`` etc. in ``include/pybind11/detail/common.h``. PATCH should be a simple integer. - Update the version HEX just below, as well. - Update ``pybind11/_version.py`` (match above) + - Run ``nox -s tests_packaging`` to ensure this was done correctly. - Ensure that all the information in ``setup.cfg`` is up-to-date, like supported Python versions. - Add release date in ``docs/changelog.rst``. @@ -49,13 +53,13 @@ To release a new version of pybind11: - Make a GitHub release (this shows up in the UI, sends new release notifications to users watching releases, and also uploads PyPI packages). (Note: if you do not use an existing tag, this creates a new lightweight tag - for you, so you could skip the above step). - - GUI method: click "Create a new release" on the far right, fill in the tag - name (if you didn't tag above, it will be made here), fill in a release - name like "Version X.Y.Z", and optionally copy-and-paste the changelog into - the description (processed as markdown by Pandoc). Check "pre-release" if - this is a beta/RC. You can get partway there with - ``cat docs/changelog.rst | pandoc -f rst -t gfm``. + for you, so you could skip the above step.) + - GUI method: Under `releases `_ + click "Draft a new release" on the far right, fill in the tag name + (if you didn't tag above, it will be made here), fill in a release name + like "Version X.Y.Z", and copy-and-paste the markdown-formatted (!) changelog + into the description (usually ``cat docs/changelog.rst | pandoc -f rst -t gfm``). + Check "pre-release" if this is a beta/RC. - CLI method: with ``gh`` installed, run ``gh release create vX.Y.Z -t "Version X.Y.Z"`` If this is a pre-release, add ``-p``. @@ -64,6 +68,7 @@ To release a new version of pybind11: - Update version macros in ``include/pybind11/detail/common.h`` (set PATCH to ``0.dev1`` and increment MINOR). - Update ``_version.py`` to match + - Run ``nox -s tests_packaging`` to ensure this was done correctly. - Add a spot for in-development updates in ``docs/changelog.rst``. - ``git add``, ``git commit``, ``git push`` @@ -71,7 +76,7 @@ If a version branch is updated, remember to set PATCH to ``1.dev1``. If you'd like to bump homebrew, run: -.. code-block:: +.. code-block:: console brew bump-formula-pr --url https://github.com/pybind/pybind11/archive/vX.Y.Z.tar.gz @@ -86,9 +91,7 @@ If you need to manually upload releases, you can download the releases from the .. code-block:: bash - python3 -m pip install build - python3 -m build - PYBIND11_SDIST_GLOBAL=1 python3 -m build + nox -s build twine upload dist/* This makes SDists and wheels, and the final line uploads them. diff --git a/pybind11/docs/requirements.txt b/pybind11/docs/requirements.txt index 8f293b5..b2801b1 100644 --- a/pybind11/docs/requirements.txt +++ b/pybind11/docs/requirements.txt @@ -1,8 +1,5 @@ -breathe==4.26.1 -# docutils 0.17 breaks HTML tags & RTD theme -# https://github.com/sphinx-doc/sphinx/issues/9001 -docutils==0.16 -sphinx==3.3.1 -sphinx_rtd_theme==0.5.0 -sphinxcontrib-moderncmakedomain==3.17 -sphinxcontrib-svg2pdfconverter==1.1.0 +breathe==4.31.0 +sphinx==3.5.4 +sphinx_rtd_theme==1.0.0 +sphinxcontrib-moderncmakedomain==3.19 +sphinxcontrib-svg2pdfconverter==1.1.1 diff --git a/pybind11/docs/upgrade.rst b/pybind11/docs/upgrade.rst index b2b6b12..d91d51e 100644 --- a/pybind11/docs/upgrade.rst +++ b/pybind11/docs/upgrade.rst @@ -8,7 +8,21 @@ to a new version. But it goes into more detail. This includes things like deprecated APIs and their replacements, build system changes, general code modernization and other useful information. -.. _upgrade-guide-2.6: +.. _upgrade-guide-2.9: + +v2.9 +==== + +* Any usage of the recently added ``py::make_simple_namespace`` should be + converted to using ``py::module_::import("types").attr("SimpleNamespace")`` + instead. + +* The use of ``_`` in custom type casters can now be replaced with the more + readable ``const_name`` instead. The old ``_`` shortcut has been retained + unless it is being used as a macro (like for gettext). + + +.. _upgrade-guide-2.7: v2.7 ==== @@ -34,6 +48,7 @@ to be common: careful review and custom fixes. +.. _upgrade-guide-2.6: v2.6 ==== diff --git a/pybind11/include/pybind11/attr.h b/pybind11/include/pybind11/attr.h index 0dedbc0..de95f89 100644 --- a/pybind11/include/pybind11/attr.h +++ b/pybind11/include/pybind11/attr.h @@ -20,54 +20,62 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) /// @{ /// Annotation for methods -struct is_method { handle class_; +struct is_method { + handle class_; explicit is_method(const handle &c) : class_(c) {} }; /// Annotation for operators -struct is_operator { }; +struct is_operator {}; /// Annotation for classes that cannot be subclassed -struct is_final { }; +struct is_final {}; /// Annotation for parent scope -struct scope { handle value; +struct scope { + handle value; explicit scope(const handle &s) : value(s) {} }; /// Annotation for documentation -struct doc { const char *value; +struct doc { + const char *value; explicit doc(const char *value) : value(value) {} }; /// Annotation for function names -struct name { const char *value; +struct name { + const char *value; explicit name(const char *value) : value(value) {} }; /// Annotation indicating that a function is an overload associated with a given "sibling" -struct sibling { handle value; +struct sibling { + handle value; explicit sibling(const handle &value) : value(value.ptr()) {} }; /// Annotation indicating that a class derives from another given type -template struct base { +template +struct base { - PYBIND11_DEPRECATED("base() was deprecated in favor of specifying 'T' as a template argument to class_") - base() { } // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute + PYBIND11_DEPRECATED( + "base() was deprecated in favor of specifying 'T' as a template argument to class_") + base() {} // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute }; /// Keep patient alive while nurse lives -template struct keep_alive { }; +template +struct keep_alive {}; /// Annotation indicating that a class is involved in a multiple inheritance relationship -struct multiple_inheritance { }; +struct multiple_inheritance {}; /// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class -struct dynamic_attr { }; +struct dynamic_attr {}; /// Annotation which enables the buffer protocol for a type -struct buffer_protocol { }; +struct buffer_protocol {}; /// Annotation which requests that a special metaclass is created for a type struct metaclass { @@ -78,7 +86,7 @@ struct metaclass { metaclass() {} /// Override pybind11's default metaclass - explicit metaclass(handle value) : value(value) { } + explicit metaclass(handle value) : value(value) {} }; /// Specifies a custom callback with signature `void (PyHeapTypeObject*)` that @@ -99,15 +107,16 @@ struct custom_type_setup { }; /// Annotation that marks a class as local to the module: -struct module_local { const bool value; +struct module_local { + const bool value; constexpr explicit module_local(bool v = true) : value(v) {} }; /// Annotation to mark enums as an arithmetic type -struct arithmetic { }; +struct arithmetic {}; /// Mark a function for addition at the beginning of the existing overload chain instead of the end -struct prepend { }; +struct prepend {}; /** \rst A call policy which places one or more guard variables (``Ts...``) around the function call. @@ -127,9 +136,13 @@ struct prepend { }; return foo(args...); // forwarded arguments }); \endrst */ -template struct call_guard; +template +struct call_guard; -template <> struct call_guard<> { using type = detail::void_type; }; +template <> +struct call_guard<> { + using type = detail::void_type; +}; template struct call_guard { @@ -154,7 +167,8 @@ PYBIND11_NAMESPACE_BEGIN(detail) enum op_id : int; enum op_type : int; struct undefined_t; -template struct op_; +template +struct op_; void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret); /// Internal data structure which holds metadata about a keyword argument @@ -166,15 +180,16 @@ struct argument_record { bool none : 1; ///< True if None is allowed when loading argument_record(const char *name, const char *descr, handle value, bool convert, bool none) - : name(name), descr(descr), value(value), convert(convert), none(none) { } + : name(name), descr(descr), value(value), convert(convert), none(none) {} }; -/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.) +/// Internal data structure which holds metadata about a bound function (signature, overloads, +/// etc.) struct function_record { function_record() : is_constructor(false), is_new_style_constructor(false), is_stateless(false), - is_operator(false), is_method(false), has_args(false), - has_kwargs(false), has_kw_only_args(false), prepend(false) { } + is_operator(false), is_method(false), has_args(false), has_kwargs(false), + prepend(false) {} /// Function name char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ @@ -189,13 +204,13 @@ struct function_record { std::vector args; /// Pointer to lambda function which converts arguments and performs the actual call - handle (*impl) (function_call &) = nullptr; + handle (*impl)(function_call &) = nullptr; /// Storage for the wrapped function pointer and captured data, if any - void *data[3] = { }; + void *data[3] = {}; /// Pointer to custom destructor for 'data' (if needed) - void (*free_data) (function_record *ptr) = nullptr; + void (*free_data)(function_record *ptr) = nullptr; /// Return value policy associated with this function return_value_policy policy = return_value_policy::automatic; @@ -221,17 +236,15 @@ struct function_record { /// True if the function has a '**kwargs' argument bool has_kwargs : 1; - /// True once a 'py::kw_only' is encountered (any following args are keyword-only) - bool has_kw_only_args : 1; - /// True if this function is to be inserted at the beginning of the overload resolution chain bool prepend : 1; /// Number of arguments (including py::args and/or py::kwargs, if present) std::uint16_t nargs; - /// Number of trailing arguments (counted in `nargs`) that are keyword-only - std::uint16_t nargs_kw_only = 0; + /// Number of leading positional arguments, which are terminated by a py::args or py::kwargs + /// argument or by a py::kw_only annotation. + std::uint16_t nargs_pos = 0; /// Number of leading arguments (counted in `nargs`) that are positional-only std::uint16_t nargs_pos_only = 0; @@ -253,7 +266,7 @@ struct function_record { struct type_record { PYBIND11_NOINLINE type_record() : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false), - default_holder(true), module_local(false), is_final(false) { } + default_holder(true), module_local(false), is_final(false) {} /// Handle to the parent scope handle scope; @@ -312,42 +325,43 @@ struct type_record { /// Is the class inheritable from python classes? bool is_final : 1; - PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *)) { - auto base_info = detail::get_type_info(base, false); + PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *) ) { + auto *base_info = detail::get_type_info(base, false); if (!base_info) { std::string tname(base.name()); detail::clean_type_id(tname); - pybind11_fail("generic_type: type \"" + std::string(name) + - "\" referenced unknown base type \"" + tname + "\""); + pybind11_fail("generic_type: type \"" + std::string(name) + + "\" referenced unknown base type \"" + tname + "\""); } if (default_holder != base_info->default_holder) { std::string tname(base.name()); detail::clean_type_id(tname); - pybind11_fail("generic_type: type \"" + std::string(name) + "\" " + - (default_holder ? "does not have" : "has") + - " a non-default holder type while its base \"" + tname + "\" " + - (base_info->default_holder ? "does not" : "does")); + pybind11_fail("generic_type: type \"" + std::string(name) + "\" " + + (default_holder ? "does not have" : "has") + + " a non-default holder type while its base \"" + tname + "\" " + + (base_info->default_holder ? "does not" : "does")); } bases.append((PyObject *) base_info->type); - if (base_info->type->tp_dictoffset != 0) + if (base_info->type->tp_dictoffset != 0) { dynamic_attr = true; + } - if (caster) + if (caster) { base_info->implicit_casts.emplace_back(type, caster); + } } }; -inline function_call::function_call(const function_record &f, handle p) : - func(f), parent(p) { +inline function_call::function_call(const function_record &f, handle p) : func(f), parent(p) { args.reserve(f.nargs); args_convert.reserve(f.nargs); } /// Tag for a new-style `__init__` defined in `detail/init.h` -struct is_new_style_constructor { }; +struct is_new_style_constructor {}; /** * Partial template specializations to process custom attributes provided to @@ -355,100 +369,133 @@ struct is_new_style_constructor { }; * fields in the type_record and function_record data structures or executed at * runtime to deal with custom call policies (e.g. keep_alive). */ -template struct process_attribute; +template +struct process_attribute; -template struct process_attribute_default { +template +struct process_attribute_default { /// Default implementation: do nothing - static void init(const T &, function_record *) { } - static void init(const T &, type_record *) { } - static void precall(function_call &) { } - static void postcall(function_call &, handle) { } + static void init(const T &, function_record *) {} + static void init(const T &, type_record *) {} + static void precall(function_call &) {} + static void postcall(function_call &, handle) {} }; /// Process an attribute specifying the function's name -template <> struct process_attribute : process_attribute_default { +template <> +struct process_attribute : process_attribute_default { static void init(const name &n, function_record *r) { r->name = const_cast(n.value); } }; /// Process an attribute specifying the function's docstring -template <> struct process_attribute : process_attribute_default { +template <> +struct process_attribute : process_attribute_default { static void init(const doc &n, function_record *r) { r->doc = const_cast(n.value); } }; /// Process an attribute specifying the function's docstring (provided as a C-style string) -template <> struct process_attribute : process_attribute_default { +template <> +struct process_attribute : process_attribute_default { static void init(const char *d, function_record *r) { r->doc = const_cast(d); } static void init(const char *d, type_record *r) { r->doc = const_cast(d); } }; -template <> struct process_attribute : process_attribute { }; +template <> +struct process_attribute : process_attribute {}; /// Process an attribute indicating the function's return value policy -template <> struct process_attribute : process_attribute_default { +template <> +struct process_attribute : process_attribute_default { static void init(const return_value_policy &p, function_record *r) { r->policy = p; } }; -/// Process an attribute which indicates that this is an overloaded function associated with a given sibling -template <> struct process_attribute : process_attribute_default { +/// Process an attribute which indicates that this is an overloaded function associated with a +/// given sibling +template <> +struct process_attribute : process_attribute_default { static void init(const sibling &s, function_record *r) { r->sibling = s.value; } }; /// Process an attribute which indicates that this function is a method -template <> struct process_attribute : process_attribute_default { - static void init(const is_method &s, function_record *r) { r->is_method = true; r->scope = s.class_; } +template <> +struct process_attribute : process_attribute_default { + static void init(const is_method &s, function_record *r) { + r->is_method = true; + r->scope = s.class_; + } }; /// Process an attribute which indicates the parent scope of a method -template <> struct process_attribute : process_attribute_default { +template <> +struct process_attribute : process_attribute_default { static void init(const scope &s, function_record *r) { r->scope = s.value; } }; /// Process an attribute which indicates that this function is an operator -template <> struct process_attribute : process_attribute_default { +template <> +struct process_attribute : process_attribute_default { static void init(const is_operator &, function_record *r) { r->is_operator = true; } }; -template <> struct process_attribute : process_attribute_default { - static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = true; } +template <> +struct process_attribute + : process_attribute_default { + static void init(const is_new_style_constructor &, function_record *r) { + r->is_new_style_constructor = true; + } }; -inline void process_kw_only_arg(const arg &a, function_record *r) { - if (!a.name || a.name[0] == '\0') - pybind11_fail("arg(): cannot specify an unnamed argument after an kw_only() annotation"); - ++r->nargs_kw_only; +inline void check_kw_only_arg(const arg &a, function_record *r) { + if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\0')) { + pybind11_fail("arg(): cannot specify an unnamed argument after a kw_only() annotation or " + "args() argument"); + } +} + +inline void append_self_arg_if_needed(function_record *r) { + if (r->is_method && r->args.empty()) { + r->args.emplace_back("self", nullptr, handle(), /*convert=*/true, /*none=*/false); + } } /// Process a keyword argument attribute (*without* a default value) -template <> struct process_attribute : process_attribute_default { +template <> +struct process_attribute : process_attribute_default { static void init(const arg &a, function_record *r) { - if (r->is_method && r->args.empty()) - r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/); + append_self_arg_if_needed(r); r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); - if (r->has_kw_only_args) process_kw_only_arg(a, r); + check_kw_only_arg(a, r); } }; /// Process a keyword argument attribute (*with* a default value) -template <> struct process_attribute : process_attribute_default { +template <> +struct process_attribute : process_attribute_default { static void init(const arg_v &a, function_record *r) { - if (r->is_method && r->args.empty()) - r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/); + if (r->is_method && r->args.empty()) { + r->args.emplace_back( + "self", /*descr=*/nullptr, /*parent=*/handle(), /*convert=*/true, /*none=*/false); + } if (!a.value) { #if !defined(NDEBUG) std::string descr("'"); - if (a.name) descr += std::string(a.name) + ": "; + if (a.name) { + descr += std::string(a.name) + ": "; + } descr += a.type + "'"; if (r->is_method) { - if (r->name) - descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'"; - else + if (r->name) { + descr += " in method '" + (std::string) str(r->scope) + "." + + (std::string) r->name + "'"; + } else { descr += " in method of '" + (std::string) str(r->scope) + "'"; + } } else if (r->name) { descr += " in function '" + (std::string) r->name + "'"; } - pybind11_fail("arg(): could not convert default argument " - + descr + " into a Python object (type not registered yet?)"); + pybind11_fail("arg(): could not convert default argument " + descr + + " into a Python object (type not registered yet?)"); #else pybind11_fail("arg(): could not convert default argument " "into a Python object (type not registered yet?). " @@ -457,27 +504,41 @@ template <> struct process_attribute : process_attribute_default { } r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); - if (r->has_kw_only_args) process_kw_only_arg(a, r); + check_kw_only_arg(a, r); } }; /// Process a keyword-only-arguments-follow pseudo argument -template <> struct process_attribute : process_attribute_default { +template <> +struct process_attribute : process_attribute_default { static void init(const kw_only &, function_record *r) { - r->has_kw_only_args = true; + append_self_arg_if_needed(r); + if (r->has_args && r->nargs_pos != static_cast(r->args.size())) { + pybind11_fail("Mismatched args() and kw_only(): they must occur at the same relative " + "argument location (or omit kw_only() entirely)"); + } + r->nargs_pos = static_cast(r->args.size()); } }; /// Process a positional-only-argument maker -template <> struct process_attribute : process_attribute_default { +template <> +struct process_attribute : process_attribute_default { static void init(const pos_only &, function_record *r) { + append_self_arg_if_needed(r); r->nargs_pos_only = static_cast(r->args.size()); + if (r->nargs_pos_only > r->nargs_pos) { + pybind11_fail("pos_only(): cannot follow a py::args() argument"); + } + // It also can't follow a kw_only, but a static_assert in pybind11.h checks that } }; -/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that) +/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees +/// that) template -struct process_attribute::value>> : process_attribute_default { +struct process_attribute::value>> + : process_attribute_default { static void init(const handle &h, type_record *r) { r->bases.append(h); } }; @@ -490,7 +551,9 @@ struct process_attribute> : process_attribute_default> { /// Process a multiple inheritance attribute template <> struct process_attribute : process_attribute_default { - static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; } + static void init(const multiple_inheritance &, type_record *r) { + r->multiple_inheritance = true; + } }; template <> @@ -536,34 +599,41 @@ template <> struct process_attribute : process_attribute_default {}; template -struct process_attribute> : process_attribute_default> { }; +struct process_attribute> : process_attribute_default> {}; /** * Process a keep_alive call policy -- invokes keep_alive_impl during the * pre-call handler if both Nurse, Patient != 0 and use the post-call handler * otherwise */ -template struct process_attribute> : public process_attribute_default> { +template +struct process_attribute> + : public process_attribute_default> { template = 0> - static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); } + static void precall(function_call &call) { + keep_alive_impl(Nurse, Patient, call, handle()); + } template = 0> - static void postcall(function_call &, handle) { } + static void postcall(function_call &, handle) {} template = 0> - static void precall(function_call &) { } + static void precall(function_call &) {} template = 0> - static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); } + static void postcall(function_call &call, handle ret) { + keep_alive_impl(Nurse, Patient, call, ret); + } }; /// Recursively iterate over variadic template arguments -template struct process_attributes { - static void init(const Args&... args, function_record *r) { +template +struct process_attributes { + static void init(const Args &...args, function_record *r) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r); PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r); using expander = int[]; (void) expander{ 0, ((void) process_attribute::type>::init(args, r), 0)...}; } - static void init(const Args&... args, type_record *r) { + static void init(const Args &...args, type_record *r) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r); PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r); using expander = int[]; @@ -595,7 +665,7 @@ using extract_guard_t = typename exactly_one_t, Extr /// Check the number of named arguments at compile time template ::value...), - size_t self = constexpr_sum(std::is_same::value...)> + size_t self = constexpr_sum(std::is_same::value...)> constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) { PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(nargs, has_args, has_kwargs); return named == 0 || (self + named + size_t(has_args) + size_t(has_kwargs)) == nargs; diff --git a/pybind11/include/pybind11/buffer_info.h b/pybind11/include/pybind11/buffer_info.h index eba68d1..06120d5 100644 --- a/pybind11/include/pybind11/buffer_info.h +++ b/pybind11/include/pybind11/buffer_info.h @@ -19,9 +19,11 @@ PYBIND11_NAMESPACE_BEGIN(detail) inline std::vector c_strides(const std::vector &shape, ssize_t itemsize) { auto ndim = shape.size(); std::vector strides(ndim, itemsize); - if (ndim > 0) - for (size_t i = ndim - 1; i > 0; --i) + if (ndim > 0) { + for (size_t i = ndim - 1; i > 0; --i) { strides[i - 1] = strides[i] * shape[i]; + } + } return strides; } @@ -29,8 +31,9 @@ inline std::vector c_strides(const std::vector &shape, ssize_t inline std::vector f_strides(const std::vector &shape, ssize_t itemsize) { auto ndim = shape.size(); std::vector strides(ndim, itemsize); - for (size_t i = 1; i < ndim; ++i) + for (size_t i = 1; i < ndim; ++i) { strides[i] = strides[i - 1] * shape[i - 1]; + } return strides; } @@ -41,55 +44,85 @@ struct buffer_info { void *ptr = nullptr; // Pointer to the underlying storage ssize_t itemsize = 0; // Size of individual items in bytes ssize_t size = 0; // Total number of entries - std::string format; // For homogeneous buffers, this should be set to format_descriptor::format() + std::string format; // For homogeneous buffers, this should be set to + // format_descriptor::format() ssize_t ndim = 0; // Number of dimensions std::vector shape; // Shape of the tensor (1 entry per dimension) - std::vector strides; // Number of bytes between adjacent entries (for each per dimension) + std::vector strides; // Number of bytes between adjacent entries + // (for each per dimension) bool readonly = false; // flag to indicate if the underlying storage may be written to buffer_info() = default; - buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, - detail::any_container shape_in, detail::any_container strides_in, bool readonly=false) - : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), - shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) { - if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) + buffer_info(void *ptr, + ssize_t itemsize, + const std::string &format, + ssize_t ndim, + detail::any_container shape_in, + detail::any_container strides_in, + bool readonly = false) + : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), + shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) { + if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) { pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); - for (size_t i = 0; i < (size_t) ndim; ++i) + } + for (size_t i = 0; i < (size_t) ndim; ++i) { size *= shape[i]; + } } template - buffer_info(T *ptr, detail::any_container shape_in, detail::any_container strides_in, bool readonly=false) - : buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor::format(), static_cast(shape_in->size()), std::move(shape_in), std::move(strides_in), readonly) { } - - buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size, bool readonly=false) - : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) { } + buffer_info(T *ptr, + detail::any_container shape_in, + detail::any_container strides_in, + bool readonly = false) + : buffer_info(private_ctr_tag(), + ptr, + sizeof(T), + format_descriptor::format(), + static_cast(shape_in->size()), + std::move(shape_in), + std::move(strides_in), + readonly) {} + + buffer_info(void *ptr, + ssize_t itemsize, + const std::string &format, + ssize_t size, + bool readonly = false) + : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) {} template - buffer_info(T *ptr, ssize_t size, bool readonly=false) - : buffer_info(ptr, sizeof(T), format_descriptor::format(), size, readonly) { } + buffer_info(T *ptr, ssize_t size, bool readonly = false) + : buffer_info(ptr, sizeof(T), format_descriptor::format(), size, readonly) {} template - buffer_info(const T *ptr, ssize_t size, bool readonly=true) - : buffer_info(const_cast(ptr), sizeof(T), format_descriptor::format(), size, readonly) { } + buffer_info(const T *ptr, ssize_t size, bool readonly = true) + : buffer_info( + const_cast(ptr), sizeof(T), format_descriptor::format(), size, readonly) {} explicit buffer_info(Py_buffer *view, bool ownview = true) - : buffer_info(view->buf, view->itemsize, view->format, view->ndim, + : buffer_info( + view->buf, + view->itemsize, + view->format, + view->ndim, {view->shape, view->shape + view->ndim}, /* Though buffer::request() requests PyBUF_STRIDES, ctypes objects * ignore this flag and return a view with NULL strides. * When strides are NULL, build them manually. */ view->strides - ? std::vector(view->strides, view->strides + view->ndim) - : detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize), + ? std::vector(view->strides, view->strides + view->ndim) + : detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize), (view->readonly != 0)) { + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) this->m_view = view; + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) this->ownview = ownview; } buffer_info(const buffer_info &) = delete; - buffer_info& operator=(const buffer_info &) = delete; + buffer_info &operator=(const buffer_info &) = delete; buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); } @@ -108,17 +141,28 @@ struct buffer_info { } ~buffer_info() { - if (m_view && ownview) { PyBuffer_Release(m_view); delete m_view; } + if (m_view && ownview) { + PyBuffer_Release(m_view); + delete m_view; + } } Py_buffer *view() const { return m_view; } Py_buffer *&view() { return m_view; } -private: - struct private_ctr_tag { }; - buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, - detail::any_container &&shape_in, detail::any_container &&strides_in, bool readonly) - : buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) { } +private: + struct private_ctr_tag {}; + + buffer_info(private_ctr_tag, + void *ptr, + ssize_t itemsize, + const std::string &format, + ssize_t ndim, + detail::any_container &&shape_in, + detail::any_container &&strides_in, + bool readonly) + : buffer_info( + ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {} Py_buffer *m_view = nullptr; bool ownview = false; @@ -126,17 +170,22 @@ struct buffer_info { PYBIND11_NAMESPACE_BEGIN(detail) -template struct compare_buffer_info { - static bool compare(const buffer_info& b) { +template +struct compare_buffer_info { + static bool compare(const buffer_info &b) { return b.format == format_descriptor::format() && b.itemsize == (ssize_t) sizeof(T); } }; -template struct compare_buffer_info::value>> { - static bool compare(const buffer_info& b) { - return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor::value || - ((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned::value ? "L" : "l")) || - ((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned::value ? "N" : "n"))); +template +struct compare_buffer_info::value>> { + static bool compare(const buffer_info &b) { + return (size_t) b.itemsize == sizeof(T) + && (b.format == format_descriptor::value + || ((sizeof(T) == sizeof(long)) + && b.format == (std::is_unsigned::value ? "L" : "l")) + || ((sizeof(T) == sizeof(size_t)) + && b.format == (std::is_unsigned::value ? "N" : "n"))); } }; diff --git a/pybind11/include/pybind11/cast.h b/pybind11/include/pybind11/cast.h index 1ec2080..5b7fb24 100644 --- a/pybind11/include/pybind11/cast.h +++ b/pybind11/include/pybind11/cast.h @@ -10,11 +10,12 @@ #pragma once -#include "pytypes.h" #include "detail/common.h" #include "detail/descr.h" #include "detail/type_caster_base.h" #include "detail/typeid.h" +#include "pytypes.h" + #include #include #include @@ -27,61 +28,54 @@ #include #include -#if defined(PYBIND11_CPP17) -# if defined(__has_include) -# if __has_include() -# define PYBIND11_HAS_STRING_VIEW -# endif -# elif defined(_MSC_VER) -# define PYBIND11_HAS_STRING_VIEW -# endif -#endif -#ifdef PYBIND11_HAS_STRING_VIEW -#include -#endif - -#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L -# define PYBIND11_HAS_U8STRING -#endif - PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) -template class type_caster : public type_caster_base { }; -template using make_caster = type_caster>; +template +class type_caster : public type_caster_base {}; +template +using make_caster = type_caster>; // Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T -template typename make_caster::template cast_op_type cast_op(make_caster &caster) { +template +typename make_caster::template cast_op_type cast_op(make_caster &caster) { return caster.operator typename make_caster::template cast_op_type(); } -template typename make_caster::template cast_op_type::type> +template +typename make_caster::template cast_op_type::type> cast_op(make_caster &&caster) { - return std::move(caster).operator - typename make_caster::template cast_op_type::type>(); + return std::move(caster).operator typename make_caster:: + template cast_op_type::type>(); } -template class type_caster> { +template +class type_caster> { private: using caster_t = make_caster; caster_t subcaster; - using reference_t = type&; - using subcaster_cast_op_type = - typename caster_t::template cast_op_type; - - static_assert(std::is_same::type &, subcaster_cast_op_type>::value || - std::is_same::value, - "std::reference_wrapper caster requires T to have a caster with an " - "`operator T &()` or `operator const T &()`"); + using reference_t = type &; + using subcaster_cast_op_type = typename caster_t::template cast_op_type; + + static_assert( + std::is_same::type &, subcaster_cast_op_type>::value + || std::is_same::value, + "std::reference_wrapper caster requires T to have a caster with an " + "`operator T &()` or `operator const T &()`"); + public: bool load(handle src, bool convert) { return subcaster.load(src, convert); } static constexpr auto name = caster_t::name; - static handle cast(const std::reference_wrapper &src, return_value_policy policy, handle parent) { + static handle + cast(const std::reference_wrapper &src, return_value_policy policy, handle parent) { // It is definitely wrong to take ownership of this pointer, so mask that rvp - if (policy == return_value_policy::take_ownership || policy == return_value_policy::automatic) + if (policy == return_value_policy::take_ownership + || policy == return_value_policy::automatic) { policy = return_value_policy::automatic_reference; + } return caster_t::cast(&src.get(), policy, parent); } - template using cast_op_type = std::reference_wrapper; + template + using cast_op_type = std::reference_wrapper; explicit operator std::reference_wrapper() { return cast_op(subcaster); } }; @@ -91,11 +85,15 @@ protected: \ public: \ static constexpr auto name = py_name; \ - template >::value, int> = 0> \ - static handle cast(T_ *src, return_value_policy policy, handle parent) { \ + template >::value, \ + int> = 0> \ + static ::pybind11::handle cast( \ + T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) { \ if (!src) \ - return none().release(); \ - if (policy == return_value_policy::take_ownership) { \ + return ::pybind11::none().release(); \ + if (policy == ::pybind11::return_value_policy::take_ownership) { \ auto h = cast(std::move(*src), policy, parent); \ delete src; \ return h; \ @@ -106,31 +104,33 @@ public: operator type &() { return value; } /* NOLINT(bugprone-macro-parentheses) */ \ operator type &&() && { return std::move(value); } /* NOLINT(bugprone-macro-parentheses) */ \ template \ - using cast_op_type = pybind11::detail::movable_cast_op_type + using cast_op_type = ::pybind11::detail::movable_cast_op_type -template using is_std_char_type = any_of< - std::is_same, /* std::string */ +template +using is_std_char_type = any_of, /* std::string */ #if defined(PYBIND11_HAS_U8STRING) - std::is_same, /* std::u8string */ + std::is_same, /* std::u8string */ #endif - std::is_same, /* std::u16string */ - std::is_same, /* std::u32string */ - std::is_same /* std::wstring */ ->; - + std::is_same, /* std::u16string */ + std::is_same, /* std::u32string */ + std::is_same /* std::wstring */ + >; template struct type_caster::value && !is_std_char_type::value>> { using _py_type_0 = conditional_t; - using _py_type_1 = conditional_t::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>; + using _py_type_1 = conditional_t::value, + _py_type_0, + typename std::make_unsigned<_py_type_0>::type>; using py_type = conditional_t::value, double, _py_type_1>; -public: +public: bool load(handle src, bool convert) { py_type py_value; - if (!src) + if (!src) { return false; + } #if !defined(PYPY_VERSION) auto index_check = [](PyObject *o) { return PyIndex_Check(o); }; @@ -141,25 +141,26 @@ struct type_caster::value && !is_std_char_t #endif if (std::is_floating_point::value) { - if (convert || PyFloat_Check(src.ptr())) + if (convert || PyFloat_Check(src.ptr())) { py_value = (py_type) PyFloat_AsDouble(src.ptr()); - else + } else { return false; + } } else if (PyFloat_Check(src.ptr()) || (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) { return false; } else { handle src_or_index = src; -#if PY_VERSION_HEX < 0x03080000 + // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls. +#if PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION) object index; - if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr()) + if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr()) index = reinterpret_steal(PyNumber_Index(src.ptr())); if (!index) { PyErr_Clear(); if (!convert) return false; - } - else { + } else { src_or_index = index; } } @@ -168,8 +169,8 @@ struct type_caster::value && !is_std_char_t py_value = as_unsigned(src_or_index.ptr()); } else { // signed integer: py_value = sizeof(T) <= sizeof(long) - ? (py_type) PyLong_AsLong(src_or_index.ptr()) - : (py_type) PYBIND11_LONG_AS_LONGLONG(src_or_index.ptr()); + ? (py_type) PyLong_AsLong(src_or_index.ptr()) + : (py_type) PYBIND11_LONG_AS_LONGLONG(src_or_index.ptr()); } } @@ -178,12 +179,14 @@ struct type_caster::value && !is_std_char_t // Check to see if the conversion is valid (integers should match exactly) // Signed/unsigned checks happen elsewhere - if (py_err || (std::is_integral::value && sizeof(py_type) != sizeof(T) && py_value != (py_type) (T) py_value)) { + if (py_err + || (std::is_integral::value && sizeof(py_type) != sizeof(T) + && py_value != (py_type) (T) py_value)) { PyErr_Clear(); if (py_err && convert && (PyNumber_Check(src.ptr()) != 0)) { auto tmp = reinterpret_steal(std::is_floating_point::value - ? PyNumber_Float(src.ptr()) - : PyNumber_Long(src.ptr())); + ? PyNumber_Float(src.ptr()) + : PyNumber_Long(src.ptr())); PyErr_Clear(); return load(tmp, false); } @@ -194,55 +197,67 @@ struct type_caster::value && !is_std_char_t return true; } - template + template static typename std::enable_if::value, handle>::type cast(U src, return_value_policy /* policy */, handle /* parent */) { return PyFloat_FromDouble((double) src); } - template - static typename std::enable_if::value && std::is_signed::value && (sizeof(U) <= sizeof(long)), handle>::type + template + static typename std::enable_if::value && std::is_signed::value + && (sizeof(U) <= sizeof(long)), + handle>::type cast(U src, return_value_policy /* policy */, handle /* parent */) { return PYBIND11_LONG_FROM_SIGNED((long) src); } - template - static typename std::enable_if::value && std::is_unsigned::value && (sizeof(U) <= sizeof(unsigned long)), handle>::type + template + static typename std::enable_if::value && std::is_unsigned::value + && (sizeof(U) <= sizeof(unsigned long)), + handle>::type cast(U src, return_value_policy /* policy */, handle /* parent */) { return PYBIND11_LONG_FROM_UNSIGNED((unsigned long) src); } - template - static typename std::enable_if::value && std::is_signed::value && (sizeof(U) > sizeof(long)), handle>::type + template + static typename std::enable_if::value && std::is_signed::value + && (sizeof(U) > sizeof(long)), + handle>::type cast(U src, return_value_policy /* policy */, handle /* parent */) { return PyLong_FromLongLong((long long) src); } - template - static typename std::enable_if::value && std::is_unsigned::value && (sizeof(U) > sizeof(unsigned long)), handle>::type + template + static typename std::enable_if::value && std::is_unsigned::value + && (sizeof(U) > sizeof(unsigned long)), + handle>::type cast(U src, return_value_policy /* policy */, handle /* parent */) { return PyLong_FromUnsignedLongLong((unsigned long long) src); } - PYBIND11_TYPE_CASTER(T, _::value>("int", "float")); + PYBIND11_TYPE_CASTER(T, const_name::value>("int", "float")); }; -template struct void_caster { +template +struct void_caster { public: bool load(handle src, bool) { - if (src && src.is_none()) + if (src && src.is_none()) { return true; + } return false; } static handle cast(T, return_value_policy /* policy */, handle /* parent */) { return none().inc_ref(); } - PYBIND11_TYPE_CASTER(T, _("None")); + PYBIND11_TYPE_CASTER(T, const_name("None")); }; -template <> class type_caster : public void_caster {}; +template <> +class type_caster : public void_caster {}; -template <> class type_caster : public type_caster { +template <> +class type_caster : public type_caster { public: using type_caster::cast; @@ -262,7 +277,7 @@ template <> class type_caster : public type_caster { } /* Check if this is a C++ type */ - auto &bases = all_type_info((PyTypeObject *) type::handle_of(h).ptr()); + const auto &bases = all_type_info((PyTypeObject *) type::handle_of(h).ptr()); if (bases.size() == 1) { // Only allowing loading from a single-value type value = values_and_holders(reinterpret_cast(h.ptr())).begin()->value_ptr(); return true; @@ -273,24 +288,31 @@ template <> class type_caster : public type_caster { } static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) { - if (ptr) + if (ptr) { return capsule(ptr).release(); + } return none().inc_ref(); } - template using cast_op_type = void*&; + template + using cast_op_type = void *&; explicit operator void *&() { return value; } - static constexpr auto name = _("capsule"); + static constexpr auto name = const_name("capsule"); + private: void *value = nullptr; }; -template <> class type_caster : public void_caster { }; +template <> +class type_caster : public void_caster {}; -template <> class type_caster { +template <> +class type_caster { public: bool load(handle src, bool convert) { - if (!src) return false; + if (!src) { + return false; + } if (src.ptr() == Py_True) { value = true; return true; @@ -304,22 +326,22 @@ template <> class type_caster { Py_ssize_t res = -1; if (src.is_none()) { - res = 0; // None is implicitly converted to False + res = 0; // None is implicitly converted to False } - #if defined(PYPY_VERSION) +#if defined(PYPY_VERSION) // On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr exists else if (hasattr(src, PYBIND11_BOOL_ATTR)) { res = PyObject_IsTrue(src.ptr()); } - #else +#else // Alternate approach for CPython: this does the same as the above, but optimized // using the CPython API so as to avoid an unneeded attribute lookup. - else if (auto tp_as_number = src.ptr()->ob_type->tp_as_number) { + else if (auto *tp_as_number = src.ptr()->ob_type->tp_as_number) { if (PYBIND11_NB_BOOL(tp_as_number)) { res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr()); } } - #endif +#endif if (res == 0 || res == 1) { value = (res != 0); return true; @@ -331,24 +353,29 @@ template <> class type_caster { static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) { return handle(src ? Py_True : Py_False).inc_ref(); } - PYBIND11_TYPE_CASTER(bool, _("bool")); + PYBIND11_TYPE_CASTER(bool, const_name("bool")); }; // Helper class for UTF-{8,16,32} C++ stl strings: -template struct string_caster { +template +struct string_caster { using CharT = typename StringType::value_type; // Simplify life by being able to assume standard char sizes (the standard only guarantees // minimums, but Python requires exact sizes) - static_assert(!std::is_same::value || sizeof(CharT) == 1, "Unsupported char size != 1"); + static_assert(!std::is_same::value || sizeof(CharT) == 1, + "Unsupported char size != 1"); #if defined(PYBIND11_HAS_U8STRING) - static_assert(!std::is_same::value || sizeof(CharT) == 1, "Unsupported char8_t size != 1"); + static_assert(!std::is_same::value || sizeof(CharT) == 1, + "Unsupported char8_t size != 1"); #endif - static_assert(!std::is_same::value || sizeof(CharT) == 2, "Unsupported char16_t size != 2"); - static_assert(!std::is_same::value || sizeof(CharT) == 4, "Unsupported char32_t size != 4"); + static_assert(!std::is_same::value || sizeof(CharT) == 2, + "Unsupported char16_t size != 2"); + static_assert(!std::is_same::value || sizeof(CharT) == 4, + "Unsupported char32_t size != 4"); // wchar_t can be either 16 bits (Windows) or 32 (everywhere else) static_assert(!std::is_same::value || sizeof(CharT) == 2 || sizeof(CharT) == 4, - "Unsupported wchar_t size != 2/4"); + "Unsupported wchar_t size != 2/4"); static constexpr size_t UTF_N = 8 * sizeof(CharT); bool load(handle src, bool) { @@ -372,7 +399,10 @@ template struct string_caster { return false; temp = reinterpret_steal(PyUnicode_FromObject(load_src.ptr())); - if (!temp) { PyErr_Clear(); return false; } + if (!temp) { + PyErr_Clear(); + return false; + } load_src = temp; #endif } @@ -393,11 +423,19 @@ template struct string_caster { } #endif - auto utfNbytes = reinterpret_steal(PyUnicode_AsEncodedString( - load_src.ptr(), UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr)); - if (!utfNbytes) { PyErr_Clear(); return false; } + auto utfNbytes + = reinterpret_steal(PyUnicode_AsEncodedString(load_src.ptr(), + UTF_N == 8 ? "utf-8" + : UTF_N == 16 ? "utf-16" + : "utf-32", + nullptr)); + if (!utfNbytes) { + PyErr_Clear(); + return false; + } - const auto *buffer = reinterpret_cast(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); + const auto *buffer + = reinterpret_cast(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT); // Skip BOM for UTF-16/32 if (PYBIND11_SILENCE_MSVC_C4127(UTF_N > 8)) { @@ -407,33 +445,42 @@ template struct string_caster { value = StringType(buffer, length); // If we're loading a string_view we need to keep the encoded Python object alive: - if (IsView) + if (IsView) { loader_life_support::add_patient(utfNbytes); + } return true; } - static handle cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) { + static handle + cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) { const char *buffer = reinterpret_cast(src.data()); auto nbytes = ssize_t(src.size() * sizeof(CharT)); handle s = decode_utfN(buffer, nbytes); - if (!s) throw error_already_set(); + if (!s) { + throw error_already_set(); + } return s; } - PYBIND11_TYPE_CASTER(StringType, _(PYBIND11_STRING_NAME)); + PYBIND11_TYPE_CASTER(StringType, const_name(PYBIND11_STRING_NAME)); private: static handle decode_utfN(const char *buffer, ssize_t nbytes) { #if !defined(PYPY_VERSION) - return - UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) : - UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) : - PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr); + return UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) + : UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) + : PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr); #else - // PyPy segfaults when on PyUnicode_DecodeUTF16 (and possibly on PyUnicode_DecodeUTF32 as well), - // so bypass the whole thing by just passing the encoding as a string value, which works properly: - return PyUnicode_Decode(buffer, nbytes, UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr); + // PyPy segfaults when on PyUnicode_DecodeUTF16 (and possibly on PyUnicode_DecodeUTF32 as + // well), so bypass the whole thing by just passing the encoding as a string value, which + // works properly: + return PyUnicode_Decode(buffer, + nbytes, + UTF_N == 8 ? "utf-8" + : UTF_N == 16 ? "utf-16" + : "utf-32", + nullptr); #endif } @@ -456,33 +503,43 @@ template struct string_caster { } template - bool load_bytes(enable_if_t::value, handle>) { return false; } + bool load_bytes(enable_if_t::value, handle>) { + return false; + } }; template -struct type_caster, enable_if_t::value>> +struct type_caster, + enable_if_t::value>> : string_caster> {}; #ifdef PYBIND11_HAS_STRING_VIEW template -struct type_caster, enable_if_t::value>> +struct type_caster, + enable_if_t::value>> : string_caster, true> {}; #endif // Type caster for C-style strings. We basically use a std::string type caster, but also add the // ability to use None as a nullptr char* (which the string caster doesn't allow). -template struct type_caster::value>> { +template +struct type_caster::value>> { using StringType = std::basic_string; using StringCaster = type_caster; StringCaster str_caster; bool none = false; CharT one_char = 0; + public: bool load(handle src, bool convert) { - if (!src) return false; + if (!src) { + return false; + } if (src.is_none()) { // Defer accepting None to other overloads (if we aren't in convert mode): - if (!convert) return false; + if (!convert) { + return false; + } none = true; return true; } @@ -490,14 +547,18 @@ template struct type_caster::value) { handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr); - if (!s) throw error_already_set(); + if (!s) { + throw error_already_set(); + } return s; } return StringCaster::cast(StringType(1, src), policy, parent); @@ -507,19 +568,21 @@ template struct type_caster(static_cast(str_caster).c_str()); } explicit operator CharT &() { - if (none) + if (none) { throw value_error("Cannot convert None to a character"); + } auto &value = static_cast(str_caster); size_t str_len = value.size(); - if (str_len == 0) + if (str_len == 0) { throw value_error("Cannot convert empty string to a character"); + } // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that - // is too high, and one for multiple unicode characters (caught later), so we need to figure - // out how long the first encoded character is in bytes to distinguish between these two - // errors. We also allow want to allow unicode characters U+0080 through U+00FF, as those - // can fit into a single char value. + // is too high, and one for multiple unicode characters (caught later), so we need to + // figure out how long the first encoded character is in bytes to distinguish between these + // two errors. We also allow want to allow unicode characters U+0080 through U+00FF, as + // those can fit into a single char value. if (PYBIND11_SILENCE_MSVC_C4127(StringCaster::UTF_N == 8) && str_len > 1 && str_len <= 4) { auto v0 = static_cast(value[0]); // low bits only: 0-127 @@ -534,7 +597,8 @@ template struct type_caster(((v0 & 3) << 6) + (static_cast(value[1]) & 0x3F)); + one_char = static_cast(((v0 & 3) << 6) + + (static_cast(value[1]) & 0x3F)); return one_char; } // Otherwise we have a single character, but it's > U+00FF @@ -547,34 +611,40 @@ template struct type_caster(value[0]); - if (one_char >= 0xD800 && one_char < 0xE000) + if (one_char >= 0xD800 && one_char < 0xE000) { throw value_error("Character code point not in range(0x10000)"); + } } - if (str_len != 1) + if (str_len != 1) { throw value_error("Expected a character, but multi-character string found"); + } one_char = value[0]; return one_char; } - static constexpr auto name = _(PYBIND11_STRING_NAME); - template using cast_op_type = pybind11::detail::cast_op_type<_T>; + static constexpr auto name = const_name(PYBIND11_STRING_NAME); + template + using cast_op_type = pybind11::detail::cast_op_type<_T>; }; // Base implementation for std::tuple and std::pair -template class Tuple, typename... Ts> class tuple_caster { +template