Merge pull request #1628 from borglab/python-updates
						commit
						3a1fe57468
					
				| 
						 | 
				
			
			@ -39,8 +39,6 @@ function install_dependencies()
 | 
			
		|||
  if [ "${GTSAM_WITH_TBB:-OFF}" == "ON" ]; then
 | 
			
		||||
    install_tbb
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  $PYTHON -m pip install -r $GITHUB_WORKSPACE/python/requirements.txt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function build()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -109,10 +109,13 @@ jobs:
 | 
			
		|||
        with:
 | 
			
		||||
          swap-size-gb: 6
 | 
			
		||||
 | 
			
		||||
      - name: Install Dependencies
 | 
			
		||||
      - name: Install System Dependencies
 | 
			
		||||
        run: |
 | 
			
		||||
          bash .github/scripts/python.sh -d
 | 
			
		||||
 | 
			
		||||
      - name: Install Python Dependencies
 | 
			
		||||
        run: python$PYTHON_VERSION -m pip install -r python/dev_requirements.txt
 | 
			
		||||
 | 
			
		||||
      - name: Build
 | 
			
		||||
        run: |
 | 
			
		||||
          bash .github/scripts/python.sh -b
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,9 +6,6 @@ FROM borglab/ubuntu-gtsam:bionic
 | 
			
		|||
# Install pip
 | 
			
		||||
RUN apt-get install -y python3-pip python3-dev
 | 
			
		||||
 | 
			
		||||
# Install python wrapper requirements
 | 
			
		||||
RUN python3 -m pip install -U -r /usr/src/gtsam/python/requirements.txt
 | 
			
		||||
 | 
			
		||||
# Run cmake again, now with python toolbox on
 | 
			
		||||
WORKDIR /usr/src/gtsam/build
 | 
			
		||||
RUN cmake \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
set(PROJECT_PYTHON_SOURCE_DIR ${PROJECT_SOURCE_DIR}/python)
 | 
			
		||||
set(GTSAM_PYTHON_BUILD_DIRECTORY ${PROJECT_BINARY_DIR}/python)
 | 
			
		||||
 | 
			
		||||
if (NOT GTSAM_BUILD_PYTHON)
 | 
			
		||||
| 
						 | 
				
			
			@ -6,11 +7,11 @@ endif()
 | 
			
		|||
 | 
			
		||||
# Generate setup.py.
 | 
			
		||||
file(READ "${PROJECT_SOURCE_DIR}/README.md" README_CONTENTS)
 | 
			
		||||
configure_file(${PROJECT_SOURCE_DIR}/python/setup.py.in
 | 
			
		||||
configure_file(${PROJECT_PYTHON_SOURCE_DIR}/setup.py.in
 | 
			
		||||
                ${GTSAM_PYTHON_BUILD_DIRECTORY}/setup.py)
 | 
			
		||||
 | 
			
		||||
# Supply MANIFEST.in for older versions of Python
 | 
			
		||||
file(COPY ${PROJECT_SOURCE_DIR}/python/MANIFEST.in
 | 
			
		||||
file(COPY ${PROJECT_PYTHON_SOURCE_DIR}/MANIFEST.in
 | 
			
		||||
     DESTINATION ${GTSAM_PYTHON_BUILD_DIRECTORY})
 | 
			
		||||
 | 
			
		||||
set(WRAP_BUILD_TYPE_POSTFIXES ${GTSAM_BUILD_TYPE_POSTFIXES})
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +100,7 @@ pybind_wrap(${GTSAM_PYTHON_TARGET} # target
 | 
			
		|||
            "gtsam" # module_name
 | 
			
		||||
            "gtsam" # top_namespace
 | 
			
		||||
            "${ignore}" # ignore_classes
 | 
			
		||||
            ${PROJECT_SOURCE_DIR}/python/gtsam/gtsam.tpl
 | 
			
		||||
            ${PROJECT_PYTHON_SOURCE_DIR}/gtsam/gtsam.tpl
 | 
			
		||||
            gtsam # libs
 | 
			
		||||
            "gtsam;gtsam_header" # dependencies
 | 
			
		||||
            ${GTSAM_ENABLE_BOOST_SERIALIZATION} # use_boost_serialization
 | 
			
		||||
| 
						 | 
				
			
			@ -178,7 +179,7 @@ if(GTSAM_UNSTABLE_BUILD_PYTHON)
 | 
			
		|||
            "gtsam_unstable" # module_name
 | 
			
		||||
            "gtsam" # top_namespace
 | 
			
		||||
            "${ignore}" # ignore_classes
 | 
			
		||||
            ${PROJECT_SOURCE_DIR}/python/gtsam_unstable/gtsam_unstable.tpl
 | 
			
		||||
            ${PROJECT_PYTHON_SOURCE_DIR}/gtsam_unstable/gtsam_unstable.tpl
 | 
			
		||||
            gtsam_unstable # libs
 | 
			
		||||
            "gtsam_unstable;gtsam_unstable_header" # dependencies
 | 
			
		||||
            ${GTSAM_ENABLE_BOOST_SERIALIZATION} # use_boost_serialization
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ For instructions on updating the version of the [wrap library](https://github.co
 | 
			
		|||
- This wrapper needs `pyparsing(>=2.4.2)`, and `numpy(>=1.11.0)`. These can be installed as follows:
 | 
			
		||||
 | 
			
		||||
  ```bash
 | 
			
		||||
  pip install -r <gtsam_folder>/python/requirements.txt
 | 
			
		||||
  pip install -r <gtsam_folder>/python/dev_requirements.txt
 | 
			
		||||
  ```
 | 
			
		||||
 | 
			
		||||
## Install
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
-r requirements.txt
 | 
			
		||||
pyparsing>=2.4.2
 | 
			
		||||
| 
						 | 
				
			
			@ -1,2 +1 @@
 | 
			
		|||
numpy>=1.11.0
 | 
			
		||||
pyparsing>=2.4.2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,19 +1,17 @@
 | 
			
		|||
"""Setup file to install the GTSAM package."""
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    from setuptools import setup, find_packages
 | 
			
		||||
except ImportError:
 | 
			
		||||
    from distutils.core import setup, find_packages
 | 
			
		||||
from setuptools import setup, find_namespace_packages
 | 
			
		||||
 | 
			
		||||
packages = find_packages(where=".")
 | 
			
		||||
packages = find_namespace_packages(
 | 
			
		||||
    where=".",
 | 
			
		||||
    exclude=('build', 'build.*', 'CMakeFiles', 'CMakeFiles.*',
 | 
			
		||||
             'gtsam.notebooks', '*.preamble', '*.specializations', 'dist'))
 | 
			
		||||
print("PACKAGES: ", packages)
 | 
			
		||||
 | 
			
		||||
package_data = {
 | 
			
		||||
    '': [
 | 
			
		||||
        "./*.so",
 | 
			
		||||
        "./*.dll",
 | 
			
		||||
        "Data/*"  # Add the data files to the package
 | 
			
		||||
        "Data/**/*"  # Add the data files in subdirectories
 | 
			
		||||
        "./*.dll"
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +39,6 @@ setup(
 | 
			
		|||
        'Operating System :: Microsoft :: Windows',
 | 
			
		||||
        'Operating System :: POSIX',
 | 
			
		||||
        'License :: OSI Approved :: BSD License',
 | 
			
		||||
        'Programming Language :: Python :: 2',
 | 
			
		||||
        'Programming Language :: Python :: 3',
 | 
			
		||||
    ],
 | 
			
		||||
    packages=packages,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,8 @@ __pycache__/
 | 
			
		|||
*dist*
 | 
			
		||||
*.egg-info
 | 
			
		||||
 | 
			
		||||
**/.DS_Store
 | 
			
		||||
 | 
			
		||||
# Files related to code coverage stats
 | 
			
		||||
**/.coverage
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,6 +63,8 @@ Checks: |
 | 
			
		|||
  -bugprone-unused-raii,
 | 
			
		||||
 | 
			
		||||
CheckOptions:
 | 
			
		||||
- key:             modernize-use-equals-default.IgnoreMacros
 | 
			
		||||
  value:           false
 | 
			
		||||
- key:             performance-for-range-copy.WarnOnAllAutoCopies
 | 
			
		||||
  value:           true
 | 
			
		||||
- key:             performance-inefficient-string-concatenation.StrictMode
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t>
 | 
			
		||||
    template <typename ThisT>
 | 
			
		||||
        auto &this_ = static_cast<ThisT &>(*this);
 | 
			
		||||
                if (load_impl<ThisT>(temp, false)) {
 | 
			
		||||
        ssize_t nd = 0;
 | 
			
		||||
        auto trivial = broadcast(buffers, nd, shape);
 | 
			
		||||
        auto ndim = (size_t) nd;
 | 
			
		||||
    int nd;
 | 
			
		||||
    ssize_t ndim() const { return detail::array_proxy(m_ptr)->nd; }
 | 
			
		||||
        using op = op_impl<id, ot, Base, L_type, R_type>;
 | 
			
		||||
template <op_id id, op_type ot, typename L, typename R>
 | 
			
		||||
    template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
 | 
			
		||||
    class_ &def(const detail::op_<id, ot, L, R> &op, const Extra &...extra) {
 | 
			
		||||
    class_ &def_cast(const detail::op_<id, ot, L, R> &op, const Extra &...extra) {
 | 
			
		||||
@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
 | 
			
		||||
struct IntStruct {
 | 
			
		||||
    explicit IntStruct(int v) : value(v){};
 | 
			
		||||
    ~IntStruct() { value = -value; }
 | 
			
		||||
    IntStruct(const IntStruct &) = default;
 | 
			
		||||
    IntStruct &operator=(const IntStruct &) = default;
 | 
			
		||||
    py::class_<IntStruct>(m, "IntStruct").def(py::init([](const int i) { return IntStruct(i); }));
 | 
			
		||||
    py::implicitly_convertible<int, IntStruct>();
 | 
			
		||||
    m.def("test", [](int expected, const IntStruct &in) {
 | 
			
		||||
        [](int expected, const IntStruct &in) {
 | 
			
		||||
| 
						 | 
				
			
			@ -235,8 +235,8 @@ directory inside your pybind11 git clone. Files will be modified in place,
 | 
			
		|||
so you can use git to monitor the changes.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
docker run --rm -v $PWD:/mounted_pybind11 -it silkeh/clang:13
 | 
			
		||||
apt-get update && apt-get install -y python3-dev python3-pytest
 | 
			
		||||
docker run --rm -v $PWD:/mounted_pybind11 -it silkeh/clang:15-bullseye
 | 
			
		||||
apt-get update && apt-get install -y git python3-dev python3-pytest
 | 
			
		||||
cmake -S /mounted_pybind11/ -B build -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);--use-color" -DDOWNLOAD_EIGEN=ON -DDOWNLOAD_CATCH=ON -DCMAKE_CXX_STANDARD=17
 | 
			
		||||
cmake --build build -j 2
 | 
			
		||||
```
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,8 @@ body:
 | 
			
		|||
  - type: markdown
 | 
			
		||||
    attributes:
 | 
			
		||||
      value: |
 | 
			
		||||
        Maintainers will only make a best effort to triage PRs. Please do your best to make the issue as easy to act on as possible, and only open if clearly a problem with pybind11 (ask first if unsure).
 | 
			
		||||
        Please do your best to make the issue as easy to act on as possible, and only submit here if there is clearly a problem with pybind11 (ask first if unsure). **Note that a reproducer in a PR is much more likely to get immediate attention.**
 | 
			
		||||
 | 
			
		||||
  - type: checkboxes
 | 
			
		||||
    id: steps
 | 
			
		||||
    attributes:
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +21,13 @@ body:
 | 
			
		|||
        - label: Consider asking first in the [Gitter chat room](https://gitter.im/pybind/Lobby) or in a [Discussion](https:/pybind/pybind11/discussions/new).
 | 
			
		||||
          required: false
 | 
			
		||||
 | 
			
		||||
  - type: input
 | 
			
		||||
    id: version
 | 
			
		||||
    attributes:
 | 
			
		||||
      label: What version (or hash if on master) of pybind11 are you using?
 | 
			
		||||
    validations:
 | 
			
		||||
      required: true
 | 
			
		||||
 | 
			
		||||
  - type: textarea
 | 
			
		||||
    id: description
 | 
			
		||||
    attributes:
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +48,14 @@ body:
 | 
			
		|||
        The code should be minimal, have no external dependencies, isolate the
 | 
			
		||||
        function(s) that cause breakage. Submit matched and complete C++ and
 | 
			
		||||
        Python snippets that can be easily compiled and run to diagnose the
 | 
			
		||||
        issue. If possible, make a PR with a new, failing test to give us a
 | 
			
		||||
        starting point to work on!
 | 
			
		||||
        issue. — Note that a reproducer in a PR is much more likely to get
 | 
			
		||||
        immediate attention: failing tests in the pybind11 CI are the best
 | 
			
		||||
        starting point for working out fixes.
 | 
			
		||||
      render: text
 | 
			
		||||
 | 
			
		||||
  - type: input
 | 
			
		||||
    id: regression
 | 
			
		||||
    attributes:
 | 
			
		||||
      label: Is this a regression? Put the last known working version here if it is.
 | 
			
		||||
      description: Put the last known working version here if this is a regression.
 | 
			
		||||
      value: Not a regression
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,14 +9,19 @@ on:
 | 
			
		|||
      - stable
 | 
			
		||||
      - v*
 | 
			
		||||
 | 
			
		||||
permissions: read-all
 | 
			
		||||
 | 
			
		||||
concurrency:
 | 
			
		||||
  group: test-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
env:
 | 
			
		||||
  PIP_BREAK_SYSTEM_PACKAGES: 1
 | 
			
		||||
  PIP_ONLY_BINARY: numpy
 | 
			
		||||
  FORCE_COLOR: 3
 | 
			
		||||
  PYTEST_TIMEOUT: 300
 | 
			
		||||
  # For cmake:
 | 
			
		||||
  VERBOSE: 1
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  # This is the "main" test suite, which tests a large number of different
 | 
			
		||||
| 
						 | 
				
			
			@ -25,15 +30,16 @@ jobs:
 | 
			
		|||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        runs-on: [ubuntu-latest, windows-2022, macos-latest]
 | 
			
		||||
        runs-on: [ubuntu-20.04, windows-2022, macos-latest]
 | 
			
		||||
        python:
 | 
			
		||||
        - '3.6'
 | 
			
		||||
        - '3.9'
 | 
			
		||||
        - '3.10'
 | 
			
		||||
        - '3.11-dev'
 | 
			
		||||
        - 'pypy-3.7'
 | 
			
		||||
        - '3.11'
 | 
			
		||||
        - '3.12'
 | 
			
		||||
        - 'pypy-3.8'
 | 
			
		||||
        - 'pypy-3.9'
 | 
			
		||||
        - 'pypy-3.10'
 | 
			
		||||
 | 
			
		||||
        # 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
 | 
			
		||||
| 
						 | 
				
			
			@ -42,12 +48,12 @@ jobs:
 | 
			
		|||
        # We support an optional key: args, for cmake args
 | 
			
		||||
        include:
 | 
			
		||||
          # Just add a key
 | 
			
		||||
          - runs-on: ubuntu-latest
 | 
			
		||||
          - runs-on: ubuntu-20.04
 | 
			
		||||
            python: '3.6'
 | 
			
		||||
            args: >
 | 
			
		||||
              -DPYBIND11_FINDPYTHON=ON
 | 
			
		||||
              -DCMAKE_CXX_FLAGS="-D_=1"
 | 
			
		||||
          - runs-on: ubuntu-latest
 | 
			
		||||
          - runs-on: ubuntu-20.04
 | 
			
		||||
            python: 'pypy-3.8'
 | 
			
		||||
            args: >
 | 
			
		||||
              -DPYBIND11_FINDPYTHON=ON
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +75,7 @@ jobs:
 | 
			
		|||
      uses: actions/setup-python@v4
 | 
			
		||||
      with:
 | 
			
		||||
        python-version: ${{ matrix.python }}
 | 
			
		||||
        allow-prereleases: true
 | 
			
		||||
 | 
			
		||||
    - name: Setup Boost (Linux)
 | 
			
		||||
      # Can't use boost + define _
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +87,7 @@ jobs:
 | 
			
		|||
      run: brew install boost
 | 
			
		||||
 | 
			
		||||
    - name: Update CMake
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.12
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.14
 | 
			
		||||
 | 
			
		||||
    - name: Cache wheels
 | 
			
		||||
      if: runner.os == 'macOS'
 | 
			
		||||
| 
						 | 
				
			
			@ -102,10 +109,12 @@ jobs:
 | 
			
		|||
      run: python -m pip install pytest-github-actions-annotate-failures
 | 
			
		||||
 | 
			
		||||
    # First build - C++11 mode and inplace
 | 
			
		||||
    # More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON here.
 | 
			
		||||
    - name: Configure C++11 ${{ matrix.args }}
 | 
			
		||||
      run: >
 | 
			
		||||
        cmake -S . -B .
 | 
			
		||||
        -DPYBIND11_WERROR=ON
 | 
			
		||||
        -DPYBIND11_SIMPLE_GIL_MANAGEMENT=ON
 | 
			
		||||
        -DDOWNLOAD_CATCH=ON
 | 
			
		||||
        -DDOWNLOAD_EIGEN=ON
 | 
			
		||||
        -DCMAKE_CXX_STANDARD=11
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +128,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' || matrix.python == '3.11-dev' || matrix.python == 'pypy-3.8'))"
 | 
			
		||||
      if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10' || matrix.python == '3.11' || matrix.python == 'pypy-3.8'))"
 | 
			
		||||
      run: cmake --build .  --target cpptest -j 2
 | 
			
		||||
 | 
			
		||||
    - name: Interface test C++11
 | 
			
		||||
| 
						 | 
				
			
			@ -129,10 +138,12 @@ jobs:
 | 
			
		|||
      run: git clean -fdx
 | 
			
		||||
 | 
			
		||||
    # Second build - C++17 mode and in a build directory
 | 
			
		||||
    # More-or-less randomly adding -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF here.
 | 
			
		||||
    - name: Configure C++17
 | 
			
		||||
      run: >
 | 
			
		||||
        cmake -S . -B build2
 | 
			
		||||
        -DPYBIND11_WERROR=ON
 | 
			
		||||
        -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
 | 
			
		||||
        -DDOWNLOAD_CATCH=ON
 | 
			
		||||
        -DDOWNLOAD_EIGEN=ON
 | 
			
		||||
        -DCMAKE_CXX_STANDARD=17
 | 
			
		||||
| 
						 | 
				
			
			@ -146,7 +157,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' || matrix.python == '3.11-dev' || matrix.python == 'pypy-3.8'))"
 | 
			
		||||
      if: "!(runner.os == 'Windows' && (matrix.python == 3.8 || matrix.python == 3.9 || matrix.python == '3.10' || matrix.python == '3.11' || matrix.python == 'pypy-3.8'))"
 | 
			
		||||
      run: cmake --build build2 --target cpptest
 | 
			
		||||
 | 
			
		||||
    # Third build - C++17 mode with unstable ABI
 | 
			
		||||
| 
						 | 
				
			
			@ -158,7 +169,6 @@ jobs:
 | 
			
		|||
        -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)
 | 
			
		||||
| 
						 | 
				
			
			@ -173,7 +183,9 @@ jobs:
 | 
			
		|||
    # This makes sure the setup_helpers module can build packages using
 | 
			
		||||
    # setuptools
 | 
			
		||||
    - name: Setuptools helpers test
 | 
			
		||||
      run: pytest tests/extra_setuptools
 | 
			
		||||
      run: |
 | 
			
		||||
        pip install setuptools
 | 
			
		||||
        pytest tests/extra_setuptools
 | 
			
		||||
      if: "!(matrix.runs-on == 'windows-2022')"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -186,23 +198,23 @@ jobs:
 | 
			
		|||
        - python-version: "3.9"
 | 
			
		||||
          python-debug: true
 | 
			
		||||
          valgrind: true
 | 
			
		||||
        - python-version: "3.11-dev"
 | 
			
		||||
        - python-version: "3.11"
 | 
			
		||||
          python-debug: false
 | 
			
		||||
 | 
			
		||||
    name: "🐍 ${{ matrix.python-version }}${{ matrix.python-debug && '-dbg' || '' }} (deadsnakes)${{ matrix.valgrind && ' • Valgrind' || '' }} • x64"
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    runs-on: ubuntu-20.04
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
    - name: Setup Python ${{ matrix.python-version }} (deadsnakes)
 | 
			
		||||
      uses: deadsnakes/action@v2.1.1
 | 
			
		||||
      uses: deadsnakes/action@v3.0.1
 | 
			
		||||
      with:
 | 
			
		||||
        python-version: ${{ matrix.python-version }}
 | 
			
		||||
        debug: ${{ matrix.python-debug }}
 | 
			
		||||
 | 
			
		||||
    - name: Update CMake
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.12
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.14
 | 
			
		||||
 | 
			
		||||
    - name: Valgrind cache
 | 
			
		||||
      if: matrix.valgrind
 | 
			
		||||
| 
						 | 
				
			
			@ -235,8 +247,6 @@ jobs:
 | 
			
		|||
        python -m pip install -r tests/requirements.txt
 | 
			
		||||
 | 
			
		||||
    - name: Configure
 | 
			
		||||
      env:
 | 
			
		||||
        SETUPTOOLS_USE_DISTUTILS: stdlib
 | 
			
		||||
      run: >
 | 
			
		||||
        cmake -S . -B build
 | 
			
		||||
        -DCMAKE_BUILD_TYPE=Debug
 | 
			
		||||
| 
						 | 
				
			
			@ -274,18 +284,27 @@ jobs:
 | 
			
		|||
          - dev
 | 
			
		||||
        std:
 | 
			
		||||
          - 11
 | 
			
		||||
        container_suffix:
 | 
			
		||||
          - ""
 | 
			
		||||
        include:
 | 
			
		||||
          - clang: 5
 | 
			
		||||
            std: 14
 | 
			
		||||
          - clang: 10
 | 
			
		||||
            std: 20
 | 
			
		||||
          - clang: 10
 | 
			
		||||
            std: 17
 | 
			
		||||
          - clang: 11
 | 
			
		||||
            std: 20
 | 
			
		||||
          - clang: 12
 | 
			
		||||
            std: 20
 | 
			
		||||
          - clang: 13
 | 
			
		||||
            std: 20
 | 
			
		||||
          - clang: 14
 | 
			
		||||
            std: 20
 | 
			
		||||
          - clang: 15
 | 
			
		||||
            std: 20
 | 
			
		||||
            container_suffix: "-bullseye"
 | 
			
		||||
 | 
			
		||||
    name: "🐍 3 • Clang ${{ matrix.clang }} • C++${{ matrix.std }} • x64"
 | 
			
		||||
    container: "silkeh/clang:${{ matrix.clang }}"
 | 
			
		||||
    container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}"
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
| 
						 | 
				
			
			@ -318,8 +337,8 @@ jobs:
 | 
			
		|||
  # Testing NVCC; forces sources to behave like .cu files
 | 
			
		||||
  cuda:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    name: "🐍 3.8 • CUDA 11.2 • Ubuntu 20.04"
 | 
			
		||||
    container: nvidia/cuda:11.2.2-devel-ubuntu20.04
 | 
			
		||||
    name: "🐍 3.10 • CUDA 12.2 • Ubuntu 22.04"
 | 
			
		||||
    container: nvidia/cuda:12.2.0-devel-ubuntu22.04
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
| 
						 | 
				
			
			@ -384,8 +403,9 @@ jobs:
 | 
			
		|||
 | 
			
		||||
  # Testing on CentOS 7 + PGI compilers, which seems to require more workarounds
 | 
			
		||||
  centos-nvhpc7:
 | 
			
		||||
    if: ${{ false }}  # JOB DISABLED (NEEDS WORK): https://github.com/pybind/pybind11/issues/4690
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    name: "🐍 3 • CentOS7 / PGI 22.3 • x64"
 | 
			
		||||
    name: "🐍 3 • CentOS7 / PGI 22.9 • x64"
 | 
			
		||||
    container: centos:7
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
| 
						 | 
				
			
			@ -395,7 +415,7 @@ jobs:
 | 
			
		|||
      run: yum update -y && yum install -y epel-release && yum install -y git python3-devel make environment-modules cmake3 yum-utils
 | 
			
		||||
 | 
			
		||||
    - name: Install NVidia HPC SDK
 | 
			
		||||
      run: yum-config-manager --add-repo https://developer.download.nvidia.com/hpc-sdk/rhel/nvhpc.repo && yum -y install nvhpc-22.3
 | 
			
		||||
      run: yum-config-manager --add-repo https://developer.download.nvidia.com/hpc-sdk/rhel/nvhpc.repo && yum -y install nvhpc-22.9
 | 
			
		||||
 | 
			
		||||
    # On CentOS 7, we have to filter a few tests (compiler internal error)
 | 
			
		||||
    # and allow deeper template recursion (not needed on CentOS 8 with a newer
 | 
			
		||||
| 
						 | 
				
			
			@ -405,12 +425,12 @@ jobs:
 | 
			
		|||
      shell: bash
 | 
			
		||||
      run: |
 | 
			
		||||
        source /etc/profile.d/modules.sh
 | 
			
		||||
        module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/22.3
 | 
			
		||||
        module load /opt/nvidia/hpc_sdk/modulefiles/nvhpc/22.9
 | 
			
		||||
        cmake3 -S . -B build -DDOWNLOAD_CATCH=ON \
 | 
			
		||||
                            -DCMAKE_CXX_STANDARD=11 \
 | 
			
		||||
                            -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \
 | 
			
		||||
                            -DCMAKE_CXX_FLAGS="-Wc,--pending_instantiations=0" \
 | 
			
		||||
                            -DPYBIND11_TEST_FILTER="test_smart_ptr.cpp;test_virtual_functions.cpp"
 | 
			
		||||
                            -DPYBIND11_TEST_FILTER="test_smart_ptr.cpp"
 | 
			
		||||
 | 
			
		||||
    # Building before installing Pip should produce a warning but not an error
 | 
			
		||||
    - name: Build
 | 
			
		||||
| 
						 | 
				
			
			@ -437,14 +457,14 @@ jobs:
 | 
			
		|||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        gcc:
 | 
			
		||||
          - 7
 | 
			
		||||
          - latest
 | 
			
		||||
        std:
 | 
			
		||||
          - 11
 | 
			
		||||
        include:
 | 
			
		||||
          - gcc: 10
 | 
			
		||||
            std: 20
 | 
			
		||||
          - { gcc: 7, std: 11 }
 | 
			
		||||
          - { gcc: 7, std: 17 }
 | 
			
		||||
          - { gcc: 8, std: 14 }
 | 
			
		||||
          - { gcc: 8, std: 17 }
 | 
			
		||||
          - { gcc: 10, std: 17 }
 | 
			
		||||
          - { gcc: 11, std: 20 }
 | 
			
		||||
          - { gcc: 12, std: 20 }
 | 
			
		||||
 | 
			
		||||
    name: "🐍 3 • GCC ${{ matrix.gcc }} • C++${{ matrix.std }}• x64"
 | 
			
		||||
    container: "gcc:${{ matrix.gcc }}"
 | 
			
		||||
| 
						 | 
				
			
			@ -459,7 +479,7 @@ jobs:
 | 
			
		|||
      run: python3 -m pip install --upgrade pip
 | 
			
		||||
 | 
			
		||||
    - name: Update CMake
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.12
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.14
 | 
			
		||||
 | 
			
		||||
    - name: Configure
 | 
			
		||||
      shell: bash
 | 
			
		||||
| 
						 | 
				
			
			@ -482,6 +502,24 @@ jobs:
 | 
			
		|||
    - name: Interface test
 | 
			
		||||
      run: cmake --build build --target test_cmake_build
 | 
			
		||||
 | 
			
		||||
    - name: Configure - Exercise cmake -DPYBIND11_TEST_OVERRIDE
 | 
			
		||||
      if: matrix.gcc == '12'
 | 
			
		||||
      shell: bash
 | 
			
		||||
      run: >
 | 
			
		||||
        cmake -S . -B build_partial
 | 
			
		||||
        -DPYBIND11_WERROR=ON
 | 
			
		||||
        -DDOWNLOAD_CATCH=ON
 | 
			
		||||
        -DCMAKE_CXX_STANDARD=${{ matrix.std }}
 | 
			
		||||
        -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
 | 
			
		||||
        "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp"
 | 
			
		||||
 | 
			
		||||
    - name: Build - Exercise cmake -DPYBIND11_TEST_OVERRIDE
 | 
			
		||||
      if: matrix.gcc == '12'
 | 
			
		||||
      run: cmake --build build_partial -j 2
 | 
			
		||||
 | 
			
		||||
    - name: Python tests - Exercise cmake -DPYBIND11_TEST_OVERRIDE
 | 
			
		||||
      if: matrix.gcc == '12'
 | 
			
		||||
      run: cmake --build build_partial --target pytest
 | 
			
		||||
 | 
			
		||||
  # Testing on ICC using the oneAPI apt repo
 | 
			
		||||
  icc:
 | 
			
		||||
| 
						 | 
				
			
			@ -731,6 +769,9 @@ jobs:
 | 
			
		|||
            args: -DCMAKE_CXX_STANDARD=20
 | 
			
		||||
          - python: 3.8
 | 
			
		||||
            args: -DCMAKE_CXX_STANDARD=17
 | 
			
		||||
          - python: 3.7
 | 
			
		||||
            args: -DCMAKE_CXX_STANDARD=14
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    name: "🐍 ${{ matrix.python }} • MSVC 2019 • x86 ${{ matrix.args }}"
 | 
			
		||||
    runs-on: windows-2019
 | 
			
		||||
| 
						 | 
				
			
			@ -745,10 +786,10 @@ jobs:
 | 
			
		|||
        architecture: x86
 | 
			
		||||
 | 
			
		||||
    - name: Update CMake
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.12
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.14
 | 
			
		||||
 | 
			
		||||
    - name: Prepare MSVC
 | 
			
		||||
      uses: ilammy/msvc-dev-cmd@v1.10.0
 | 
			
		||||
      uses: ilammy/msvc-dev-cmd@v1.12.1
 | 
			
		||||
      with:
 | 
			
		||||
        arch: x86
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -798,10 +839,10 @@ jobs:
 | 
			
		|||
        architecture: x86
 | 
			
		||||
 | 
			
		||||
    - name: Update CMake
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.12
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.14
 | 
			
		||||
 | 
			
		||||
    - name: Prepare MSVC
 | 
			
		||||
      uses: ilammy/msvc-dev-cmd@v1.10.0
 | 
			
		||||
      uses: ilammy/msvc-dev-cmd@v1.12.1
 | 
			
		||||
      with:
 | 
			
		||||
        arch: x86
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -849,7 +890,7 @@ jobs:
 | 
			
		|||
        python3 -m pip install -r tests/requirements.txt
 | 
			
		||||
 | 
			
		||||
    - name: Update CMake
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.12
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.14
 | 
			
		||||
 | 
			
		||||
    - name: Configure C++20
 | 
			
		||||
      run: >
 | 
			
		||||
| 
						 | 
				
			
			@ -871,6 +912,21 @@ jobs:
 | 
			
		|||
    - name: Interface test C++20
 | 
			
		||||
      run: cmake --build build --target test_cmake_build
 | 
			
		||||
 | 
			
		||||
    - name: Configure C++20 - Exercise cmake -DPYBIND11_TEST_OVERRIDE
 | 
			
		||||
      run: >
 | 
			
		||||
        cmake -S . -B build_partial
 | 
			
		||||
        -DPYBIND11_WERROR=ON
 | 
			
		||||
        -DDOWNLOAD_CATCH=ON
 | 
			
		||||
        -DDOWNLOAD_EIGEN=ON
 | 
			
		||||
        -DCMAKE_CXX_STANDARD=20
 | 
			
		||||
        "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp"
 | 
			
		||||
 | 
			
		||||
    - name: Build C++20 - Exercise cmake -DPYBIND11_TEST_OVERRIDE
 | 
			
		||||
      run: cmake --build build_partial -j 2
 | 
			
		||||
 | 
			
		||||
    - name: Python tests - Exercise cmake -DPYBIND11_TEST_OVERRIDE
 | 
			
		||||
      run: cmake --build build_partial --target pytest
 | 
			
		||||
 | 
			
		||||
  mingw:
 | 
			
		||||
    name: "🐍 3 • windows-latest • ${{ matrix.sys }}"
 | 
			
		||||
    runs-on: windows-latest
 | 
			
		||||
| 
						 | 
				
			
			@ -905,7 +961,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 -DDOWNLOAD_CATCH=ON -S . -B build
 | 
			
		||||
      run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=11 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build
 | 
			
		||||
 | 
			
		||||
    - name: Build C++11
 | 
			
		||||
      run: cmake --build build -j 2
 | 
			
		||||
| 
						 | 
				
			
			@ -923,7 +979,7 @@ jobs:
 | 
			
		|||
      run: git clean -fdx
 | 
			
		||||
 | 
			
		||||
    - name: Configure C++14
 | 
			
		||||
      run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -DDOWNLOAD_CATCH=ON -S . -B build2
 | 
			
		||||
      run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=14 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build2
 | 
			
		||||
 | 
			
		||||
    - name: Build C++14
 | 
			
		||||
      run: cmake --build build2 -j 2
 | 
			
		||||
| 
						 | 
				
			
			@ -941,7 +997,7 @@ jobs:
 | 
			
		|||
      run: git clean -fdx
 | 
			
		||||
 | 
			
		||||
    - name: Configure C++17
 | 
			
		||||
      run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DDOWNLOAD_CATCH=ON -S . -B build3
 | 
			
		||||
      run: cmake -G "MinGW Makefiles" -DCMAKE_CXX_STANDARD=17 -DPYBIND11_WERROR=ON -DDOWNLOAD_CATCH=ON -S . -B build3
 | 
			
		||||
 | 
			
		||||
    - name: Build C++17
 | 
			
		||||
      run: cmake --build build3 -j 2
 | 
			
		||||
| 
						 | 
				
			
			@ -954,3 +1010,156 @@ jobs:
 | 
			
		|||
 | 
			
		||||
    - name: Interface test C++17
 | 
			
		||||
      run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target test_cmake_build
 | 
			
		||||
 | 
			
		||||
  windows_clang:
 | 
			
		||||
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        os: [windows-latest]
 | 
			
		||||
        python: ['3.10']
 | 
			
		||||
 | 
			
		||||
    runs-on: "${{ matrix.os }}"
 | 
			
		||||
 | 
			
		||||
    name: "🐍 ${{ matrix.python }} • ${{ matrix.os }} • clang-latest"
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Show env
 | 
			
		||||
        run: env
 | 
			
		||||
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
      - name: Set up Clang
 | 
			
		||||
        uses: egor-tensin/setup-clang@v1
 | 
			
		||||
 | 
			
		||||
      - name: Setup Python ${{ matrix.python }}
 | 
			
		||||
        uses: actions/setup-python@v4
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: ${{ matrix.python }}
 | 
			
		||||
 | 
			
		||||
      - name: Update CMake
 | 
			
		||||
        uses: jwlawson/actions-setup-cmake@v1.14
 | 
			
		||||
 | 
			
		||||
      - name: Install ninja-build tool
 | 
			
		||||
        uses: seanmiddleditch/gha-setup-ninja@v3
 | 
			
		||||
 | 
			
		||||
      - name: Run pip installs
 | 
			
		||||
        run: |
 | 
			
		||||
          python -m pip install --upgrade pip
 | 
			
		||||
          python -m pip install -r tests/requirements.txt
 | 
			
		||||
 | 
			
		||||
      - name: Show Clang++ version
 | 
			
		||||
        run: clang++ --version
 | 
			
		||||
 | 
			
		||||
      - name: Show CMake version
 | 
			
		||||
        run: cmake --version
 | 
			
		||||
 | 
			
		||||
      # TODO: WERROR=ON
 | 
			
		||||
      - name: Configure Clang
 | 
			
		||||
        run: >
 | 
			
		||||
          cmake -G Ninja -S . -B .
 | 
			
		||||
          -DPYBIND11_WERROR=OFF
 | 
			
		||||
          -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
 | 
			
		||||
          -DDOWNLOAD_CATCH=ON
 | 
			
		||||
          -DDOWNLOAD_EIGEN=ON
 | 
			
		||||
          -DCMAKE_CXX_COMPILER=clang++
 | 
			
		||||
          -DCMAKE_CXX_STANDARD=17
 | 
			
		||||
 | 
			
		||||
      - name: Build
 | 
			
		||||
        run: cmake --build . -j 2
 | 
			
		||||
 | 
			
		||||
      - name: Python tests
 | 
			
		||||
        run: cmake --build . --target pytest -j 2
 | 
			
		||||
 | 
			
		||||
      - name: C++ tests
 | 
			
		||||
        run: cmake --build . --target cpptest -j 2
 | 
			
		||||
 | 
			
		||||
      - name: Interface test
 | 
			
		||||
        run: cmake --build . --target test_cmake_build -j 2
 | 
			
		||||
 | 
			
		||||
      - name: Clean directory
 | 
			
		||||
        run: git clean -fdx
 | 
			
		||||
 | 
			
		||||
  macos_brew_install_llvm:
 | 
			
		||||
    name: "macos-latest • brew install llvm"
 | 
			
		||||
    runs-on: macos-latest
 | 
			
		||||
 | 
			
		||||
    env:
 | 
			
		||||
      # https://apple.stackexchange.com/questions/227026/how-to-install-recent-clang-with-homebrew
 | 
			
		||||
      LDFLAGS: '-L/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/lib'
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Update PATH
 | 
			
		||||
        run: echo "/usr/local/opt/llvm/bin" >> $GITHUB_PATH
 | 
			
		||||
 | 
			
		||||
      - name: Show env
 | 
			
		||||
        run: env
 | 
			
		||||
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
      - name: Show Clang++ version before brew install llvm
 | 
			
		||||
        run: clang++ --version
 | 
			
		||||
 | 
			
		||||
      - name: brew install llvm
 | 
			
		||||
        run: brew install llvm
 | 
			
		||||
 | 
			
		||||
      - name: Show Clang++ version after brew install llvm
 | 
			
		||||
        run: clang++ --version
 | 
			
		||||
 | 
			
		||||
      - name: Update CMake
 | 
			
		||||
        uses: jwlawson/actions-setup-cmake@v1.14
 | 
			
		||||
 | 
			
		||||
      - name: Run pip installs
 | 
			
		||||
        run: |
 | 
			
		||||
          python3 -m pip install --upgrade pip
 | 
			
		||||
          python3 -m pip install -r tests/requirements.txt
 | 
			
		||||
          python3 -m pip install numpy
 | 
			
		||||
          python3 -m pip install scipy
 | 
			
		||||
 | 
			
		||||
      - name: Show CMake version
 | 
			
		||||
        run: cmake --version
 | 
			
		||||
 | 
			
		||||
      - name: CMake Configure
 | 
			
		||||
        run: >
 | 
			
		||||
          cmake -S . -B .
 | 
			
		||||
          -DPYBIND11_WERROR=ON
 | 
			
		||||
          -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
 | 
			
		||||
          -DDOWNLOAD_CATCH=ON
 | 
			
		||||
          -DDOWNLOAD_EIGEN=ON
 | 
			
		||||
          -DCMAKE_CXX_COMPILER=clang++
 | 
			
		||||
          -DCMAKE_CXX_STANDARD=17
 | 
			
		||||
          -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
 | 
			
		||||
 | 
			
		||||
      - name: Build
 | 
			
		||||
        run: cmake --build . -j 2
 | 
			
		||||
 | 
			
		||||
      - name: Python tests
 | 
			
		||||
        run: cmake --build . --target pytest -j 2
 | 
			
		||||
 | 
			
		||||
      - name: C++ tests
 | 
			
		||||
        run: cmake --build . --target cpptest -j 2
 | 
			
		||||
 | 
			
		||||
      - name: Interface test
 | 
			
		||||
        run: cmake --build . --target test_cmake_build -j 2
 | 
			
		||||
 | 
			
		||||
      - name: CMake Configure - Exercise cmake -DPYBIND11_TEST_OVERRIDE
 | 
			
		||||
        run: >
 | 
			
		||||
          cmake -S . -B build_partial
 | 
			
		||||
          -DPYBIND11_WERROR=ON
 | 
			
		||||
          -DPYBIND11_SIMPLE_GIL_MANAGEMENT=OFF
 | 
			
		||||
          -DDOWNLOAD_CATCH=ON
 | 
			
		||||
          -DDOWNLOAD_EIGEN=ON
 | 
			
		||||
          -DCMAKE_CXX_COMPILER=clang++
 | 
			
		||||
          -DCMAKE_CXX_STANDARD=17
 | 
			
		||||
          -DPYTHON_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)")
 | 
			
		||||
          "-DPYBIND11_TEST_OVERRIDE=test_call_policies.cpp;test_gil_scoped.cpp;test_thread.cpp"
 | 
			
		||||
 | 
			
		||||
      - name: Build - Exercise cmake -DPYBIND11_TEST_OVERRIDE
 | 
			
		||||
        run: cmake --build build_partial -j 2
 | 
			
		||||
 | 
			
		||||
      - name: Python tests - Exercise cmake -DPYBIND11_TEST_OVERRIDE
 | 
			
		||||
        run: cmake --build build_partial --target pytest -j 2
 | 
			
		||||
 | 
			
		||||
      - name: Clean directory
 | 
			
		||||
        run: git clean -fdx
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,14 @@ on:
 | 
			
		|||
      - stable
 | 
			
		||||
      - v*
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
  contents: read
 | 
			
		||||
 | 
			
		||||
env:
 | 
			
		||||
  PIP_BREAK_SYSTEM_PACKAGES: 1
 | 
			
		||||
  # For cmake:
 | 
			
		||||
  VERBOSE: 1
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  # This tests various versions of CMake in various combinations, to make sure
 | 
			
		||||
  # the configure step passes.
 | 
			
		||||
| 
						 | 
				
			
			@ -16,22 +24,26 @@ jobs:
 | 
			
		|||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        runs-on: [ubuntu-latest, macos-latest, windows-latest]
 | 
			
		||||
        runs-on: [ubuntu-20.04, macos-latest, windows-latest]
 | 
			
		||||
        arch: [x64]
 | 
			
		||||
        cmake: ["3.23"]
 | 
			
		||||
        cmake: ["3.26"]
 | 
			
		||||
 | 
			
		||||
        include:
 | 
			
		||||
        - runs-on: ubuntu-latest
 | 
			
		||||
        - runs-on: ubuntu-20.04
 | 
			
		||||
          arch: x64
 | 
			
		||||
          cmake: 3.4
 | 
			
		||||
          cmake: "3.5"
 | 
			
		||||
 | 
			
		||||
        - runs-on: ubuntu-20.04
 | 
			
		||||
          arch: x64
 | 
			
		||||
          cmake: "3.27"
 | 
			
		||||
 | 
			
		||||
        - runs-on: macos-latest
 | 
			
		||||
          arch: x64
 | 
			
		||||
          cmake: 3.7
 | 
			
		||||
          cmake: "3.7"
 | 
			
		||||
 | 
			
		||||
        - runs-on: windows-2019
 | 
			
		||||
          arch: x64 # x86 compilers seem to be missing on 2019 image
 | 
			
		||||
          cmake: 3.18
 | 
			
		||||
          cmake: "3.18"
 | 
			
		||||
 | 
			
		||||
    name: 🐍 3.7 • CMake ${{ matrix.cmake }} • ${{ matrix.runs-on }}
 | 
			
		||||
    runs-on: ${{ matrix.runs-on }}
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +63,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.12
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.14
 | 
			
		||||
      with:
 | 
			
		||||
        cmake-version: ${{ matrix.cmake }}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,8 +12,13 @@ on:
 | 
			
		|||
    - stable
 | 
			
		||||
    - "v*"
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
  contents: read
 | 
			
		||||
 | 
			
		||||
env:
 | 
			
		||||
  FORCE_COLOR: 3
 | 
			
		||||
  # For cmake:
 | 
			
		||||
  VERBOSE: 1
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  pre-commit:
 | 
			
		||||
| 
						 | 
				
			
			@ -36,12 +41,12 @@ jobs:
 | 
			
		|||
    # in .github/CONTRIBUTING.md and update as needed.
 | 
			
		||||
    name: Clang-Tidy
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    container: silkeh/clang:13
 | 
			
		||||
    container: silkeh/clang:15-bullseye
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
    - name: Install requirements
 | 
			
		||||
      run: apt-get update && apt-get install -y python3-dev python3-pytest
 | 
			
		||||
      run: apt-get update && apt-get install -y git python3-dev python3-pytest
 | 
			
		||||
 | 
			
		||||
    - name: Configure
 | 
			
		||||
      run: >
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,14 +3,23 @@ on:
 | 
			
		|||
  pull_request_target:
 | 
			
		||||
    types: [closed]
 | 
			
		||||
 | 
			
		||||
permissions: {}
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  label:
 | 
			
		||||
    name: Labeler
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    permissions:
 | 
			
		||||
      contents: read
 | 
			
		||||
      pull-requests: write
 | 
			
		||||
    steps:
 | 
			
		||||
 | 
			
		||||
    - uses: actions/labeler@main
 | 
			
		||||
      if: github.event.pull_request.merged == true
 | 
			
		||||
      if: >
 | 
			
		||||
        github.event.pull_request.merged == true &&
 | 
			
		||||
        !startsWith(github.event.pull_request.title, 'chore(deps):') &&
 | 
			
		||||
        !startsWith(github.event.pull_request.title, 'ci(fix):') &&
 | 
			
		||||
        !startsWith(github.event.pull_request.title, 'docs(changelog):')
 | 
			
		||||
      with:
 | 
			
		||||
        repo-token: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
        configuration-path: .github/labeler_merged.yml
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,11 @@ on:
 | 
			
		|||
    types:
 | 
			
		||||
    - published
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
  contents: read
 | 
			
		||||
 | 
			
		||||
env:
 | 
			
		||||
  PIP_BREAK_SYSTEM_PACKAGES: 1
 | 
			
		||||
  PIP_ONLY_BINARY: numpy
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
| 
						 | 
				
			
			@ -98,13 +102,13 @@ jobs:
 | 
			
		|||
    - uses: actions/download-artifact@v3
 | 
			
		||||
 | 
			
		||||
    - name: Publish standard package
 | 
			
		||||
      uses: pypa/gh-action-pypi-publish@v1.5.0
 | 
			
		||||
      uses: pypa/gh-action-pypi-publish@release/v1
 | 
			
		||||
      with:
 | 
			
		||||
        password: ${{ secrets.pypi_password }}
 | 
			
		||||
        packages_dir: standard/
 | 
			
		||||
        packages-dir: standard/
 | 
			
		||||
 | 
			
		||||
    - name: Publish global package
 | 
			
		||||
      uses: pypa/gh-action-pypi-publish@v1.5.0
 | 
			
		||||
      uses: pypa/gh-action-pypi-publish@release/v1
 | 
			
		||||
      with:
 | 
			
		||||
        password: ${{ secrets.pypi_password_global }}
 | 
			
		||||
        packages_dir: global/
 | 
			
		||||
        packages-dir: global/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,112 +1,116 @@
 | 
			
		|||
 | 
			
		||||
name: Upstream
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  workflow_dispatch:
 | 
			
		||||
  pull_request:
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
  contents: read
 | 
			
		||||
 | 
			
		||||
concurrency:
 | 
			
		||||
  group: upstream-${{ github.ref }}
 | 
			
		||||
  cancel-in-progress: true
 | 
			
		||||
 | 
			
		||||
env:
 | 
			
		||||
  PIP_ONLY_BINARY: numpy
 | 
			
		||||
  PIP_BREAK_SYSTEM_PACKAGES: 1
 | 
			
		||||
  PIP_ONLY_BINARY: ":all:"
 | 
			
		||||
  # For cmake:
 | 
			
		||||
  VERBOSE: 1
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  standard:
 | 
			
		||||
    name: "🐍 3.11 latest internals • ubuntu-latest • x64"
 | 
			
		||||
    name: "🐍 3.12 latest • ubuntu-latest • x64"
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    # Only runs when the  'python dev' label is selected
 | 
			
		||||
    if: "contains(github.event.pull_request.labels.*.name, 'python dev')"
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
    - name: Setup Python 3.11
 | 
			
		||||
    - name: Setup Python 3.12
 | 
			
		||||
      uses: actions/setup-python@v4
 | 
			
		||||
      with:
 | 
			
		||||
        python-version: "3.11-dev"
 | 
			
		||||
        python-version: "3.12-dev"
 | 
			
		||||
 | 
			
		||||
    - name: Setup Boost (Linux)
 | 
			
		||||
      if: runner.os == 'Linux'
 | 
			
		||||
    - name: Setup Boost
 | 
			
		||||
      run: sudo apt-get install libboost-dev
 | 
			
		||||
 | 
			
		||||
    - name: Update CMake
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.12
 | 
			
		||||
      uses: jwlawson/actions-setup-cmake@v1.14
 | 
			
		||||
 | 
			
		||||
    - name: Prepare env
 | 
			
		||||
    - name: Run pip installs
 | 
			
		||||
      run: |
 | 
			
		||||
        python -m pip install --upgrade pip
 | 
			
		||||
        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
 | 
			
		||||
    - name: Show platform info
 | 
			
		||||
      run: |
 | 
			
		||||
        python -m platform
 | 
			
		||||
        cmake --version
 | 
			
		||||
        pip list
 | 
			
		||||
 | 
			
		||||
    # First build - C++11 mode and inplace
 | 
			
		||||
    - name: Configure C++11
 | 
			
		||||
      run: >
 | 
			
		||||
        cmake -S . -B .
 | 
			
		||||
        cmake -S . -B build11
 | 
			
		||||
        -DPYBIND11_WERROR=ON
 | 
			
		||||
        -DDOWNLOAD_CATCH=ON
 | 
			
		||||
        -DDOWNLOAD_EIGEN=ON
 | 
			
		||||
        -DCMAKE_CXX_STANDARD=11
 | 
			
		||||
        -DCMAKE_BUILD_TYPE=Debug
 | 
			
		||||
 | 
			
		||||
    - name: Build C++11
 | 
			
		||||
      run: cmake --build . -j 2
 | 
			
		||||
      run: cmake --build build11 -j 2
 | 
			
		||||
 | 
			
		||||
    - name: Python tests C++11
 | 
			
		||||
      run: cmake --build . --target pytest -j 2
 | 
			
		||||
      run: cmake --build build11 --target pytest -j 2
 | 
			
		||||
 | 
			
		||||
    - name: C++11 tests
 | 
			
		||||
      run: cmake --build .  --target cpptest -j 2
 | 
			
		||||
      run: cmake --build build11  --target cpptest -j 2
 | 
			
		||||
 | 
			
		||||
    - name: Interface test C++11
 | 
			
		||||
      run: cmake --build . --target test_cmake_build
 | 
			
		||||
 | 
			
		||||
    - name: Clean directory
 | 
			
		||||
      run: git clean -fdx
 | 
			
		||||
      run: cmake --build build11 --target test_cmake_build
 | 
			
		||||
 | 
			
		||||
    # Second build - C++17 mode and in a build directory
 | 
			
		||||
    - name: Configure C++17
 | 
			
		||||
      run: >
 | 
			
		||||
        cmake -S . -B build2
 | 
			
		||||
        cmake -S . -B build17
 | 
			
		||||
        -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: Build C++17
 | 
			
		||||
      run: cmake --build build17 -j 2
 | 
			
		||||
 | 
			
		||||
    - name: Python tests
 | 
			
		||||
      run: cmake --build build2 --target pytest
 | 
			
		||||
    - name: Python tests C++17
 | 
			
		||||
      run: cmake --build build17 --target pytest
 | 
			
		||||
 | 
			
		||||
    - name: C++ tests
 | 
			
		||||
      run: cmake --build build2 --target cpptest
 | 
			
		||||
    - name: C++17 tests
 | 
			
		||||
      run: cmake --build build17 --target cpptest
 | 
			
		||||
 | 
			
		||||
    # Third build - C++17 mode with unstable ABI
 | 
			
		||||
    - name: Configure (unstable ABI)
 | 
			
		||||
      run: >
 | 
			
		||||
        cmake -S . -B build3
 | 
			
		||||
        cmake -S . -B build17max
 | 
			
		||||
        -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
 | 
			
		||||
      run: cmake --build build17max -j 2
 | 
			
		||||
 | 
			
		||||
    - name: Python tests (unstable ABI)
 | 
			
		||||
      run: cmake --build build3 --target pytest
 | 
			
		||||
      run: cmake --build build17max --target pytest
 | 
			
		||||
 | 
			
		||||
    - name: Interface test
 | 
			
		||||
      run: cmake --build build2 --target test_cmake_build
 | 
			
		||||
    - name: Interface test (unstable ABI)
 | 
			
		||||
      run: cmake --build build17max --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
 | 
			
		||||
      run: |
 | 
			
		||||
        pip install setuptools
 | 
			
		||||
        pytest tests/extra_setuptools
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,3 +43,4 @@ pybind11Targets.cmake
 | 
			
		|||
/pybind11/share/*
 | 
			
		||||
/docs/_build/*
 | 
			
		||||
.ipynb_checkpoints/
 | 
			
		||||
tests/main.cpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,10 +12,62 @@
 | 
			
		|||
#
 | 
			
		||||
# See https://github.com/pre-commit/pre-commit
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ci:
 | 
			
		||||
  autoupdate_commit_msg: "chore(deps): update pre-commit hooks"
 | 
			
		||||
  autofix_commit_msg: "style: pre-commit fixes"
 | 
			
		||||
  autoupdate_schedule: monthly
 | 
			
		||||
 | 
			
		||||
# third-party content
 | 
			
		||||
exclude: ^tools/JoinPaths.cmake$
 | 
			
		||||
 | 
			
		||||
repos:
 | 
			
		||||
 | 
			
		||||
# Clang format the codebase automatically
 | 
			
		||||
- repo: https://github.com/pre-commit/mirrors-clang-format
 | 
			
		||||
  rev: "v16.0.6"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: clang-format
 | 
			
		||||
    types_or: [c++, c, cuda]
 | 
			
		||||
 | 
			
		||||
# Black, the code formatter, natively supports pre-commit
 | 
			
		||||
- repo: https://github.com/psf/black
 | 
			
		||||
  rev: "23.3.0" # Keep in sync with blacken-docs
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: black
 | 
			
		||||
 | 
			
		||||
# Ruff, the Python auto-correcting linter written in Rust
 | 
			
		||||
- repo: https://github.com/astral-sh/ruff-pre-commit
 | 
			
		||||
  rev: v0.0.276
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: ruff
 | 
			
		||||
    args: ["--fix", "--show-fixes"]
 | 
			
		||||
 | 
			
		||||
# Check static types with mypy
 | 
			
		||||
- repo: https://github.com/pre-commit/mirrors-mypy
 | 
			
		||||
  rev: "v1.4.1"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: mypy
 | 
			
		||||
    args: []
 | 
			
		||||
    exclude: ^(tests|docs)/
 | 
			
		||||
    additional_dependencies:
 | 
			
		||||
    - markdown-it-py<3 # Drop this together with dropping Python 3.7 support.
 | 
			
		||||
    - nox
 | 
			
		||||
    - rich
 | 
			
		||||
    - types-setuptools
 | 
			
		||||
 | 
			
		||||
# CMake formatting
 | 
			
		||||
- repo: https://github.com/cheshirekow/cmake-format-precommit
 | 
			
		||||
  rev: "v0.6.13"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: cmake-format
 | 
			
		||||
    additional_dependencies: [pyyaml]
 | 
			
		||||
    types: [file]
 | 
			
		||||
    files: (\.cmake|CMakeLists.txt)(.in)?$
 | 
			
		||||
 | 
			
		||||
# Standard hooks
 | 
			
		||||
- repo: https://github.com/pre-commit/pre-commit-hooks
 | 
			
		||||
  rev: "v4.3.0"
 | 
			
		||||
  rev: "v4.4.0"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: check-added-large-files
 | 
			
		||||
  - id: check-case-conflict
 | 
			
		||||
| 
						 | 
				
			
			@ -30,109 +82,38 @@ repos:
 | 
			
		|||
  - id: requirements-txt-fixer
 | 
			
		||||
  - id: trailing-whitespace
 | 
			
		||||
 | 
			
		||||
# Upgrade old Python syntax
 | 
			
		||||
- repo: https://github.com/asottile/pyupgrade
 | 
			
		||||
  rev: "v2.37.1"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: pyupgrade
 | 
			
		||||
    args: [--py36-plus]
 | 
			
		||||
 | 
			
		||||
# Nicely sort includes
 | 
			
		||||
- repo: https://github.com/PyCQA/isort
 | 
			
		||||
  rev: "5.10.1"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: isort
 | 
			
		||||
 | 
			
		||||
# Black, the code formatter, natively supports pre-commit
 | 
			
		||||
- repo: https://github.com/psf/black
 | 
			
		||||
  rev: "22.6.0" # Keep in sync with blacken-docs
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: black
 | 
			
		||||
 | 
			
		||||
# Also code format the docs
 | 
			
		||||
- repo: https://github.com/asottile/blacken-docs
 | 
			
		||||
  rev: "v1.12.1"
 | 
			
		||||
  rev: "1.14.0"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: blacken-docs
 | 
			
		||||
    additional_dependencies:
 | 
			
		||||
    - black==22.6.0 # keep in sync with black hook
 | 
			
		||||
    - black==23.3.0 # keep in sync with black hook
 | 
			
		||||
 | 
			
		||||
# Changes tabs to spaces
 | 
			
		||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
 | 
			
		||||
  rev: "v1.3.0"
 | 
			
		||||
  rev: "v1.5.1"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: remove-tabs
 | 
			
		||||
 | 
			
		||||
# Avoid directional quotes
 | 
			
		||||
- repo: https://github.com/sirosen/texthooks
 | 
			
		||||
  rev: "0.3.1"
 | 
			
		||||
  rev: "0.5.0"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: fix-ligatures
 | 
			
		||||
  - id: fix-smartquotes
 | 
			
		||||
 | 
			
		||||
# Autoremoves unused imports
 | 
			
		||||
- repo: https://github.com/hadialqattan/pycln
 | 
			
		||||
  rev: "v2.0.1"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: pycln
 | 
			
		||||
    stages: [manual]
 | 
			
		||||
 | 
			
		||||
# Checking for common mistakes
 | 
			
		||||
- repo: https://github.com/pre-commit/pygrep-hooks
 | 
			
		||||
  rev: "v1.9.0"
 | 
			
		||||
  rev: "v1.10.0"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: python-check-blanket-noqa
 | 
			
		||||
  - id: python-check-blanket-type-ignore
 | 
			
		||||
  - id: python-no-log-warn
 | 
			
		||||
  - id: python-use-type-annotations
 | 
			
		||||
  - id: rst-backticks
 | 
			
		||||
  - id: rst-directive-colons
 | 
			
		||||
  - id: rst-inline-touching-normal
 | 
			
		||||
 | 
			
		||||
# Automatically remove noqa that are not used
 | 
			
		||||
- repo: https://github.com/asottile/yesqa
 | 
			
		||||
  rev: "v1.3.0"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: yesqa
 | 
			
		||||
    additional_dependencies: &flake8_dependencies
 | 
			
		||||
      - flake8-bugbear
 | 
			
		||||
      - pep8-naming
 | 
			
		||||
 | 
			
		||||
# Flake8 also supports pre-commit natively (same author)
 | 
			
		||||
- repo: https://github.com/PyCQA/flake8
 | 
			
		||||
  rev: "4.0.1"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: flake8
 | 
			
		||||
    exclude: ^(docs/.*|tools/.*)$
 | 
			
		||||
    additional_dependencies: *flake8_dependencies
 | 
			
		||||
 | 
			
		||||
# PyLint has native support - not always usable, but works for us
 | 
			
		||||
- repo: https://github.com/PyCQA/pylint
 | 
			
		||||
  rev: "v2.14.4"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: pylint
 | 
			
		||||
    files: ^pybind11
 | 
			
		||||
 | 
			
		||||
# CMake formatting
 | 
			
		||||
- repo: https://github.com/cheshirekow/cmake-format-precommit
 | 
			
		||||
  rev: "v0.6.13"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: cmake-format
 | 
			
		||||
    additional_dependencies: [pyyaml]
 | 
			
		||||
    types: [file]
 | 
			
		||||
    files: (\.cmake|CMakeLists.txt)(.in)?$
 | 
			
		||||
 | 
			
		||||
# Check static types with mypy
 | 
			
		||||
- repo: https://github.com/pre-commit/mirrors-mypy
 | 
			
		||||
  rev: "v0.961"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: mypy
 | 
			
		||||
    args: []
 | 
			
		||||
    exclude: ^(tests|docs)/
 | 
			
		||||
    additional_dependencies: [nox, rich]
 | 
			
		||||
 | 
			
		||||
# Checks the manifest for missing files (native support)
 | 
			
		||||
- repo: https://github.com/mgedmin/check-manifest
 | 
			
		||||
  rev: "0.48"
 | 
			
		||||
  rev: "0.49"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: check-manifest
 | 
			
		||||
    # This is a slow hook, so only run this if --hook-stage manual is passed
 | 
			
		||||
| 
						 | 
				
			
			@ -140,16 +121,18 @@ repos:
 | 
			
		|||
    additional_dependencies: [cmake, ninja]
 | 
			
		||||
 | 
			
		||||
# Check for spelling
 | 
			
		||||
# Use tools/codespell_ignore_lines_from_errors.py
 | 
			
		||||
# to rebuild .codespell-ignore-lines
 | 
			
		||||
- repo: https://github.com/codespell-project/codespell
 | 
			
		||||
  rev: "v2.1.0"
 | 
			
		||||
  rev: "v2.2.5"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: codespell
 | 
			
		||||
    exclude: ".supp$"
 | 
			
		||||
    args: ["-L", "nd,ot,thist"]
 | 
			
		||||
    args: ["-x.codespell-ignore-lines", "-Lccompiler"]
 | 
			
		||||
 | 
			
		||||
# Check for common shell mistakes
 | 
			
		||||
- repo: https://github.com/shellcheck-py/shellcheck-py
 | 
			
		||||
  rev: "v0.8.0.4"
 | 
			
		||||
  rev: "v0.9.0.5"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: shellcheck
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -162,9 +145,9 @@ repos:
 | 
			
		|||
    entry: PyBind|Numpy|Cmake|CCache|PyTest
 | 
			
		||||
    exclude: ^\.pre-commit-config.yaml$
 | 
			
		||||
 | 
			
		||||
# Clang format the codebase automatically
 | 
			
		||||
- repo: https://github.com/pre-commit/mirrors-clang-format
 | 
			
		||||
  rev: "v14.0.6"
 | 
			
		||||
# PyLint has native support - not always usable, but works for us
 | 
			
		||||
- repo: https://github.com/PyCQA/pylint
 | 
			
		||||
  rev: "v3.0.0a6"
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: clang-format
 | 
			
		||||
    types_or: [c++, c, cuda]
 | 
			
		||||
  - id: pylint
 | 
			
		||||
    files: ^pybind11
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,15 +5,15 @@
 | 
			
		|||
# All rights reserved. Use of this source code is governed by a
 | 
			
		||||
# BSD-style license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
cmake_minimum_required(VERSION 3.4)
 | 
			
		||||
cmake_minimum_required(VERSION 3.5)
 | 
			
		||||
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.4...3.22)` syntax does not work with
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` 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.22)
 | 
			
		||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
 | 
			
		||||
  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
 | 
			
		||||
else()
 | 
			
		||||
  cmake_policy(VERSION 3.22)
 | 
			
		||||
  cmake_policy(VERSION 3.26)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
# Avoid infinite recursion if tests include this as a subdirectory
 | 
			
		||||
| 
						 | 
				
			
			@ -91,10 +91,16 @@ endif()
 | 
			
		|||
option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT})
 | 
			
		||||
option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT})
 | 
			
		||||
option(PYBIND11_NOPYTHON "Disable search for Python" OFF)
 | 
			
		||||
option(PYBIND11_SIMPLE_GIL_MANAGEMENT
 | 
			
		||||
       "Use simpler GIL management logic that does not support disassociation" OFF)
 | 
			
		||||
set(PYBIND11_INTERNALS_VERSION
 | 
			
		||||
    ""
 | 
			
		||||
    CACHE STRING "Override the ABI version, may be used to enable the unstable ABI.")
 | 
			
		||||
 | 
			
		||||
if(PYBIND11_SIMPLE_GIL_MANAGEMENT)
 | 
			
		||||
  add_compile_definitions(PYBIND11_SIMPLE_GIL_MANAGEMENT)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
cmake_dependent_option(
 | 
			
		||||
  USE_PYTHON_INCLUDE_DIR
 | 
			
		||||
  "Install pybind11 headers in Python include directory instead of default installation prefix"
 | 
			
		||||
| 
						 | 
				
			
			@ -120,6 +126,9 @@ set(PYBIND11_HEADERS
 | 
			
		|||
    include/pybind11/complex.h
 | 
			
		||||
    include/pybind11/options.h
 | 
			
		||||
    include/pybind11/eigen.h
 | 
			
		||||
    include/pybind11/eigen/common.h
 | 
			
		||||
    include/pybind11/eigen/matrix.h
 | 
			
		||||
    include/pybind11/eigen/tensor.h
 | 
			
		||||
    include/pybind11/embed.h
 | 
			
		||||
    include/pybind11/eval.h
 | 
			
		||||
    include/pybind11/gil.h
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +140,8 @@ set(PYBIND11_HEADERS
 | 
			
		|||
    include/pybind11/pytypes.h
 | 
			
		||||
    include/pybind11/stl.h
 | 
			
		||||
    include/pybind11/stl_bind.h
 | 
			
		||||
    include/pybind11/stl/filesystem.h)
 | 
			
		||||
    include/pybind11/stl/filesystem.h
 | 
			
		||||
    include/pybind11/type_caster_pyobject_ptr.h)
 | 
			
		||||
 | 
			
		||||
# Compare with grep and warn if mismatched
 | 
			
		||||
if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)
 | 
			
		||||
| 
						 | 
				
			
			@ -198,6 +208,9 @@ else()
 | 
			
		|||
endif()
 | 
			
		||||
 | 
			
		||||
include("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11Common.cmake")
 | 
			
		||||
# https://github.com/jtojnar/cmake-snips/#concatenating-paths-when-building-pkg-config-files
 | 
			
		||||
# TODO: cmake 3.20 adds the cmake_path() function, which obsoletes this snippet
 | 
			
		||||
include("${CMAKE_CURRENT_SOURCE_DIR}/tools/JoinPaths.cmake")
 | 
			
		||||
 | 
			
		||||
# Relative directory setting
 | 
			
		||||
if(USE_PYTHON_INCLUDE_DIR AND DEFINED Python_INCLUDE_DIRS)
 | 
			
		||||
| 
						 | 
				
			
			@ -262,6 +275,16 @@ if(PYBIND11_INSTALL)
 | 
			
		|||
    NAMESPACE "pybind11::"
 | 
			
		||||
    DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})
 | 
			
		||||
 | 
			
		||||
  # pkg-config support
 | 
			
		||||
  if(NOT prefix_for_pc_file)
 | 
			
		||||
    set(prefix_for_pc_file "${CMAKE_INSTALL_PREFIX}")
 | 
			
		||||
  endif()
 | 
			
		||||
  join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
 | 
			
		||||
  configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11.pc.in"
 | 
			
		||||
                 "${CMAKE_CURRENT_BINARY_DIR}/pybind11.pc" @ONLY)
 | 
			
		||||
  install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pybind11.pc"
 | 
			
		||||
          DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig/")
 | 
			
		||||
 | 
			
		||||
  # Uninstall target
 | 
			
		||||
  if(PYBIND11_MASTER_PROJECT)
 | 
			
		||||
    configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake_uninstall.cmake.in"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
prune tests
 | 
			
		||||
recursive-include pybind11/include/pybind11 *.h
 | 
			
		||||
recursive-include pybind11 *.py
 | 
			
		||||
recursive-include pybind11 py.typed
 | 
			
		||||
include pybind11/share/cmake/pybind11/*.cmake
 | 
			
		||||
include LICENSE README.rst pyproject.toml setup.py setup.cfg
 | 
			
		||||
include LICENSE README.rst SECURITY.md pyproject.toml setup.py setup.cfg
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -135,7 +135,7 @@ This project was created by `Wenzel
 | 
			
		|||
Jakob <http://rgl.epfl.ch/people/wjakob>`_. Significant features and/or
 | 
			
		||||
improvements to the code were contributed by Jonas Adler, Lori A. Burns,
 | 
			
		||||
Sylvain Corlay, Eric Cousineau, Aaron Gokaslan, Ralf Grosse-Kunstleve, Trent Houliston, Axel
 | 
			
		||||
Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov Johan Mabille, Tomasz Miąsko,
 | 
			
		||||
Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov, Johan Mabille, Tomasz Miąsko,
 | 
			
		||||
Dean Moldovan, Ben Pritchard, Jason Rhinelander, Boris Schäling, Pim
 | 
			
		||||
Schellart, Henry Schreiner, Ivan Smirnov, Boris Staletic, and Patrick Stewart.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
# Security Policy
 | 
			
		||||
 | 
			
		||||
## Supported Versions
 | 
			
		||||
 | 
			
		||||
Security updates are applied only to the latest release.
 | 
			
		||||
 | 
			
		||||
## Reporting a Vulnerability
 | 
			
		||||
 | 
			
		||||
If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
 | 
			
		||||
 | 
			
		||||
Please disclose it at [security advisory](https://github.com/pybind/pybind11/security/advisories/new).
 | 
			
		||||
 | 
			
		||||
This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ type is explicitly allowed.
 | 
			
		|||
 | 
			
		||||
.. code-block:: cpp
 | 
			
		||||
 | 
			
		||||
    namespace pybind11 { namespace detail {
 | 
			
		||||
    namespace PYBIND11_NAMESPACE { namespace detail {
 | 
			
		||||
        template <> struct type_caster<inty> {
 | 
			
		||||
        public:
 | 
			
		||||
            /**
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +78,7 @@ type is explicitly allowed.
 | 
			
		|||
                return PyLong_FromLong(src.long_value);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }} // namespace pybind11::detail
 | 
			
		||||
    }} // namespace PYBIND11_NAMESPACE::detail
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ types:
 | 
			
		|||
.. code-block:: cpp
 | 
			
		||||
 | 
			
		||||
    // `boost::optional` as an example -- can be any `std::optional`-like container
 | 
			
		||||
    namespace pybind11 { namespace detail {
 | 
			
		||||
    namespace PYBIND11_NAMESPACE { namespace detail {
 | 
			
		||||
        template <typename T>
 | 
			
		||||
        struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {};
 | 
			
		||||
    }}
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ for custom variant types:
 | 
			
		|||
.. code-block:: cpp
 | 
			
		||||
 | 
			
		||||
    // `boost::variant` as an example -- can be any `std::variant`-like container
 | 
			
		||||
    namespace pybind11 { namespace detail {
 | 
			
		||||
    namespace PYBIND11_NAMESPACE { namespace detail {
 | 
			
		||||
        template <typename... Ts>
 | 
			
		||||
        struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +66,7 @@ for custom variant types:
 | 
			
		|||
                return boost::apply_visitor(args...);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }} // namespace pybind11::detail
 | 
			
		||||
    }} // namespace PYBIND11_NAMESPACE::detail
 | 
			
		||||
 | 
			
		||||
The ``visit_helper`` specialization is not required if your ``name::variant`` provides
 | 
			
		||||
a ``name::visit()`` function. For any other function name, the specialization must be
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -101,8 +101,11 @@ conversion has the same overhead as implicit conversion.
 | 
			
		|||
    m.def("str_output",
 | 
			
		||||
        []() {
 | 
			
		||||
            std::string s = "Send your r\xe9sum\xe9 to Alice in HR"; // Latin-1
 | 
			
		||||
            py::str py_s = PyUnicode_DecodeLatin1(s.data(), s.length());
 | 
			
		||||
            return py_s;
 | 
			
		||||
            py::handle py_s = PyUnicode_DecodeLatin1(s.data(), s.length(), nullptr);
 | 
			
		||||
            if (!py_s) {
 | 
			
		||||
                throw py::error_already_set();
 | 
			
		||||
            }
 | 
			
		||||
            return py::reinterpret_steal<py::str>(py_s);
 | 
			
		||||
        }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +116,8 @@ conversion has the same overhead as implicit conversion.
 | 
			
		|||
 | 
			
		||||
The `Python C API
 | 
			
		||||
<https://docs.python.org/3/c-api/unicode.html#built-in-codecs>`_ provides
 | 
			
		||||
several built-in codecs.
 | 
			
		||||
several built-in codecs. Note that these all return *new* references, so
 | 
			
		||||
use :cpp:func:`reinterpret_steal` when converting them to a :cpp:class:`str`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
One could also use a third party encoding library such as libiconv to transcode
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1228,7 +1228,7 @@ whether a downcast is safe, you can proceed by specializing the
 | 
			
		|||
        std::string bark() const { return sound; }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    namespace pybind11 {
 | 
			
		||||
    namespace PYBIND11_NAMESPACE {
 | 
			
		||||
        template<> struct polymorphic_type_hook<Pet> {
 | 
			
		||||
            static const void *get(const Pet *src, const std::type_info*& type) {
 | 
			
		||||
                // note that src may be nullptr
 | 
			
		||||
| 
						 | 
				
			
			@ -1239,7 +1239,7 @@ whether a downcast is safe, you can proceed by specializing the
 | 
			
		|||
                return src;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    } // namespace pybind11
 | 
			
		||||
    } // namespace PYBIND11_NAMESPACE
 | 
			
		||||
 | 
			
		||||
When pybind11 wants to convert a C++ pointer of type ``Base*`` to a
 | 
			
		||||
Python object, it calls ``polymorphic_type_hook<Base>::get()`` to
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ information, see :doc:`/compiling`.
 | 
			
		|||
 | 
			
		||||
.. code-block:: cmake
 | 
			
		||||
 | 
			
		||||
    cmake_minimum_required(VERSION 3.4)
 | 
			
		||||
    cmake_minimum_required(VERSION 3.5...3.26)
 | 
			
		||||
    project(example)
 | 
			
		||||
 | 
			
		||||
    find_package(pybind11 REQUIRED)  # or `add_subdirectory(pybind11)`
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -177,9 +177,12 @@ section.
 | 
			
		|||
    may be explicitly (re-)thrown to delegate it to the other,
 | 
			
		||||
    previously-declared existing exception translators.
 | 
			
		||||
 | 
			
		||||
    Note that ``libc++`` and ``libstdc++`` `behave differently <https://stackoverflow.com/questions/19496643/using-clang-fvisibility-hidden-and-typeinfo-and-type-erasure/28827430>`_
 | 
			
		||||
    with ``-fvisibility=hidden``. Therefore exceptions that are used across ABI boundaries need to be explicitly exported, as exercised in ``tests/test_exceptions.h``.
 | 
			
		||||
    See also: "Problems with C++ exceptions" under `GCC Wiki <https://gcc.gnu.org/wiki/Visibility>`_.
 | 
			
		||||
    Note that ``libc++`` and ``libstdc++`` `behave differently under macOS
 | 
			
		||||
    <https://stackoverflow.com/questions/19496643/using-clang-fvisibility-hidden-and-typeinfo-and-type-erasure/28827430>`_
 | 
			
		||||
    with ``-fvisibility=hidden``. Therefore exceptions that are used across ABI
 | 
			
		||||
    boundaries need to be explicitly exported, as exercised in
 | 
			
		||||
    ``tests/test_exceptions.h``. See also:
 | 
			
		||||
    "Problems with C++ exceptions" under `GCC Wiki <https://gcc.gnu.org/wiki/Visibility>`_.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Local vs Global Exception Translators
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,15 +39,42 @@ The ``PYBIND11_MAKE_OPAQUE`` macro does *not* require the above workarounds.
 | 
			
		|||
Global Interpreter Lock (GIL)
 | 
			
		||||
=============================
 | 
			
		||||
 | 
			
		||||
When calling a C++ function from Python, the GIL is always held.
 | 
			
		||||
The Python C API dictates that the Global Interpreter Lock (GIL) must always
 | 
			
		||||
be held by the current thread to safely access Python objects. As a result,
 | 
			
		||||
when Python calls into C++ via pybind11 the GIL must be held, and pybind11
 | 
			
		||||
will never implicitly release the GIL.
 | 
			
		||||
 | 
			
		||||
.. code-block:: cpp
 | 
			
		||||
 | 
			
		||||
    void my_function() {
 | 
			
		||||
        /* GIL is held when this function is called from Python */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PYBIND11_MODULE(example, m) {
 | 
			
		||||
        m.def("my_function", &my_function);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
pybind11 will ensure that the GIL is held when it knows that it is calling
 | 
			
		||||
Python code. For example, if a Python callback is passed to C++ code via
 | 
			
		||||
``std::function``, when C++ code calls the function the built-in wrapper
 | 
			
		||||
will acquire the GIL before calling the Python callback. Similarly, the
 | 
			
		||||
``PYBIND11_OVERRIDE`` family of macros will acquire the GIL before calling
 | 
			
		||||
back into Python.
 | 
			
		||||
 | 
			
		||||
When writing C++ code that is called from other C++ code, if that code accesses
 | 
			
		||||
Python state, it must explicitly acquire and release the GIL.
 | 
			
		||||
 | 
			
		||||
The classes :class:`gil_scoped_release` and :class:`gil_scoped_acquire` can be
 | 
			
		||||
used to acquire and release the global interpreter lock in the body of a C++
 | 
			
		||||
function call. In this way, long-running C++ code can be parallelized using
 | 
			
		||||
multiple Python threads. Taking :ref:`overriding_virtuals` as an example, this
 | 
			
		||||
multiple Python threads, **but great care must be taken** when any
 | 
			
		||||
:class:`gil_scoped_release` appear: if there is any way that the C++ code
 | 
			
		||||
can access Python objects, :class:`gil_scoped_acquire` should be used to
 | 
			
		||||
reacquire the GIL. Taking :ref:`overriding_virtuals` as an example, this
 | 
			
		||||
could be realized as follows (important changes highlighted):
 | 
			
		||||
 | 
			
		||||
.. code-block:: cpp
 | 
			
		||||
    :emphasize-lines: 8,9,31,32
 | 
			
		||||
    :emphasize-lines: 8,30,31
 | 
			
		||||
 | 
			
		||||
    class PyAnimal : public Animal {
 | 
			
		||||
    public:
 | 
			
		||||
| 
						 | 
				
			
			@ -56,9 +83,7 @@ could be realized as follows (important changes highlighted):
 | 
			
		|||
 | 
			
		||||
        /* Trampoline (need one for each virtual function) */
 | 
			
		||||
        std::string go(int n_times) {
 | 
			
		||||
            /* Acquire GIL before calling Python code */
 | 
			
		||||
            py::gil_scoped_acquire acquire;
 | 
			
		||||
 | 
			
		||||
            /* PYBIND11_OVERRIDE_PURE will acquire the GIL before accessing Python state */
 | 
			
		||||
            PYBIND11_OVERRIDE_PURE(
 | 
			
		||||
                std::string, /* Return type */
 | 
			
		||||
                Animal,      /* Parent class */
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +103,8 @@ could be realized as follows (important changes highlighted):
 | 
			
		|||
            .def(py::init<>());
 | 
			
		||||
 | 
			
		||||
        m.def("call_go", [](Animal *animal) -> std::string {
 | 
			
		||||
            /* Release GIL before calling into (potentially long-running) C++ code */
 | 
			
		||||
            // GIL is held when called from Python code. Release GIL before
 | 
			
		||||
            // calling into (potentially long-running) C++ code
 | 
			
		||||
            py::gil_scoped_release release;
 | 
			
		||||
            return call_go(animal);
 | 
			
		||||
        });
 | 
			
		||||
| 
						 | 
				
			
			@ -92,6 +118,34 @@ The ``call_go`` wrapper can also be simplified using the ``call_guard`` policy
 | 
			
		|||
    m.def("call_go", &call_go, py::call_guard<py::gil_scoped_release>());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Common Sources Of Global Interpreter Lock Errors
 | 
			
		||||
==================================================================
 | 
			
		||||
 | 
			
		||||
Failing to properly hold the Global Interpreter Lock (GIL) is one of the
 | 
			
		||||
more common sources of bugs within code that uses pybind11. If you are
 | 
			
		||||
running into GIL related errors, we highly recommend you consult the
 | 
			
		||||
following checklist.
 | 
			
		||||
 | 
			
		||||
- Do you have any global variables that are pybind11 objects or invoke
 | 
			
		||||
  pybind11 functions in either their constructor or destructor? You are generally
 | 
			
		||||
  not allowed to invoke any Python function in a global static context. We recommend
 | 
			
		||||
  using lazy initialization and then intentionally leaking at the end of the program.
 | 
			
		||||
 | 
			
		||||
- Do you have any pybind11 objects that are members of other C++ structures? One
 | 
			
		||||
  commonly overlooked requirement is that pybind11 objects have to increase their reference count
 | 
			
		||||
  whenever their copy constructor is called. Thus, you need to be holding the GIL to invoke
 | 
			
		||||
  the copy constructor of any C++ class that has a pybind11 member. This can sometimes be very
 | 
			
		||||
  tricky to track for complicated programs Think carefully when you make a pybind11 object
 | 
			
		||||
  a member in another struct.
 | 
			
		||||
 | 
			
		||||
- C++ destructors that invoke Python functions can be particularly troublesome as
 | 
			
		||||
  destructors can sometimes get invoked in weird and unexpected circumstances as a result
 | 
			
		||||
  of exceptions.
 | 
			
		||||
 | 
			
		||||
- You should try running your code in a debug build. That will enable additional assertions
 | 
			
		||||
  within pybind11 that will throw exceptions on certain GIL handling errors
 | 
			
		||||
  (reference counting operations).
 | 
			
		||||
 | 
			
		||||
Binding sequence data types, iterators, the slicing protocol, etc.
 | 
			
		||||
==================================================================
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -298,6 +352,15 @@ The class ``options`` allows you to selectively suppress auto-generated signatur
 | 
			
		|||
        m.def("add", [](int a, int b) { return a + b; }, "A function which adds two numbers");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
pybind11 also appends all members of an enum to the resulting enum docstring.
 | 
			
		||||
This default behavior can be disabled by using the ``disable_enum_members_docstring()``
 | 
			
		||||
function of the ``options`` class.
 | 
			
		||||
 | 
			
		||||
With ``disable_user_defined_docstrings()`` all user defined docstrings of
 | 
			
		||||
``module_::def()``, ``class_::def()`` and ``enum_()`` are disabled, but the
 | 
			
		||||
function signatures and enum members are included in the docstring, unless they
 | 
			
		||||
are disabled separately.
 | 
			
		||||
 | 
			
		||||
Note that changes to the settings affect only function bindings created during the
 | 
			
		||||
lifetime of the ``options`` instance. When it goes out of scope at the end of the module's init function,
 | 
			
		||||
the default settings are restored to prevent unwanted side effects.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -433,7 +433,7 @@ following:
 | 
			
		|||
            { 2, 4 },                                  // shape (rows, cols)
 | 
			
		||||
            { sizeof(uint8_t) * 4, sizeof(uint8_t) }   // strides in bytes
 | 
			
		||||
        );
 | 
			
		||||
    })
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
This approach is meant for providing a ``memoryview`` for a C/C++ buffer not
 | 
			
		||||
managed by Python. The user is responsible for managing the lifetime of the
 | 
			
		||||
| 
						 | 
				
			
			@ -449,7 +449,7 @@ We can also use ``memoryview::from_memory`` for a simple 1D contiguous buffer:
 | 
			
		|||
            buffer,               // buffer pointer
 | 
			
		||||
            sizeof(uint8_t) * 8   // buffer size
 | 
			
		||||
        );
 | 
			
		||||
    })
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
.. versionchanged:: 2.6
 | 
			
		||||
    ``memoryview::from_memory`` added.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -157,7 +157,7 @@ specialized:
 | 
			
		|||
    PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
 | 
			
		||||
 | 
			
		||||
    // Only needed if the type's `.get()` goes by another name
 | 
			
		||||
    namespace pybind11 { namespace detail {
 | 
			
		||||
    namespace PYBIND11_NAMESPACE { namespace detail {
 | 
			
		||||
        template <typename T>
 | 
			
		||||
        struct holder_helper<SmartPtr<T>> { // <-- specialization
 | 
			
		||||
            static const T *get(const SmartPtr<T> &p) { return p.getPointer(); }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,364 @@ Starting with version 1.8.0, pybind11 releases use a `semantic versioning
 | 
			
		|||
Changes will be added here periodically from the "Suggested changelog entry"
 | 
			
		||||
block in pull request descriptions.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Version 2.11.1 (July 17, 2023)
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
Changes:
 | 
			
		||||
 | 
			
		||||
* ``PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF`` is now provided as an option
 | 
			
		||||
  for disabling the default-on ``PyGILState_Check()``'s in
 | 
			
		||||
  ``pybind11::handle``'s ``inc_ref()`` & ``dec_ref()``.
 | 
			
		||||
  `#4753 <https://github.com/pybind/pybind11/pull/4753>`_
 | 
			
		||||
 | 
			
		||||
* ``PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF`` was disabled for PyPy in general
 | 
			
		||||
  (not just PyPy Windows).
 | 
			
		||||
  `#4751 <https://github.com/pybind/pybind11/pull/4751>`_
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Version 2.11.0 (July 14, 2023)
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
New features:
 | 
			
		||||
 | 
			
		||||
* The newly added ``pybind11::detail::is_move_constructible`` trait can be
 | 
			
		||||
  specialized for cases in which ``std::is_move_constructible`` does not work
 | 
			
		||||
  as needed. This is very similar to the long-established
 | 
			
		||||
  ``pybind11::detail::is_copy_constructible``.
 | 
			
		||||
  `#4631 <https://github.com/pybind/pybind11/pull/4631>`_
 | 
			
		||||
 | 
			
		||||
* Introduce ``recursive_container_traits``.
 | 
			
		||||
  `#4623 <https://github.com/pybind/pybind11/pull/4623>`_
 | 
			
		||||
 | 
			
		||||
* ``pybind11/type_caster_pyobject_ptr.h`` was added to support automatic
 | 
			
		||||
  wrapping of APIs that make use of ``PyObject *``. This header needs to
 | 
			
		||||
  included explicitly (i.e. it is not included implicitly
 | 
			
		||||
  with ``pybind/pybind11.h``).
 | 
			
		||||
  `#4601 <https://github.com/pybind/pybind11/pull/4601>`_
 | 
			
		||||
 | 
			
		||||
* ``format_descriptor<>`` & ``npy_format_descriptor<>`` ``PyObject *``
 | 
			
		||||
  specializations were added. The latter enables ``py::array_t<PyObject *>``
 | 
			
		||||
  to/from-python conversions.
 | 
			
		||||
  `#4674 <https://github.com/pybind/pybind11/pull/4674>`_
 | 
			
		||||
 | 
			
		||||
* ``buffer_info`` gained an ``item_type_is_equivalent_to<T>()`` member
 | 
			
		||||
  function.
 | 
			
		||||
  `#4674 <https://github.com/pybind/pybind11/pull/4674>`_
 | 
			
		||||
 | 
			
		||||
* The ``capsule`` API gained a user-friendly constructor
 | 
			
		||||
  (``py::capsule(ptr, "name", dtor)``).
 | 
			
		||||
  `#4720 <https://github.com/pybind/pybind11/pull/4720>`_
 | 
			
		||||
 | 
			
		||||
Changes:
 | 
			
		||||
 | 
			
		||||
* ``PyGILState_Check()``'s in ``pybind11::handle``'s ``inc_ref()`` &
 | 
			
		||||
  ``dec_ref()`` are now enabled by default again.
 | 
			
		||||
  `#4246 <https://github.com/pybind/pybind11/pull/4246>`_
 | 
			
		||||
 | 
			
		||||
* ``py::initialize_interpreter()`` using ``PyConfig_InitPythonConfig()``
 | 
			
		||||
  instead of ``PyConfig_InitIsolatedConfig()``, to obtain complete
 | 
			
		||||
  ``sys.path``.
 | 
			
		||||
  `#4473 <https://github.com/pybind/pybind11/pull/4473>`_
 | 
			
		||||
 | 
			
		||||
* Cast errors now always include Python type information, even if
 | 
			
		||||
  ``PYBIND11_DETAILED_ERROR_MESSAGES`` is not defined. This increases binary
 | 
			
		||||
  sizes slightly (~1.5%) but the error messages are much more informative.
 | 
			
		||||
  `#4463 <https://github.com/pybind/pybind11/pull/4463>`_
 | 
			
		||||
 | 
			
		||||
* The docstring generation for the ``std::array``-list caster was fixed.
 | 
			
		||||
  Previously, signatures included the size of the list in a non-standard,
 | 
			
		||||
  non-spec compliant way. The new format conforms to PEP 593.
 | 
			
		||||
  **Tooling for processing the docstrings may need to be updated accordingly.**
 | 
			
		||||
  `#4679 <https://github.com/pybind/pybind11/pull/4679>`_
 | 
			
		||||
 | 
			
		||||
* Setter return values (which are inaccessible for all practical purposes) are
 | 
			
		||||
  no longer converted to Python (only to be discarded).
 | 
			
		||||
  `#4621 <https://github.com/pybind/pybind11/pull/4621>`_
 | 
			
		||||
 | 
			
		||||
* Allow lambda specified to function definition to be ``noexcept(true)``
 | 
			
		||||
  in C++17.
 | 
			
		||||
  `#4593 <https://github.com/pybind/pybind11/pull/4593>`_
 | 
			
		||||
 | 
			
		||||
* Get rid of recursive template instantiations for concatenating type
 | 
			
		||||
  signatures on C++17 and higher.
 | 
			
		||||
  `#4587 <https://github.com/pybind/pybind11/pull/4587>`_
 | 
			
		||||
 | 
			
		||||
* Compatibility with Python 3.12 (beta). Note that the minimum pybind11
 | 
			
		||||
  ABI version for Python 3.12 is version 5. (The default ABI version
 | 
			
		||||
  for Python versions up to and including 3.11 is still version 4.).
 | 
			
		||||
  `#4570 <https://github.com/pybind/pybind11/pull/4570>`_
 | 
			
		||||
 | 
			
		||||
* With ``PYBIND11_INTERNALS_VERSION 5`` (default for Python 3.12+), MSVC builds
 | 
			
		||||
  use ``std::hash<std::type_index>`` and ``std::equal_to<std::type_index>``
 | 
			
		||||
  instead of string-based type comparisons. This resolves issues when binding
 | 
			
		||||
  types defined in the unnamed namespace.
 | 
			
		||||
  `#4319 <https://github.com/pybind/pybind11/pull/4319>`_
 | 
			
		||||
 | 
			
		||||
* Python exception ``__notes__`` (introduced with Python 3.11) are now added to
 | 
			
		||||
  the ``error_already_set::what()`` output.
 | 
			
		||||
  `#4678 <https://github.com/pybind/pybind11/pull/4678>`_
 | 
			
		||||
 | 
			
		||||
Build system improvements:
 | 
			
		||||
 | 
			
		||||
* CMake 3.27 support was added, CMake 3.4 support was dropped.
 | 
			
		||||
  FindPython will be used if ``FindPythonInterp`` is not present.
 | 
			
		||||
  `#4719 <https://github.com/pybind/pybind11/pull/4719>`_
 | 
			
		||||
 | 
			
		||||
* Update clang-tidy to 15 in CI.
 | 
			
		||||
  `#4387 <https://github.com/pybind/pybind11/pull/4387>`_
 | 
			
		||||
 | 
			
		||||
* Moved the linting framework over to Ruff.
 | 
			
		||||
  `#4483 <https://github.com/pybind/pybind11/pull/4483>`_
 | 
			
		||||
 | 
			
		||||
* Skip ``lto`` checks and target generation when
 | 
			
		||||
  ``CMAKE_INTERPROCEDURAL_OPTIMIZATION`` is defined.
 | 
			
		||||
  `#4643 <https://github.com/pybind/pybind11/pull/4643>`_
 | 
			
		||||
 | 
			
		||||
* No longer inject ``-stdlib=libc++``, not needed for modern Pythons
 | 
			
		||||
  (macOS 10.9+).
 | 
			
		||||
  `#4639 <https://github.com/pybind/pybind11/pull/4639>`_
 | 
			
		||||
 | 
			
		||||
* PyPy 3.10 support was added, PyPy 3.7 support was dropped.
 | 
			
		||||
  `#4728 <https://github.com/pybind/pybind11/pull/4728>`_
 | 
			
		||||
 | 
			
		||||
* Testing with Python 3.12 beta releases was added.
 | 
			
		||||
  `#4713 <https://github.com/pybind/pybind11/pull/4713>`_
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Version 2.10.4 (Mar 16, 2023)
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
Changes:
 | 
			
		||||
 | 
			
		||||
* ``python3 -m pybind11`` gained a ``--version`` option (prints the version and
 | 
			
		||||
  exits).
 | 
			
		||||
  `#4526 <https://github.com/pybind/pybind11/pull/4526>`_
 | 
			
		||||
 | 
			
		||||
Bug Fixes:
 | 
			
		||||
 | 
			
		||||
* Fix a warning when pydebug is enabled on Python 3.11.
 | 
			
		||||
  `#4461 <https://github.com/pybind/pybind11/pull/4461>`_
 | 
			
		||||
 | 
			
		||||
* Ensure ``gil_scoped_release`` RAII is non-copyable.
 | 
			
		||||
  `#4490 <https://github.com/pybind/pybind11/pull/4490>`_
 | 
			
		||||
 | 
			
		||||
* Ensure the tests dir does not show up with new versions of setuptools.
 | 
			
		||||
  `#4510 <https://github.com/pybind/pybind11/pull/4510>`_
 | 
			
		||||
 | 
			
		||||
* Better stacklevel for a warning in setuptools helpers.
 | 
			
		||||
  `#4516 <https://github.com/pybind/pybind11/pull/4516>`_
 | 
			
		||||
 | 
			
		||||
Version 2.10.3 (Jan 3, 2023)
 | 
			
		||||
----------------------------
 | 
			
		||||
 | 
			
		||||
Changes:
 | 
			
		||||
 | 
			
		||||
* Temporarily made our GIL status assertions (added in 2.10.2) disabled by
 | 
			
		||||
  default (re-enable manually by defining
 | 
			
		||||
  ``PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF``, will be enabled in 2.11).
 | 
			
		||||
  `#4432 <https://github.com/pybind/pybind11/pull/4432>`_
 | 
			
		||||
 | 
			
		||||
* Improved error messages when ``inc_ref``/``dec_ref`` are called with an
 | 
			
		||||
  invalid GIL state.
 | 
			
		||||
  `#4427 <https://github.com/pybind/pybind11/pull/4427>`_
 | 
			
		||||
  `#4436 <https://github.com/pybind/pybind11/pull/4436>`_
 | 
			
		||||
 | 
			
		||||
Bug Fixes:
 | 
			
		||||
 | 
			
		||||
* Some minor touchups found by static analyzers.
 | 
			
		||||
  `#4440 <https://github.com/pybind/pybind11/pull/4440>`_
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Version 2.10.2 (Dec 20, 2022)
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
Changes:
 | 
			
		||||
 | 
			
		||||
* ``scoped_interpreter`` constructor taking ``PyConfig``.
 | 
			
		||||
  `#4330 <https://github.com/pybind/pybind11/pull/4330>`_
 | 
			
		||||
 | 
			
		||||
* ``pybind11/eigen/tensor.h`` adds converters to and from ``Eigen::Tensor`` and
 | 
			
		||||
  ``Eigen::TensorMap``.
 | 
			
		||||
  `#4201 <https://github.com/pybind/pybind11/pull/4201>`_
 | 
			
		||||
 | 
			
		||||
* ``PyGILState_Check()``'s  were integrated to ``pybind11::handle``
 | 
			
		||||
  ``inc_ref()`` & ``dec_ref()``. The added GIL checks are guarded by
 | 
			
		||||
  ``PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF``, which is the default only if
 | 
			
		||||
  ``NDEBUG`` is not defined. (Made non-default in 2.10.3, will be active in 2.11)
 | 
			
		||||
  `#4246 <https://github.com/pybind/pybind11/pull/4246>`_
 | 
			
		||||
 | 
			
		||||
* Add option for enable/disable enum members in docstring.
 | 
			
		||||
  `#2768 <https://github.com/pybind/pybind11/pull/2768>`_
 | 
			
		||||
 | 
			
		||||
* Fixed typing of ``KeysView``, ``ValuesView`` and ``ItemsView`` in ``bind_map``.
 | 
			
		||||
  `#4353 <https://github.com/pybind/pybind11/pull/4353>`_
 | 
			
		||||
 | 
			
		||||
Bug fixes:
 | 
			
		||||
 | 
			
		||||
* Bug fix affecting only Python 3.6 under very specific, uncommon conditions:
 | 
			
		||||
  move ``PyEval_InitThreads()`` call to the correct location.
 | 
			
		||||
  `#4350 <https://github.com/pybind/pybind11/pull/4350>`_
 | 
			
		||||
 | 
			
		||||
* Fix segfault bug when passing foreign native functions to functional.h.
 | 
			
		||||
  `#4254 <https://github.com/pybind/pybind11/pull/4254>`_
 | 
			
		||||
 | 
			
		||||
Build system improvements:
 | 
			
		||||
 | 
			
		||||
* Support setting PYTHON_LIBRARIES manually for Windows ARM cross-compilation
 | 
			
		||||
  (classic mode).
 | 
			
		||||
  `#4406 <https://github.com/pybind/pybind11/pull/4406>`_
 | 
			
		||||
 | 
			
		||||
* Extend IPO/LTO detection for ICX (a.k.a IntelLLVM) compiler.
 | 
			
		||||
  `#4402 <https://github.com/pybind/pybind11/pull/4402>`_
 | 
			
		||||
 | 
			
		||||
* Allow calling ``find_package(pybind11 CONFIG)`` multiple times from separate
 | 
			
		||||
  directories in the same CMake project and properly link Python (new mode).
 | 
			
		||||
  `#4401 <https://github.com/pybind/pybind11/pull/4401>`_
 | 
			
		||||
 | 
			
		||||
* ``multiprocessing_set_spawn`` in pytest fixture for added safety.
 | 
			
		||||
  `#4377 <https://github.com/pybind/pybind11/pull/4377>`_
 | 
			
		||||
 | 
			
		||||
* Fixed a bug in two pybind11/tools cmake scripts causing "Unknown arguments specified" errors.
 | 
			
		||||
  `#4327 <https://github.com/pybind/pybind11/pull/4327>`_
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Version 2.10.1 (Oct 31, 2022)
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
This is the first version to fully support embedding the newly released Python 3.11.
 | 
			
		||||
 | 
			
		||||
Changes:
 | 
			
		||||
 | 
			
		||||
* Allow ``pybind11::capsule`` constructor to take null destructor pointers.
 | 
			
		||||
  `#4221 <https://github.com/pybind/pybind11/pull/4221>`_
 | 
			
		||||
 | 
			
		||||
* ``embed.h`` was changed so that ``PYTHONPATH`` is used also with Python 3.11
 | 
			
		||||
  (established behavior).
 | 
			
		||||
  `#4119 <https://github.com/pybind/pybind11/pull/4119>`_
 | 
			
		||||
 | 
			
		||||
* A ``PYBIND11_SIMPLE_GIL_MANAGEMENT`` option was added (cmake, C++ define),
 | 
			
		||||
  along with many additional tests in ``test_gil_scoped.py``. The option may be
 | 
			
		||||
  useful to try when debugging GIL-related issues, to determine if the more
 | 
			
		||||
  complex default implementation is or is not to blame. See #4216 for
 | 
			
		||||
  background. WARNING: Please be careful to not create ODR violations when
 | 
			
		||||
  using the option: everything that is linked together with mutual symbol
 | 
			
		||||
  visibility needs to be rebuilt.
 | 
			
		||||
  `#4216 <https://github.com/pybind/pybind11/pull/4216>`_
 | 
			
		||||
 | 
			
		||||
* ``PYBIND11_EXPORT_EXCEPTION`` was made non-empty only under macOS. This makes
 | 
			
		||||
  Linux builds safer, and enables the removal of warning suppression pragmas for
 | 
			
		||||
  Windows.
 | 
			
		||||
  `#4298 <https://github.com/pybind/pybind11/pull/4298>`_
 | 
			
		||||
 | 
			
		||||
Bug fixes:
 | 
			
		||||
 | 
			
		||||
* Fixed a bug where ``UnicodeDecodeError`` was not propagated from various
 | 
			
		||||
  ``py::str`` ctors when decoding surrogate utf characters.
 | 
			
		||||
  `#4294 <https://github.com/pybind/pybind11/pull/4294>`_
 | 
			
		||||
 | 
			
		||||
* Revert perfect forwarding for ``make_iterator``. This broke at least one
 | 
			
		||||
  valid use case. May revisit later.
 | 
			
		||||
  `#4234 <https://github.com/pybind/pybind11/pull/4234>`_
 | 
			
		||||
 | 
			
		||||
* Fix support for safe casts to ``void*`` (regression in 2.10.0).
 | 
			
		||||
  `#4275 <https://github.com/pybind/pybind11/pull/4275>`_
 | 
			
		||||
 | 
			
		||||
* Fix ``char8_t`` support (regression in 2.9).
 | 
			
		||||
  `#4278 <https://github.com/pybind/pybind11/pull/4278>`_
 | 
			
		||||
 | 
			
		||||
* Unicode surrogate character in Python exception message leads to process
 | 
			
		||||
  termination in ``error_already_set::what()``.
 | 
			
		||||
  `#4297 <https://github.com/pybind/pybind11/pull/4297>`_
 | 
			
		||||
 | 
			
		||||
* Fix MSVC 2019 v.1924 & C++14 mode error for ``overload_cast``.
 | 
			
		||||
  `#4188 <https://github.com/pybind/pybind11/pull/4188>`_
 | 
			
		||||
 | 
			
		||||
* Make augmented assignment operators non-const for the object-api. Behavior
 | 
			
		||||
  was previously broken for augmented assignment operators.
 | 
			
		||||
  `#4065 <https://github.com/pybind/pybind11/pull/4065>`_
 | 
			
		||||
 | 
			
		||||
* Add proper error checking to C++ bindings for Python list append and insert.
 | 
			
		||||
  `#4208 <https://github.com/pybind/pybind11/pull/4208>`_
 | 
			
		||||
 | 
			
		||||
* Work-around for Nvidia's CUDA nvcc compiler in versions 11.4.0 - 11.8.0.
 | 
			
		||||
  `#4220 <https://github.com/pybind/pybind11/pull/4220>`_
 | 
			
		||||
 | 
			
		||||
* A workaround for PyPy was added in the ``py::error_already_set``
 | 
			
		||||
  implementation, related to PR `#1895 <https://github.com/pybind/pybind11/pull/1895>`_
 | 
			
		||||
  released with v2.10.0.
 | 
			
		||||
  `#4079 <https://github.com/pybind/pybind11/pull/4079>`_
 | 
			
		||||
 | 
			
		||||
* Fixed compiler errors when C++23 ``std::forward_like`` is available.
 | 
			
		||||
  `#4136 <https://github.com/pybind/pybind11/pull/4136>`_
 | 
			
		||||
 | 
			
		||||
* Properly raise exceptions in contains methods (like when an object in unhashable).
 | 
			
		||||
  `#4209 <https://github.com/pybind/pybind11/pull/4209>`_
 | 
			
		||||
 | 
			
		||||
* Further improve another error in exception handling.
 | 
			
		||||
  `#4232 <https://github.com/pybind/pybind11/pull/4232>`_
 | 
			
		||||
 | 
			
		||||
* ``get_local_internals()`` was made compatible with
 | 
			
		||||
  ``finalize_interpreter()``, fixing potential freezes during interpreter
 | 
			
		||||
  finalization.
 | 
			
		||||
  `#4192 <https://github.com/pybind/pybind11/pull/4192>`_
 | 
			
		||||
 | 
			
		||||
Performance and style:
 | 
			
		||||
 | 
			
		||||
* Reserve space in set and STL map casters if possible. This will prevent
 | 
			
		||||
  unnecessary rehashing / resizing by knowing the number of keys ahead of time
 | 
			
		||||
  for Python to C++ casting. This improvement will greatly speed up the casting
 | 
			
		||||
  of large unordered maps and sets.
 | 
			
		||||
  `#4194 <https://github.com/pybind/pybind11/pull/4194>`_
 | 
			
		||||
 | 
			
		||||
* GIL RAII scopes are non-copyable to avoid potential bugs.
 | 
			
		||||
  `#4183 <https://github.com/pybind/pybind11/pull/4183>`_
 | 
			
		||||
 | 
			
		||||
* Explicitly default all relevant ctors for pytypes in the ``PYBIND11_OBJECT``
 | 
			
		||||
  macros and enforce the clang-tidy checks ``modernize-use-equals-default`` in
 | 
			
		||||
  macros as well.
 | 
			
		||||
  `#4017 <https://github.com/pybind/pybind11/pull/4017>`_
 | 
			
		||||
 | 
			
		||||
* Optimize iterator advancement in C++ bindings.
 | 
			
		||||
  `#4237 <https://github.com/pybind/pybind11/pull/4237>`_
 | 
			
		||||
 | 
			
		||||
* Use the modern ``PyObject_GenericGetDict`` and ``PyObject_GenericSetDict``
 | 
			
		||||
  for handling dynamic attribute dictionaries.
 | 
			
		||||
  `#4106 <https://github.com/pybind/pybind11/pull/4106>`_
 | 
			
		||||
 | 
			
		||||
* Document that users should use ``PYBIND11_NAMESPACE`` instead of using ``pybind11`` when
 | 
			
		||||
  opening namespaces. Using namespace declarations and namespace qualification
 | 
			
		||||
  remain the same as ``pybind11``. This is done to ensure consistent symbol
 | 
			
		||||
  visibility.
 | 
			
		||||
  `#4098 <https://github.com/pybind/pybind11/pull/4098>`_
 | 
			
		||||
 | 
			
		||||
* Mark ``detail::forward_like`` as constexpr.
 | 
			
		||||
  `#4147 <https://github.com/pybind/pybind11/pull/4147>`_
 | 
			
		||||
 | 
			
		||||
* Optimize unpacking_collector when processing ``arg_v`` arguments.
 | 
			
		||||
  `#4219 <https://github.com/pybind/pybind11/pull/4219>`_
 | 
			
		||||
 | 
			
		||||
* Optimize casting C++ object to ``None``.
 | 
			
		||||
  `#4269 <https://github.com/pybind/pybind11/pull/4269>`_
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Build system improvements:
 | 
			
		||||
 | 
			
		||||
* CMake: revert overwrite behavior, now opt-in with ``PYBIND11_PYTHONLIBS_OVERRWRITE OFF``.
 | 
			
		||||
  `#4195 <https://github.com/pybind/pybind11/pull/4195>`_
 | 
			
		||||
 | 
			
		||||
* Include a pkg-config file when installing pybind11, such as in the Python
 | 
			
		||||
  package.
 | 
			
		||||
  `#4077 <https://github.com/pybind/pybind11/pull/4077>`_
 | 
			
		||||
 | 
			
		||||
* Avoid stripping debug symbols when ``CMAKE_BUILD_TYPE`` is set to ``DEBUG``
 | 
			
		||||
  instead of ``Debug``.
 | 
			
		||||
  `#4078 <https://github.com/pybind/pybind11/pull/4078>`_
 | 
			
		||||
 | 
			
		||||
* Followup to `#3948 <https://github.com/pybind/pybind11/pull/3948>`_, fixing vcpkg again.
 | 
			
		||||
  `#4123 <https://github.com/pybind/pybind11/pull/4123>`_
 | 
			
		||||
 | 
			
		||||
Version 2.10.0 (Jul 15, 2022)
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,6 +58,16 @@ interactive Python session demonstrating this example is shown below:
 | 
			
		|||
    Static member functions can be bound in the same way using
 | 
			
		||||
    :func:`class_::def_static`.
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    Binding C++ types in unnamed namespaces (also known as anonymous namespaces)
 | 
			
		||||
    works reliably on many platforms, but not all. The `XFAIL_CONDITION` in
 | 
			
		||||
    tests/test_unnamed_namespace_a.py encodes the currently known conditions.
 | 
			
		||||
    For background see `#4319 <https://github.com/pybind/pybind11/pull/4319>`_.
 | 
			
		||||
    If portability is a concern, it is therefore not recommended to bind C++
 | 
			
		||||
    types in unnamed namespaces. It will be safest to manually pick unique
 | 
			
		||||
    namespace names.
 | 
			
		||||
 | 
			
		||||
Keyword and default arguments
 | 
			
		||||
=============================
 | 
			
		||||
It is possible to specify keyword and default arguments using the syntax
 | 
			
		||||
| 
						 | 
				
			
			@ -539,3 +549,7 @@ The ``name`` property returns the name of the enum value as a unicode string.
 | 
			
		|||
           ...
 | 
			
		||||
 | 
			
		||||
    By default, these are omitted to conserve space.
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
 | 
			
		||||
    Contrary to Python customs, enum values from the wrappers should not be compared using ``is``, but with ``==`` (see `#1177 <https://github.com/pybind/pybind11/issues/1177>`_ for background).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -241,7 +241,7 @@ extension module can be created with just a few lines of code:
 | 
			
		|||
 | 
			
		||||
.. code-block:: cmake
 | 
			
		||||
 | 
			
		||||
    cmake_minimum_required(VERSION 3.4...3.18)
 | 
			
		||||
    cmake_minimum_required(VERSION 3.5...3.26)
 | 
			
		||||
    project(example LANGUAGES CXX)
 | 
			
		||||
 | 
			
		||||
    add_subdirectory(pybind11)
 | 
			
		||||
| 
						 | 
				
			
			@ -261,6 +261,9 @@ PyPI integration, can be found in the [cmake_example]_  repository.
 | 
			
		|||
.. versionchanged:: 2.6
 | 
			
		||||
   CMake 3.4+ is required.
 | 
			
		||||
 | 
			
		||||
.. versionchanged:: 2.11
 | 
			
		||||
   CMake 3.5+ is required.
 | 
			
		||||
 | 
			
		||||
Further information can be found at :doc:`cmake/index`.
 | 
			
		||||
 | 
			
		||||
pybind11_add_module
 | 
			
		||||
| 
						 | 
				
			
			@ -495,7 +498,7 @@ You can use these targets to build complex applications. For example, the
 | 
			
		|||
 | 
			
		||||
.. code-block:: cmake
 | 
			
		||||
 | 
			
		||||
    cmake_minimum_required(VERSION 3.4)
 | 
			
		||||
    cmake_minimum_required(VERSION 3.5...3.26)
 | 
			
		||||
    project(example LANGUAGES CXX)
 | 
			
		||||
 | 
			
		||||
    find_package(pybind11 REQUIRED)  # or add_subdirectory(pybind11)
 | 
			
		||||
| 
						 | 
				
			
			@ -553,7 +556,7 @@ information about usage in C++, see :doc:`/advanced/embedding`.
 | 
			
		|||
 | 
			
		||||
.. code-block:: cmake
 | 
			
		||||
 | 
			
		||||
    cmake_minimum_required(VERSION 3.4...3.18)
 | 
			
		||||
    cmake_minimum_required(VERSION 3.5...3.26)
 | 
			
		||||
    project(example LANGUAGES CXX)
 | 
			
		||||
 | 
			
		||||
    find_package(pybind11 REQUIRED)  # or add_subdirectory(pybind11)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -353,12 +353,11 @@ def prepare(app):
 | 
			
		|||
        f.write(contents)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def clean_up(app, exception):
 | 
			
		||||
def clean_up(app, exception):  # noqa: ARG001
 | 
			
		||||
    (DIR / "readme.rst").unlink()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def setup(app):
 | 
			
		||||
 | 
			
		||||
    # Add hook for building doxygen xml when needed
 | 
			
		||||
    app.connect("builder-inited", generate_doxygen_xml)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -284,7 +284,8 @@ There are three possible solutions:
 | 
			
		|||
   COMPONENTS Interpreter Development)`` on modern CMake (3.12+, 3.15+ better,
 | 
			
		||||
   3.18.2+ best). Pybind11 in these cases uses the new CMake FindPython instead
 | 
			
		||||
   of the old, deprecated search tools, and these modules are much better at
 | 
			
		||||
   finding the correct Python.
 | 
			
		||||
   finding the correct Python. If FindPythonLibs/Interp are not available
 | 
			
		||||
   (CMake 3.27+), then this will be ignored and FindPython will be used.
 | 
			
		||||
3. Set ``PYBIND11_NOPYTHON`` to ``TRUE``. Pybind11 will not search for Python.
 | 
			
		||||
   However, you will have to use the target-based system, and do more setup
 | 
			
		||||
   yourself, because it does not know about or include things that depend on
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,10 +33,12 @@ If you don't have nox, you should either use ``pipx run nox`` instead, or use
 | 
			
		|||
    - 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``.
 | 
			
		||||
          - Check to make sure
 | 
			
		||||
            `needs-changelog <https://github.com/pybind/pybind11/pulls?q=is%3Apr+is%3Aclosed+label%3A%22needs+changelog%22>`_
 | 
			
		||||
            issues are entered in the changelog (clear the label when done).
 | 
			
		||||
    - Add release date in ``docs/changelog.rst`` and integrate the output of
 | 
			
		||||
      ``nox -s make_changelog``.
 | 
			
		||||
          - Note that the ``make_changelog`` command inspects
 | 
			
		||||
            `needs changelog <https://github.com/pybind/pybind11/pulls?q=is%3Apr+is%3Aclosed+label%3A%22needs+changelog%22>`_.
 | 
			
		||||
          - Manually clear the ``needs changelog`` labels using the GitHub web
 | 
			
		||||
            interface (very easy: start by clicking the link above).
 | 
			
		||||
    - ``git add`` and ``git commit``, ``git push``. **Ensure CI passes**. (If it
 | 
			
		||||
      fails due to a known flake issue, either ignore or restart CI.)
 | 
			
		||||
- Add a release branch if this is a new minor version, or update the existing release branch if it is a patch version
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,20 @@ 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.11:
 | 
			
		||||
 | 
			
		||||
v2.11
 | 
			
		||||
=====
 | 
			
		||||
 | 
			
		||||
* The minimum version of CMake is now 3.5. A future version will likely move to
 | 
			
		||||
  requiring something like CMake 3.15. Note that CMake 3.27 is removing the
 | 
			
		||||
  long-deprecated support for ``FindPythonInterp`` if you set 3.27 as the
 | 
			
		||||
  minimum or maximum supported version. To prepare for that future, CMake 3.15+
 | 
			
		||||
  using ``FindPython`` or setting ``PYBIND11_FINDPYTHON`` is highly recommended,
 | 
			
		||||
  otherwise pybind11 will automatically switch to using ``FindPython`` if
 | 
			
		||||
  ``FindPythonInterp`` is not available.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.. _upgrade-guide-2.9:
 | 
			
		||||
 | 
			
		||||
v2.9
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,9 @@ struct is_method {
 | 
			
		|||
    explicit is_method(const handle &c) : class_(c) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Annotation for setters
 | 
			
		||||
struct is_setter {};
 | 
			
		||||
 | 
			
		||||
/// Annotation for operators
 | 
			
		||||
struct is_operator {};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -188,8 +191,8 @@ struct argument_record {
 | 
			
		|||
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),
 | 
			
		||||
          prepend(false) {}
 | 
			
		||||
          is_operator(false), is_method(false), is_setter(false), has_args(false),
 | 
			
		||||
          has_kwargs(false), prepend(false) {}
 | 
			
		||||
 | 
			
		||||
    /// Function name
 | 
			
		||||
    char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
 | 
			
		||||
| 
						 | 
				
			
			@ -230,6 +233,9 @@ struct function_record {
 | 
			
		|||
    /// True if this is a method
 | 
			
		||||
    bool is_method : 1;
 | 
			
		||||
 | 
			
		||||
    /// True if this is a setter
 | 
			
		||||
    bool is_setter : 1;
 | 
			
		||||
 | 
			
		||||
    /// True if the function has a '*args' argument
 | 
			
		||||
    bool has_args : 1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -399,7 +405,7 @@ struct process_attribute<doc> : process_attribute_default<doc> {
 | 
			
		|||
template <>
 | 
			
		||||
struct process_attribute<const char *> : process_attribute_default<const char *> {
 | 
			
		||||
    static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); }
 | 
			
		||||
    static void init(const char *d, type_record *r) { r->doc = const_cast<char *>(d); }
 | 
			
		||||
    static void init(const char *d, type_record *r) { r->doc = d; }
 | 
			
		||||
};
 | 
			
		||||
template <>
 | 
			
		||||
struct process_attribute<char *> : process_attribute<const char *> {};
 | 
			
		||||
| 
						 | 
				
			
			@ -426,6 +432,12 @@ struct process_attribute<is_method> : process_attribute_default<is_method> {
 | 
			
		|||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Process an attribute which indicates that this function is a setter
 | 
			
		||||
template <>
 | 
			
		||||
struct process_attribute<is_setter> : process_attribute_default<is_setter> {
 | 
			
		||||
    static void init(const is_setter &, function_record *r) { r->is_setter = true; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Process an attribute which indicates the parent scope of a method
 | 
			
		||||
template <>
 | 
			
		||||
struct process_attribute<scope> : process_attribute_default<scope> {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,6 +37,9 @@ inline std::vector<ssize_t> f_strides(const std::vector<ssize_t> &shape, ssize_t
 | 
			
		|||
    return strides;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename SFINAE = void>
 | 
			
		||||
struct compare_buffer_info;
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
 | 
			
		||||
/// Information record describing a Python buffer object
 | 
			
		||||
| 
						 | 
				
			
			@ -150,6 +153,17 @@ struct buffer_info {
 | 
			
		|||
    Py_buffer *view() const { return m_view; }
 | 
			
		||||
    Py_buffer *&view() { return m_view; }
 | 
			
		||||
 | 
			
		||||
    /* True if the buffer item type is equivalent to `T`. */
 | 
			
		||||
    // To define "equivalent" by example:
 | 
			
		||||
    // `buffer_info::item_type_is_equivalent_to<int>(b)` and
 | 
			
		||||
    // `buffer_info::item_type_is_equivalent_to<long>(b)` may both be true
 | 
			
		||||
    // on some platforms, but `int` and `unsigned` will never be equivalent.
 | 
			
		||||
    // For the ground truth, please inspect `detail::compare_buffer_info<>`.
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    bool item_type_is_equivalent_to() const {
 | 
			
		||||
        return detail::compare_buffer_info<T>::compare(*this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    struct private_ctr_tag {};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -170,9 +184,10 @@ private:
 | 
			
		|||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
 | 
			
		||||
template <typename T, typename SFINAE = void>
 | 
			
		||||
template <typename T, typename SFINAE>
 | 
			
		||||
struct compare_buffer_info {
 | 
			
		||||
    static bool compare(const buffer_info &b) {
 | 
			
		||||
        // NOLINTNEXTLINE(bugprone-sizeof-expression) Needed for `PyObject *`
 | 
			
		||||
        return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,9 @@
 | 
			
		|||
#include <vector>
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
 | 
			
		||||
template <typename type, typename SFINAE = void>
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +91,8 @@ public:
 | 
			
		|||
    template <typename T_,                                                                        \
 | 
			
		||||
              ::pybind11::detail::enable_if_t<                                                    \
 | 
			
		||||
                  std::is_same<type, ::pybind11::detail::remove_cv_t<T_>>::value,                 \
 | 
			
		||||
                  int> = 0>                                                                       \
 | 
			
		||||
                  int>                                                                            \
 | 
			
		||||
              = 0>                                                                                \
 | 
			
		||||
    static ::pybind11::handle cast(                                                               \
 | 
			
		||||
        T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) {             \
 | 
			
		||||
        if (!src)                                                                                 \
 | 
			
		||||
| 
						 | 
				
			
			@ -248,7 +252,7 @@ public:
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    static handle cast(T, return_value_policy /* policy */, handle /* parent */) {
 | 
			
		||||
        return none().inc_ref();
 | 
			
		||||
        return none().release();
 | 
			
		||||
    }
 | 
			
		||||
    PYBIND11_TYPE_CASTER(T, const_name("None"));
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -291,7 +295,7 @@ public:
 | 
			
		|||
        if (ptr) {
 | 
			
		||||
            return capsule(ptr).release();
 | 
			
		||||
        }
 | 
			
		||||
        return none().inc_ref();
 | 
			
		||||
        return none().release();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
| 
						 | 
				
			
			@ -389,7 +393,7 @@ struct string_caster {
 | 
			
		|||
 | 
			
		||||
        // For UTF-8 we avoid the need for a temporary `bytes` object by using
 | 
			
		||||
        // `PyUnicode_AsUTF8AndSize`.
 | 
			
		||||
        if (PYBIND11_SILENCE_MSVC_C4127(UTF_N == 8)) {
 | 
			
		||||
        if (UTF_N == 8) {
 | 
			
		||||
            Py_ssize_t size = -1;
 | 
			
		||||
            const auto *buffer
 | 
			
		||||
                = reinterpret_cast<const CharT *>(PyUnicode_AsUTF8AndSize(load_src.ptr(), &size));
 | 
			
		||||
| 
						 | 
				
			
			@ -416,7 +420,7 @@ struct string_caster {
 | 
			
		|||
            = reinterpret_cast<const CharT *>(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)) {
 | 
			
		||||
        if (UTF_N > 8) {
 | 
			
		||||
            buffer++;
 | 
			
		||||
            length--;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -537,7 +541,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    static handle cast(const CharT *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (src == nullptr) {
 | 
			
		||||
            return pybind11::none().inc_ref();
 | 
			
		||||
            return pybind11::none().release();
 | 
			
		||||
        }
 | 
			
		||||
        return StringCaster::cast(StringType(src), policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -572,7 +576,7 @@ public:
 | 
			
		|||
        // 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) {
 | 
			
		||||
        if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) {
 | 
			
		||||
            auto v0 = static_cast<unsigned char>(value[0]);
 | 
			
		||||
            // low bits only: 0-127
 | 
			
		||||
            // 0b110xxxxx - start of 2-byte sequence
 | 
			
		||||
| 
						 | 
				
			
			@ -598,7 +602,7 @@ public:
 | 
			
		|||
        // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a
 | 
			
		||||
        // surrogate pair with total length 2 instantly indicates a range error (but not a "your
 | 
			
		||||
        // string was too long" error).
 | 
			
		||||
        else if (PYBIND11_SILENCE_MSVC_C4127(StringCaster::UTF_N == 16) && str_len == 2) {
 | 
			
		||||
        else if (StringCaster::UTF_N == 16 && str_len == 2) {
 | 
			
		||||
            one_char = static_cast<CharT>(value[0]);
 | 
			
		||||
            if (one_char >= 0xD800 && one_char < 0xE000) {
 | 
			
		||||
                throw value_error("Character code point not in range(0x10000)");
 | 
			
		||||
| 
						 | 
				
			
			@ -960,7 +964,7 @@ struct move_always<
 | 
			
		|||
    enable_if_t<
 | 
			
		||||
        all_of<move_is_plain_type<T>,
 | 
			
		||||
               negation<is_copy_constructible<T>>,
 | 
			
		||||
               std::is_move_constructible<T>,
 | 
			
		||||
               is_move_constructible<T>,
 | 
			
		||||
               std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>
 | 
			
		||||
    : std::true_type {};
 | 
			
		||||
template <typename T, typename SFINAE = void>
 | 
			
		||||
| 
						 | 
				
			
			@ -971,7 +975,7 @@ struct move_if_unreferenced<
 | 
			
		|||
    enable_if_t<
 | 
			
		||||
        all_of<move_is_plain_type<T>,
 | 
			
		||||
               negation<move_always<T>>,
 | 
			
		||||
               std::is_move_constructible<T>,
 | 
			
		||||
               is_move_constructible<T>,
 | 
			
		||||
               std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>
 | 
			
		||||
    : std::true_type {};
 | 
			
		||||
template <typename T>
 | 
			
		||||
| 
						 | 
				
			
			@ -1013,11 +1017,14 @@ type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &ha
 | 
			
		|||
                  "Internal error: type_caster should only be used for C++ types");
 | 
			
		||||
    if (!conv.load(handle, true)) {
 | 
			
		||||
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
        throw cast_error("Unable to cast Python instance to C++ type (#define "
 | 
			
		||||
                         "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
 | 
			
		||||
        throw cast_error(
 | 
			
		||||
            "Unable to cast Python instance of type "
 | 
			
		||||
            + str(type::handle_of(handle)).cast<std::string>()
 | 
			
		||||
            + " to C++ type '?' (#define "
 | 
			
		||||
              "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
 | 
			
		||||
#else
 | 
			
		||||
        throw cast_error("Unable to cast Python instance of type "
 | 
			
		||||
                         + (std::string) str(type::handle_of(handle)) + " to C++ type '"
 | 
			
		||||
                         + str(type::handle_of(handle)).cast<std::string>() + " to C++ type '"
 | 
			
		||||
                         + type_id<T>() + "'");
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1034,7 +1041,11 @@ make_caster<T> load_type(const handle &handle) {
 | 
			
		|||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
 | 
			
		||||
// pytype -> C++ type
 | 
			
		||||
template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = 0>
 | 
			
		||||
template <typename T,
 | 
			
		||||
          detail::enable_if_t<!detail::is_pyobject<T>::value
 | 
			
		||||
                                  && !detail::is_same_ignoring_cvref<T, PyObject *>::value,
 | 
			
		||||
                              int>
 | 
			
		||||
          = 0>
 | 
			
		||||
T cast(const handle &handle) {
 | 
			
		||||
    using namespace detail;
 | 
			
		||||
    static_assert(!cast_is_temporary_value_reference<T>::value,
 | 
			
		||||
| 
						 | 
				
			
			@ -1048,6 +1059,34 @@ T cast(const handle &handle) {
 | 
			
		|||
    return T(reinterpret_borrow<object>(handle));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Note that `cast<PyObject *>(obj)` increments the reference count of `obj`.
 | 
			
		||||
// This is necessary for the case that `obj` is a temporary, and could
 | 
			
		||||
// not possibly be different, given
 | 
			
		||||
// 1. the established convention that the passed `handle` is borrowed, and
 | 
			
		||||
// 2. we don't want to force all generic code using `cast<T>()` to special-case
 | 
			
		||||
//    handling of `T` = `PyObject *` (to increment the reference count there).
 | 
			
		||||
// It is the responsibility of the caller to ensure that the reference count
 | 
			
		||||
// is decremented.
 | 
			
		||||
template <typename T,
 | 
			
		||||
          typename Handle,
 | 
			
		||||
          detail::enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value
 | 
			
		||||
                                  && detail::is_same_ignoring_cvref<Handle, handle>::value,
 | 
			
		||||
                              int>
 | 
			
		||||
          = 0>
 | 
			
		||||
T cast(Handle &&handle) {
 | 
			
		||||
    return handle.inc_ref().ptr();
 | 
			
		||||
}
 | 
			
		||||
// To optimize way an inc_ref/dec_ref cycle:
 | 
			
		||||
template <typename T,
 | 
			
		||||
          typename Object,
 | 
			
		||||
          detail::enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value
 | 
			
		||||
                                  && detail::is_same_ignoring_cvref<Object, object>::value,
 | 
			
		||||
                              int>
 | 
			
		||||
          = 0>
 | 
			
		||||
T cast(Object &&obj) {
 | 
			
		||||
    return obj.release().ptr();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// C++ type -> py::object
 | 
			
		||||
template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = 0>
 | 
			
		||||
object cast(T &&value,
 | 
			
		||||
| 
						 | 
				
			
			@ -1081,12 +1120,13 @@ detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
 | 
			
		|||
    if (obj.ref_count() > 1) {
 | 
			
		||||
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
        throw cast_error(
 | 
			
		||||
            "Unable to cast Python instance to C++ rvalue: instance has multiple references"
 | 
			
		||||
            " (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
 | 
			
		||||
            "Unable to cast Python " + str(type::handle_of(obj)).cast<std::string>()
 | 
			
		||||
            + " instance to C++ rvalue: instance has multiple references"
 | 
			
		||||
              " (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
 | 
			
		||||
#else
 | 
			
		||||
        throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj))
 | 
			
		||||
                         + " instance to C++ " + type_id<T>()
 | 
			
		||||
                         + " instance: instance has multiple references");
 | 
			
		||||
        throw cast_error("Unable to move from Python "
 | 
			
		||||
                         + str(type::handle_of(obj)).cast<std::string>() + " instance to C++ "
 | 
			
		||||
                         + type_id<T>() + " instance: instance has multiple references");
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1179,11 +1219,9 @@ enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&)
 | 
			
		|||
    pybind11_fail("Internal error: cast_safe fallback invoked");
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
enable_if_t<std::is_same<void, intrinsic_t<T>>::value, void> cast_safe(object &&) {}
 | 
			
		||||
enable_if_t<std::is_void<T>::value, void> cast_safe(object &&) {}
 | 
			
		||||
template <typename T>
 | 
			
		||||
enable_if_t<detail::none_of<cast_is_temporary_value_reference<T>,
 | 
			
		||||
                            std::is_same<void, intrinsic_t<T>>>::value,
 | 
			
		||||
            T>
 | 
			
		||||
enable_if_t<detail::none_of<cast_is_temporary_value_reference<T>, std::is_void<T>>::value, T>
 | 
			
		||||
cast_safe(object &&o) {
 | 
			
		||||
    return pybind11::cast<T>(std::move(o));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1193,9 +1231,10 @@ PYBIND11_NAMESPACE_END(detail)
 | 
			
		|||
// The overloads could coexist, i.e. the #if is not strictly speaking needed,
 | 
			
		||||
// but it is an easy minor optimization.
 | 
			
		||||
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
inline cast_error cast_error_unable_to_convert_call_arg() {
 | 
			
		||||
    return cast_error("Unable to convert call argument to Python object (#define "
 | 
			
		||||
                      "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
 | 
			
		||||
inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name) {
 | 
			
		||||
    return cast_error("Unable to convert call argument '" + name
 | 
			
		||||
                      + "' to Python object (#define "
 | 
			
		||||
                        "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name,
 | 
			
		||||
| 
						 | 
				
			
			@ -1218,7 +1257,7 @@ tuple make_tuple(Args &&...args_) {
 | 
			
		|||
    for (size_t i = 0; i < args.size(); i++) {
 | 
			
		||||
        if (!args[i]) {
 | 
			
		||||
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
            throw cast_error_unable_to_convert_call_arg();
 | 
			
		||||
            throw cast_error_unable_to_convert_call_arg(std::to_string(i));
 | 
			
		||||
#else
 | 
			
		||||
            std::array<std::string, size> argtypes{{type_id<Args>()...}};
 | 
			
		||||
            throw cast_error_unable_to_convert_call_arg(std::to_string(i), argtypes[i]);
 | 
			
		||||
| 
						 | 
				
			
			@ -1508,7 +1547,7 @@ private:
 | 
			
		|||
            detail::make_caster<T>::cast(std::forward<T>(x), policy, {}));
 | 
			
		||||
        if (!o) {
 | 
			
		||||
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
            throw cast_error_unable_to_convert_call_arg();
 | 
			
		||||
            throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()));
 | 
			
		||||
#else
 | 
			
		||||
            throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()),
 | 
			
		||||
                                                        type_id<T>());
 | 
			
		||||
| 
						 | 
				
			
			@ -1540,12 +1579,12 @@ private:
 | 
			
		|||
        }
 | 
			
		||||
        if (!a.value) {
 | 
			
		||||
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
            throw cast_error_unable_to_convert_call_arg();
 | 
			
		||||
            throw cast_error_unable_to_convert_call_arg(a.name);
 | 
			
		||||
#else
 | 
			
		||||
            throw cast_error_unable_to_convert_call_arg(a.name, a.type);
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
        m_kwargs[a.name] = a.value;
 | 
			
		||||
        m_kwargs[a.name] = std::move(a.value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void process(list & /*args_list*/, detail::kwargs_proxy kp) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,9 @@ extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObjec
 | 
			
		|||
    return PyProperty_Type.tp_descr_set(self, cls, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Forward declaration to use in `make_static_property_type()`
 | 
			
		||||
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type);
 | 
			
		||||
 | 
			
		||||
/** A `static_property` is the same as a `property` but the `__get__()` and `__set__()`
 | 
			
		||||
    methods are modified to always use the object type instead of a concrete instance.
 | 
			
		||||
    Return value: New reference. */
 | 
			
		||||
| 
						 | 
				
			
			@ -87,6 +90,13 @@ inline PyTypeObject *make_static_property_type() {
 | 
			
		|||
        pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#    if PY_VERSION_HEX >= 0x030C0000
 | 
			
		||||
    // PRE 3.12 FEATURE FREEZE. PLEASE REVIEW AFTER FREEZE.
 | 
			
		||||
    // Since Python-3.12 property-derived types are required to
 | 
			
		||||
    // have dynamic attributes (to set `__doc__`)
 | 
			
		||||
    enable_dynamic_attributes(heap_type);
 | 
			
		||||
#    endif
 | 
			
		||||
 | 
			
		||||
    setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
 | 
			
		||||
    PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -435,9 +445,17 @@ inline void clear_instance(PyObject *self) {
 | 
			
		|||
/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc`
 | 
			
		||||
/// to destroy the C++ object itself, while the rest is Python bookkeeping.
 | 
			
		||||
extern "C" inline void pybind11_object_dealloc(PyObject *self) {
 | 
			
		||||
    auto *type = Py_TYPE(self);
 | 
			
		||||
 | 
			
		||||
    // If this is a GC tracked object, untrack it first
 | 
			
		||||
    // Note that the track call is implicitly done by the
 | 
			
		||||
    // default tp_alloc, which we never override.
 | 
			
		||||
    if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC) != 0) {
 | 
			
		||||
        PyObject_GC_UnTrack(self);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    clear_instance(self);
 | 
			
		||||
 | 
			
		||||
    auto *type = Py_TYPE(self);
 | 
			
		||||
    type->tp_free(self);
 | 
			
		||||
 | 
			
		||||
#if PY_VERSION_HEX < 0x03080000
 | 
			
		||||
| 
						 | 
				
			
			@ -502,31 +520,6 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
 | 
			
		|||
    return (PyObject *) heap_type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// dynamic_attr: Support for `d = instance.__dict__`.
 | 
			
		||||
extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
 | 
			
		||||
    PyObject *&dict = *_PyObject_GetDictPtr(self);
 | 
			
		||||
    if (!dict) {
 | 
			
		||||
        dict = PyDict_New();
 | 
			
		||||
    }
 | 
			
		||||
    Py_XINCREF(dict);
 | 
			
		||||
    return dict;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// dynamic_attr: Support for `instance.__dict__ = dict()`.
 | 
			
		||||
extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) {
 | 
			
		||||
    if (!PyDict_Check(new_dict)) {
 | 
			
		||||
        PyErr_Format(PyExc_TypeError,
 | 
			
		||||
                     "__dict__ must be set to a dictionary, not a '%.200s'",
 | 
			
		||||
                     get_fully_qualified_tp_name(Py_TYPE(new_dict)).c_str());
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    PyObject *&dict = *_PyObject_GetDictPtr(self);
 | 
			
		||||
    Py_INCREF(new_dict);
 | 
			
		||||
    Py_CLEAR(dict);
 | 
			
		||||
    dict = new_dict;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
 | 
			
		||||
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
 | 
			
		||||
    PyObject *&dict = *_PyObject_GetDictPtr(self);
 | 
			
		||||
| 
						 | 
				
			
			@ -558,9 +551,17 @@ inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
 | 
			
		|||
    type->tp_traverse = pybind11_traverse;
 | 
			
		||||
    type->tp_clear = pybind11_clear;
 | 
			
		||||
 | 
			
		||||
    static PyGetSetDef getset[] = {
 | 
			
		||||
        {const_cast<char *>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr},
 | 
			
		||||
        {nullptr, nullptr, nullptr, nullptr, nullptr}};
 | 
			
		||||
    static PyGetSetDef getset[] = {{
 | 
			
		||||
#if PY_VERSION_HEX < 0x03070000
 | 
			
		||||
                                       const_cast<char *>("__dict__"),
 | 
			
		||||
#else
 | 
			
		||||
                                       "__dict__",
 | 
			
		||||
#endif
 | 
			
		||||
                                       PyObject_GenericGetDict,
 | 
			
		||||
                                       PyObject_GenericSetDict,
 | 
			
		||||
                                       nullptr,
 | 
			
		||||
                                       nullptr},
 | 
			
		||||
                                   {nullptr, nullptr, nullptr, nullptr, nullptr}};
 | 
			
		||||
    type->tp_getset = getset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,15 +10,76 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define PYBIND11_VERSION_MAJOR 2
 | 
			
		||||
#define PYBIND11_VERSION_MINOR 10
 | 
			
		||||
#define PYBIND11_VERSION_PATCH 0
 | 
			
		||||
#define PYBIND11_VERSION_MINOR 11
 | 
			
		||||
#define PYBIND11_VERSION_PATCH 1
 | 
			
		||||
 | 
			
		||||
// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html
 | 
			
		||||
// Additional convention: 0xD = dev
 | 
			
		||||
#define PYBIND11_VERSION_HEX 0x020A0000
 | 
			
		||||
#define PYBIND11_VERSION_HEX 0x020B0100
 | 
			
		||||
 | 
			
		||||
#define PYBIND11_NAMESPACE_BEGIN(name) namespace name {
 | 
			
		||||
#define PYBIND11_NAMESPACE_END(name) }
 | 
			
		||||
// Define some generic pybind11 helper macros for warning management.
 | 
			
		||||
//
 | 
			
		||||
// Note that compiler-specific push/pop pairs are baked into the
 | 
			
		||||
// PYBIND11_NAMESPACE_BEGIN/PYBIND11_NAMESPACE_END pair of macros. Therefore manual
 | 
			
		||||
// PYBIND11_WARNING_PUSH/PYBIND11_WARNING_POP are usually only needed in `#include` sections.
 | 
			
		||||
//
 | 
			
		||||
// If you find you need to suppress a warning, please try to make the suppression as local as
 | 
			
		||||
// possible using these macros. Please also be sure to push/pop with the pybind11 macros. Please
 | 
			
		||||
// only use compiler specifics if you need to check specific versions, e.g. Apple Clang vs. vanilla
 | 
			
		||||
// Clang.
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#    define PYBIND11_COMPILER_MSVC
 | 
			
		||||
#    define PYBIND11_PRAGMA(...) __pragma(__VA_ARGS__)
 | 
			
		||||
#    define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(warning(push))
 | 
			
		||||
#    define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning(pop))
 | 
			
		||||
#elif defined(__INTEL_COMPILER)
 | 
			
		||||
#    define PYBIND11_COMPILER_INTEL
 | 
			
		||||
#    define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)
 | 
			
		||||
#    define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(warning push)
 | 
			
		||||
#    define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning pop)
 | 
			
		||||
#elif defined(__clang__)
 | 
			
		||||
#    define PYBIND11_COMPILER_CLANG
 | 
			
		||||
#    define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)
 | 
			
		||||
#    define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(clang diagnostic push)
 | 
			
		||||
#    define PYBIND11_WARNING_POP PYBIND11_PRAGMA(clang diagnostic push)
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
#    define PYBIND11_COMPILER_GCC
 | 
			
		||||
#    define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)
 | 
			
		||||
#    define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(GCC diagnostic push)
 | 
			
		||||
#    define PYBIND11_WARNING_POP PYBIND11_PRAGMA(GCC diagnostic pop)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef PYBIND11_COMPILER_MSVC
 | 
			
		||||
#    define PYBIND11_WARNING_DISABLE_MSVC(name) PYBIND11_PRAGMA(warning(disable : name))
 | 
			
		||||
#else
 | 
			
		||||
#    define PYBIND11_WARNING_DISABLE_MSVC(name)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef PYBIND11_COMPILER_CLANG
 | 
			
		||||
#    define PYBIND11_WARNING_DISABLE_CLANG(name) PYBIND11_PRAGMA(clang diagnostic ignored name)
 | 
			
		||||
#else
 | 
			
		||||
#    define PYBIND11_WARNING_DISABLE_CLANG(name)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef PYBIND11_COMPILER_GCC
 | 
			
		||||
#    define PYBIND11_WARNING_DISABLE_GCC(name) PYBIND11_PRAGMA(GCC diagnostic ignored name)
 | 
			
		||||
#else
 | 
			
		||||
#    define PYBIND11_WARNING_DISABLE_GCC(name)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef PYBIND11_COMPILER_INTEL
 | 
			
		||||
#    define PYBIND11_WARNING_DISABLE_INTEL(name) PYBIND11_PRAGMA(warning disable name)
 | 
			
		||||
#else
 | 
			
		||||
#    define PYBIND11_WARNING_DISABLE_INTEL(name)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define PYBIND11_NAMESPACE_BEGIN(name)                                                            \
 | 
			
		||||
    namespace name {                                                                              \
 | 
			
		||||
    PYBIND11_WARNING_PUSH
 | 
			
		||||
 | 
			
		||||
#define PYBIND11_NAMESPACE_END(name)                                                              \
 | 
			
		||||
    PYBIND11_WARNING_POP                                                                          \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
// Robust support for some features and loading modules compiled against different pybind versions
 | 
			
		||||
// requires forcing hidden visibility on pybind code, so we enforce this by setting the attribute
 | 
			
		||||
| 
						 | 
				
			
			@ -96,13 +157,10 @@
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#if !defined(PYBIND11_EXPORT_EXCEPTION)
 | 
			
		||||
#    ifdef __MINGW32__
 | 
			
		||||
// workaround for:
 | 
			
		||||
// error: 'dllexport' implies default visibility, but xxx has already been declared with a
 | 
			
		||||
// different visibility
 | 
			
		||||
#        define PYBIND11_EXPORT_EXCEPTION
 | 
			
		||||
#    else
 | 
			
		||||
#    if defined(__apple_build_version__)
 | 
			
		||||
#        define PYBIND11_EXPORT_EXCEPTION PYBIND11_EXPORT
 | 
			
		||||
#    else
 | 
			
		||||
#        define PYBIND11_EXPORT_EXCEPTION
 | 
			
		||||
#    endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -154,9 +212,9 @@
 | 
			
		|||
 | 
			
		||||
/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#    pragma warning(push)
 | 
			
		||||
PYBIND11_WARNING_PUSH
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4505)
 | 
			
		||||
// C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed (PyPy only)
 | 
			
		||||
#    pragma warning(disable : 4505)
 | 
			
		||||
#    if defined(_DEBUG) && !defined(Py_DEBUG)
 | 
			
		||||
// Workaround for a VS 2022 issue.
 | 
			
		||||
// NOTE: This workaround knowingly violates the Python.h include order requirement:
 | 
			
		||||
| 
						 | 
				
			
			@ -205,11 +263,8 @@
 | 
			
		|||
#    endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L
 | 
			
		||||
#    define PYBIND11_HAS_U8STRING
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <Python.h>
 | 
			
		||||
// Reminder: WITH_THREAD is always defined if PY_VERSION_HEX >= 0x03070000
 | 
			
		||||
#if PY_VERSION_HEX < 0x03060000
 | 
			
		||||
#    error "PYTHON < 3.6 IS UNSUPPORTED. pybind11 v2.9 was the last to support Python 2 and 3.5."
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -233,12 +288,16 @@
 | 
			
		|||
#    undef copysign
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(PYPY_VERSION) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
 | 
			
		||||
#    define PYBIND11_SIMPLE_GIL_MANAGEMENT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#    if defined(PYBIND11_DEBUG_MARKER)
 | 
			
		||||
#        define _DEBUG
 | 
			
		||||
#        undef PYBIND11_DEBUG_MARKER
 | 
			
		||||
#    endif
 | 
			
		||||
#    pragma warning(pop)
 | 
			
		||||
PYBIND11_WARNING_POP
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
| 
						 | 
				
			
			@ -259,6 +318,17 @@
 | 
			
		|||
#    endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Must be after including <version> or one of the other headers specified by the standard
 | 
			
		||||
#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L
 | 
			
		||||
#    define PYBIND11_HAS_U8STRING
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// See description of PR #4246:
 | 
			
		||||
#if !defined(PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF) && !defined(NDEBUG)                       \
 | 
			
		||||
    && !defined(PYPY_VERSION) && !defined(PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF)
 | 
			
		||||
#    define PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// #define PYBIND11_STR_LEGACY_PERMISSIVE
 | 
			
		||||
// If DEFINED, pybind11::str can hold PyUnicodeObject or PyBytesObject
 | 
			
		||||
//             (probably surprising and never documented, but this was the
 | 
			
		||||
| 
						 | 
				
			
			@ -363,7 +433,7 @@
 | 
			
		|||
 | 
			
		||||
/** \rst
 | 
			
		||||
    This macro creates the entry point that will be invoked when the Python interpreter
 | 
			
		||||
    imports an extension module. The module name is given as the fist argument and it
 | 
			
		||||
    imports an extension module. The module name is given as the first argument and it
 | 
			
		||||
    should not be in quotes. The second macro argument defines a variable of type
 | 
			
		||||
    `py::module_` which can be used to initialize the module.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -588,6 +658,10 @@ template <class T>
 | 
			
		|||
using remove_cvref_t = typename remove_cvref<T>::type;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/// Example usage: is_same_ignoring_cvref<T, PyObject *>::value
 | 
			
		||||
template <typename T, typename U>
 | 
			
		||||
using is_same_ignoring_cvref = std::is_same<detail::remove_cvref_t<T>, U>;
 | 
			
		||||
 | 
			
		||||
/// Index sequences
 | 
			
		||||
#if defined(PYBIND11_CPP14)
 | 
			
		||||
using std::index_sequence;
 | 
			
		||||
| 
						 | 
				
			
			@ -681,7 +755,16 @@ template <typename C, typename R, typename... A>
 | 
			
		|||
struct remove_class<R (C::*)(A...) const> {
 | 
			
		||||
    using type = R(A...);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef __cpp_noexcept_function_type
 | 
			
		||||
template <typename C, typename R, typename... A>
 | 
			
		||||
struct remove_class<R (C::*)(A...) noexcept> {
 | 
			
		||||
    using type = R(A...);
 | 
			
		||||
};
 | 
			
		||||
template <typename C, typename R, typename... A>
 | 
			
		||||
struct remove_class<R (C::*)(A...) const noexcept> {
 | 
			
		||||
    using type = R(A...);
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
/// Helper template to strip away type modifiers
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct intrinsic_type {
 | 
			
		||||
| 
						 | 
				
			
			@ -898,12 +981,6 @@ using expand_side_effects = bool[];
 | 
			
		|||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#    pragma warning(push)
 | 
			
		||||
#    pragma warning(disable : 4275)
 | 
			
		||||
//     warning C4275: An exported class was derived from a class that wasn't exported.
 | 
			
		||||
//     Can be ignored when derived from a STL class.
 | 
			
		||||
#endif
 | 
			
		||||
/// C++ bindings of builtin Python exceptions
 | 
			
		||||
class PYBIND11_EXPORT_EXCEPTION builtin_exception : public std::runtime_error {
 | 
			
		||||
public:
 | 
			
		||||
| 
						 | 
				
			
			@ -911,9 +988,6 @@ public:
 | 
			
		|||
    /// Set the error using the Python C API
 | 
			
		||||
    virtual void set_error() const = 0;
 | 
			
		||||
};
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#    pragma warning(pop)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define PYBIND11_RUNTIME_EXCEPTION(name, type)                                                    \
 | 
			
		||||
    class PYBIND11_EXPORT_EXCEPTION name : public builtin_exception {                             \
 | 
			
		||||
| 
						 | 
				
			
			@ -948,6 +1022,15 @@ PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used in
 | 
			
		|||
template <typename T, typename SFINAE = void>
 | 
			
		||||
struct format_descriptor {};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct format_descriptor<
 | 
			
		||||
    T,
 | 
			
		||||
    detail::enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value>> {
 | 
			
		||||
    static constexpr const char c = 'O';
 | 
			
		||||
    static constexpr const char value[2] = {c, '\0'};
 | 
			
		||||
    static std::string format() { return std::string(1, c); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
// Returns the index of the given type in the type char array below, and in the list in numpy.h
 | 
			
		||||
// The order here is: bool; 8 ints ((signed,unsigned)x(8,16,32,64)bits); float,double,long double;
 | 
			
		||||
| 
						 | 
				
			
			@ -1033,12 +1116,7 @@ PYBIND11_NAMESPACE_END(detail)
 | 
			
		|||
///  - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func)
 | 
			
		||||
///  - sweet:   overload_cast<Arg0, Arg1, Arg2>(&Class::func)
 | 
			
		||||
template <typename... Args>
 | 
			
		||||
#    if (defined(_MSC_VER) && _MSC_VER < 1920) /* MSVC 2017 */                                    \
 | 
			
		||||
        || (defined(__clang__) && __clang_major__ == 5)
 | 
			
		||||
static constexpr detail::overload_cast_impl<Args...> overload_cast = {};
 | 
			
		||||
#    else
 | 
			
		||||
static constexpr detail::overload_cast_impl<Args...> overload_cast;
 | 
			
		||||
#    endif
 | 
			
		||||
static constexpr detail::overload_cast_impl<Args...> overload_cast{};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/// Const member function selector for overload_cast
 | 
			
		||||
| 
						 | 
				
			
			@ -1147,20 +1225,28 @@ constexpr
 | 
			
		|||
#    define PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) // All versions (as of July 2021).
 | 
			
		||||
 | 
			
		||||
// warning C4127: Conditional expression is constant
 | 
			
		||||
constexpr inline bool silence_msvc_c4127(bool cond) { return cond; }
 | 
			
		||||
 | 
			
		||||
#    define PYBIND11_SILENCE_MSVC_C4127(...) ::pybind11::detail::silence_msvc_c4127(__VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
#    define PYBIND11_SILENCE_MSVC_C4127(...) __VA_ARGS__
 | 
			
		||||
#if defined(__clang__)                                                                            \
 | 
			
		||||
    && (defined(__apple_build_version__) /* AppleClang 13.0.0.13000029 was the only data point    \
 | 
			
		||||
                                            available. */                                         \
 | 
			
		||||
        || (__clang_major__ >= 7                                                                  \
 | 
			
		||||
            && __clang_major__ <= 12) /* Clang 3, 5, 13, 14, 15 do not generate the warning. */   \
 | 
			
		||||
    )
 | 
			
		||||
#    define PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING
 | 
			
		||||
// Example:
 | 
			
		||||
// tests/test_kwargs_and_defaults.cpp:46:68: error: local variable 'args' will be copied despite
 | 
			
		||||
// being returned by name [-Werror,-Wreturn-std-move]
 | 
			
		||||
//     m.def("args_function", [](py::args args) -> py::tuple { return args; });
 | 
			
		||||
//                                                                    ^~~~
 | 
			
		||||
// test_kwargs_and_defaults.cpp:46:68: note: call 'std::move' explicitly to avoid copying
 | 
			
		||||
//     m.def("args_function", [](py::args args) -> py::tuple { return args; });
 | 
			
		||||
//                                                                    ^~~~
 | 
			
		||||
//                                                                    std::move(args)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Pybind offers detailed error messages by default for all builts that are debug (through the
 | 
			
		||||
// negation of ndebug). This can also be manually enabled by users, for any builds, through
 | 
			
		||||
// defining PYBIND11_DETAILED_ERROR_MESSAGES.
 | 
			
		||||
// negation of NDEBUG). This can also be manually enabled by users, for any builds, through
 | 
			
		||||
// defining PYBIND11_DETAILED_ERROR_MESSAGES. This information is primarily useful for those
 | 
			
		||||
// who are writing (as opposed to merely using) libraries that use pybind11.
 | 
			
		||||
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) && !defined(NDEBUG)
 | 
			
		||||
#    define PYBIND11_DETAILED_ERROR_MESSAGES
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -143,11 +143,24 @@ constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) {
 | 
			
		|||
    return descr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __cpp_fold_expressions
 | 
			
		||||
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
 | 
			
		||||
constexpr descr<N1 + N2 + 2, Ts1..., Ts2...> operator,(const descr<N1, Ts1...> &a,
 | 
			
		||||
                                                       const descr<N2, Ts2...> &b) {
 | 
			
		||||
    return a + const_name(", ") + b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <size_t N, typename... Ts, typename... Args>
 | 
			
		||||
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) {
 | 
			
		||||
    return (d, ..., args);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
template <size_t N, typename... Ts, typename... Args>
 | 
			
		||||
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
 | 
			
		||||
    -> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
 | 
			
		||||
    return d + const_name(", ") + concat(args...);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
template <size_t N, typename... Ts>
 | 
			
		||||
constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,9 @@
 | 
			
		|||
#include "class.h"
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +118,7 @@ template <typename Class>
 | 
			
		|||
void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
 | 
			
		||||
    PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
 | 
			
		||||
    no_nullptr(ptr);
 | 
			
		||||
    if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) {
 | 
			
		||||
    if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
 | 
			
		||||
        // We're going to try to construct an alias by moving the cpp type.  Whether or not
 | 
			
		||||
        // that succeeds, we still need to destroy the original cpp pointer (either the
 | 
			
		||||
        // moved away leftover, if the alias construction works, or the value itself if we
 | 
			
		||||
| 
						 | 
				
			
			@ -156,7 +159,7 @@ void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
 | 
			
		|||
    auto *ptr = holder_helper<Holder<Class>>::get(holder);
 | 
			
		||||
    no_nullptr(ptr);
 | 
			
		||||
    // If we need an alias, check that the held pointer is actually an alias instance
 | 
			
		||||
    if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) {
 | 
			
		||||
    if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
 | 
			
		||||
        throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
 | 
			
		||||
                         "is not an alias instance");
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -172,9 +175,9 @@ void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
 | 
			
		|||
template <typename Class>
 | 
			
		||||
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
 | 
			
		||||
    PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
 | 
			
		||||
    static_assert(std::is_move_constructible<Cpp<Class>>::value,
 | 
			
		||||
    static_assert(is_move_constructible<Cpp<Class>>::value,
 | 
			
		||||
                  "pybind11::init() return-by-value factory function requires a movable class");
 | 
			
		||||
    if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias) {
 | 
			
		||||
    if (Class::has_alias && need_alias) {
 | 
			
		||||
        construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
 | 
			
		||||
    } else {
 | 
			
		||||
        v_h.value_ptr() = new Cpp<Class>(std::move(result));
 | 
			
		||||
| 
						 | 
				
			
			@ -187,7 +190,7 @@ void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
 | 
			
		|||
template <typename Class>
 | 
			
		||||
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
 | 
			
		||||
    static_assert(
 | 
			
		||||
        std::is_move_constructible<Alias<Class>>::value,
 | 
			
		||||
        is_move_constructible<Alias<Class>>::value,
 | 
			
		||||
        "pybind11::init() return-by-alias-value factory function requires a movable alias class");
 | 
			
		||||
    v_h.value_ptr() = new Alias<Class>(std::move(result));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -206,10 +209,11 @@ struct constructor {
 | 
			
		|||
            extra...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Class,
 | 
			
		||||
              typename... Extra,
 | 
			
		||||
              enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value,
 | 
			
		||||
                          int> = 0>
 | 
			
		||||
    template <
 | 
			
		||||
        typename Class,
 | 
			
		||||
        typename... Extra,
 | 
			
		||||
        enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value, int>
 | 
			
		||||
        = 0>
 | 
			
		||||
    static void execute(Class &cl, const Extra &...extra) {
 | 
			
		||||
        cl.def(
 | 
			
		||||
            "__init__",
 | 
			
		||||
| 
						 | 
				
			
			@ -226,10 +230,11 @@ struct constructor {
 | 
			
		|||
            extra...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Class,
 | 
			
		||||
              typename... Extra,
 | 
			
		||||
              enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value,
 | 
			
		||||
                          int> = 0>
 | 
			
		||||
    template <
 | 
			
		||||
        typename Class,
 | 
			
		||||
        typename... Extra,
 | 
			
		||||
        enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value, int>
 | 
			
		||||
        = 0>
 | 
			
		||||
    static void execute(Class &cl, const Extra &...extra) {
 | 
			
		||||
        cl.def(
 | 
			
		||||
            "__init__",
 | 
			
		||||
| 
						 | 
				
			
			@ -245,10 +250,11 @@ struct constructor {
 | 
			
		|||
// Implementing class for py::init_alias<...>()
 | 
			
		||||
template <typename... Args>
 | 
			
		||||
struct alias_constructor {
 | 
			
		||||
    template <typename Class,
 | 
			
		||||
              typename... Extra,
 | 
			
		||||
              enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value,
 | 
			
		||||
                          int> = 0>
 | 
			
		||||
    template <
 | 
			
		||||
        typename Class,
 | 
			
		||||
        typename... Extra,
 | 
			
		||||
        enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int>
 | 
			
		||||
        = 0>
 | 
			
		||||
    static void execute(Class &cl, const Extra &...extra) {
 | 
			
		||||
        cl.def(
 | 
			
		||||
            "__init__",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,12 @@
 | 
			
		|||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "common.h"
 | 
			
		||||
 | 
			
		||||
#if defined(WITH_THREAD) && defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
 | 
			
		||||
#    include "../gil.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "../pytypes.h"
 | 
			
		||||
 | 
			
		||||
#include <exception>
 | 
			
		||||
| 
						 | 
				
			
			@ -28,15 +34,26 @@
 | 
			
		|||
/// further ABI-incompatible changes may be made before the ABI is officially
 | 
			
		||||
/// changed to the new version.
 | 
			
		||||
#ifndef PYBIND11_INTERNALS_VERSION
 | 
			
		||||
#    define PYBIND11_INTERNALS_VERSION 4
 | 
			
		||||
#    if PY_VERSION_HEX >= 0x030C0000
 | 
			
		||||
// Version bump for Python 3.12+, before first 3.12 beta release.
 | 
			
		||||
#        define PYBIND11_INTERNALS_VERSION 5
 | 
			
		||||
#    else
 | 
			
		||||
#        define PYBIND11_INTERNALS_VERSION 4
 | 
			
		||||
#    endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// This requirement is mainly to reduce the support burden (see PR #4570).
 | 
			
		||||
static_assert(PY_VERSION_HEX < 0x030C0000 || PYBIND11_INTERNALS_VERSION >= 5,
 | 
			
		||||
              "pybind11 ABI version 5 is the minimum for Python 3.12+");
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
 | 
			
		||||
using ExceptionTranslator = void (*)(std::exception_ptr);
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
 | 
			
		||||
constexpr const char *internals_function_record_capsule_name = "pybind11_function_record_capsule";
 | 
			
		||||
 | 
			
		||||
// Forward declarations
 | 
			
		||||
inline PyTypeObject *make_static_property_type();
 | 
			
		||||
inline PyTypeObject *make_default_metaclass();
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +66,7 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
 | 
			
		|||
// `Py_LIMITED_API` anyway.
 | 
			
		||||
#    if PYBIND11_INTERNALS_VERSION > 4
 | 
			
		||||
#        define PYBIND11_TLS_KEY_REF Py_tss_t &
 | 
			
		||||
#        ifdef __GNUC__
 | 
			
		||||
#        if defined(__GNUC__) && !defined(__INTEL_COMPILER)
 | 
			
		||||
// Clang on macOS warns due to `Py_tss_NEEDS_INIT` not specifying an initializer
 | 
			
		||||
// for every field.
 | 
			
		||||
#            define PYBIND11_TLS_KEY_INIT(var)                                                    \
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +123,8 @@ inline void tls_replace_value(PYBIND11_TLS_KEY_REF key, void *value) {
 | 
			
		|||
// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name,
 | 
			
		||||
// which works.  If not under a known-good stl, provide our own name-based hash and equality
 | 
			
		||||
// functions that use the type name.
 | 
			
		||||
#if defined(__GLIBCXX__)
 | 
			
		||||
#if (PYBIND11_INTERNALS_VERSION <= 4 && defined(__GLIBCXX__))                                     \
 | 
			
		||||
    || (PYBIND11_INTERNALS_VERSION >= 5 && !defined(_LIBCPP_VERSION))
 | 
			
		||||
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; }
 | 
			
		||||
using type_hash = std::hash<std::type_index>;
 | 
			
		||||
using type_equal_to = std::equal_to<std::type_index>;
 | 
			
		||||
| 
						 | 
				
			
			@ -169,11 +187,23 @@ struct internals {
 | 
			
		|||
    PyTypeObject *default_metaclass;
 | 
			
		||||
    PyObject *instance_base;
 | 
			
		||||
#if defined(WITH_THREAD)
 | 
			
		||||
    // Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
 | 
			
		||||
    PYBIND11_TLS_KEY_INIT(tstate)
 | 
			
		||||
#    if PYBIND11_INTERNALS_VERSION > 4
 | 
			
		||||
    PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
 | 
			
		||||
#    endif // PYBIND11_INTERNALS_VERSION > 4
 | 
			
		||||
    // Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
 | 
			
		||||
    PyInterpreterState *istate = nullptr;
 | 
			
		||||
 | 
			
		||||
#    if PYBIND11_INTERNALS_VERSION > 4
 | 
			
		||||
    // Note that we have to use a std::string to allocate memory to ensure a unique address
 | 
			
		||||
    // We want unique addresses since we use pointer equality to compare function records
 | 
			
		||||
    std::string function_record_capsule_name = internals_function_record_capsule_name;
 | 
			
		||||
#    endif
 | 
			
		||||
 | 
			
		||||
    internals() = default;
 | 
			
		||||
    internals(const internals &other) = delete;
 | 
			
		||||
    internals &operator=(const internals &other) = delete;
 | 
			
		||||
    ~internals() {
 | 
			
		||||
#    if PYBIND11_INTERNALS_VERSION > 4
 | 
			
		||||
        PYBIND11_TLS_FREE(loader_life_support_tls_key);
 | 
			
		||||
| 
						 | 
				
			
			@ -401,6 +431,38 @@ inline void translate_local_exception(std::exception_ptr p) {
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
inline object get_python_state_dict() {
 | 
			
		||||
    object state_dict;
 | 
			
		||||
#if PYBIND11_INTERNALS_VERSION <= 4 || PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)
 | 
			
		||||
    state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins());
 | 
			
		||||
#else
 | 
			
		||||
#    if PY_VERSION_HEX < 0x03090000
 | 
			
		||||
    PyInterpreterState *istate = _PyInterpreterState_Get();
 | 
			
		||||
#    else
 | 
			
		||||
    PyInterpreterState *istate = PyInterpreterState_Get();
 | 
			
		||||
#    endif
 | 
			
		||||
    if (istate) {
 | 
			
		||||
        state_dict = reinterpret_borrow<object>(PyInterpreterState_GetDict(istate));
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    if (!state_dict) {
 | 
			
		||||
        raise_from(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED");
 | 
			
		||||
    }
 | 
			
		||||
    return state_dict;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline object get_internals_obj_from_state_dict(handle state_dict) {
 | 
			
		||||
    return reinterpret_borrow<object>(dict_getitemstring(state_dict.ptr(), PYBIND11_INTERNALS_ID));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline internals **get_internals_pp_from_capsule(handle obj) {
 | 
			
		||||
    void *raw_ptr = PyCapsule_GetPointer(obj.ptr(), /*name=*/nullptr);
 | 
			
		||||
    if (raw_ptr == nullptr) {
 | 
			
		||||
        raise_from(PyExc_SystemError, "pybind11::detail::get_internals_pp_from_capsule() FAILED");
 | 
			
		||||
    }
 | 
			
		||||
    return static_cast<internals **>(raw_ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Return a reference to the current `internals` data
 | 
			
		||||
PYBIND11_NOINLINE internals &get_internals() {
 | 
			
		||||
    auto **&internals_pp = get_internals_pp();
 | 
			
		||||
| 
						 | 
				
			
			@ -408,21 +470,29 @@ PYBIND11_NOINLINE internals &get_internals() {
 | 
			
		|||
        return **internals_pp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if defined(WITH_THREAD)
 | 
			
		||||
#    if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
 | 
			
		||||
    gil_scoped_acquire gil;
 | 
			
		||||
#    else
 | 
			
		||||
    // Ensure that the GIL is held since we will need to make Python calls.
 | 
			
		||||
    // Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
 | 
			
		||||
    struct gil_scoped_acquire_local {
 | 
			
		||||
        gil_scoped_acquire_local() : state(PyGILState_Ensure()) {}
 | 
			
		||||
        gil_scoped_acquire_local(const gil_scoped_acquire_local &) = delete;
 | 
			
		||||
        gil_scoped_acquire_local &operator=(const gil_scoped_acquire_local &) = delete;
 | 
			
		||||
        ~gil_scoped_acquire_local() { PyGILState_Release(state); }
 | 
			
		||||
        const PyGILState_STATE state;
 | 
			
		||||
    } gil;
 | 
			
		||||
#    endif
 | 
			
		||||
#endif
 | 
			
		||||
    error_scope err_scope;
 | 
			
		||||
 | 
			
		||||
    PYBIND11_STR_TYPE id(PYBIND11_INTERNALS_ID);
 | 
			
		||||
    auto builtins = handle(PyEval_GetBuiltins());
 | 
			
		||||
    if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
 | 
			
		||||
        internals_pp = static_cast<internals **>(capsule(builtins[id]));
 | 
			
		||||
 | 
			
		||||
        // We loaded builtins through python's builtins, which means that our `error_already_set`
 | 
			
		||||
    dict state_dict = get_python_state_dict();
 | 
			
		||||
    if (object internals_obj = get_internals_obj_from_state_dict(state_dict)) {
 | 
			
		||||
        internals_pp = get_internals_pp_from_capsule(internals_obj);
 | 
			
		||||
    }
 | 
			
		||||
    if (internals_pp && *internals_pp) {
 | 
			
		||||
        // We loaded the internals through `state_dict`, which means that our `error_already_set`
 | 
			
		||||
        // and `builtin_exception` may be different local classes than the ones set up in the
 | 
			
		||||
        // initial exception translator, below, so add another for our local exception classes.
 | 
			
		||||
        //
 | 
			
		||||
| 
						 | 
				
			
			@ -440,16 +510,15 @@ PYBIND11_NOINLINE internals &get_internals() {
 | 
			
		|||
        internals_ptr = new internals();
 | 
			
		||||
#if defined(WITH_THREAD)
 | 
			
		||||
 | 
			
		||||
#    if PY_VERSION_HEX < 0x03090000
 | 
			
		||||
        PyEval_InitThreads();
 | 
			
		||||
#    endif
 | 
			
		||||
        PyThreadState *tstate = PyThreadState_Get();
 | 
			
		||||
        // NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
 | 
			
		||||
        if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->tstate)) {
 | 
			
		||||
            pybind11_fail("get_internals: could not successfully initialize the tstate TSS key!");
 | 
			
		||||
        }
 | 
			
		||||
        PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate);
 | 
			
		||||
 | 
			
		||||
#    if PYBIND11_INTERNALS_VERSION > 4
 | 
			
		||||
        // NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
 | 
			
		||||
        if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) {
 | 
			
		||||
            pybind11_fail("get_internals: could not successfully initialize the "
 | 
			
		||||
                          "loader_life_support TSS key!");
 | 
			
		||||
| 
						 | 
				
			
			@ -457,7 +526,7 @@ PYBIND11_NOINLINE internals &get_internals() {
 | 
			
		|||
#    endif
 | 
			
		||||
        internals_ptr->istate = tstate->interp;
 | 
			
		||||
#endif
 | 
			
		||||
        builtins[id] = capsule(internals_pp);
 | 
			
		||||
        state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp);
 | 
			
		||||
        internals_ptr->registered_exception_translators.push_front(&translate_exception);
 | 
			
		||||
        internals_ptr->static_property_type = make_static_property_type();
 | 
			
		||||
        internals_ptr->default_metaclass = make_default_metaclass();
 | 
			
		||||
| 
						 | 
				
			
			@ -489,6 +558,7 @@ struct local_internals {
 | 
			
		|||
    struct shared_loader_life_support_data {
 | 
			
		||||
        PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
 | 
			
		||||
        shared_loader_life_support_data() {
 | 
			
		||||
            // NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
 | 
			
		||||
            if (!PYBIND11_TLS_KEY_CREATE(loader_life_support_tls_key)) {
 | 
			
		||||
                pybind11_fail("local_internals: could not successfully initialize the "
 | 
			
		||||
                              "loader_life_support TLS key!");
 | 
			
		||||
| 
						 | 
				
			
			@ -512,8 +582,13 @@ struct local_internals {
 | 
			
		|||
 | 
			
		||||
/// Works like `get_internals`, but for things which are locally registered.
 | 
			
		||||
inline local_internals &get_local_internals() {
 | 
			
		||||
    static local_internals locals;
 | 
			
		||||
    return locals;
 | 
			
		||||
    // Current static can be created in the interpreter finalization routine. If the later will be
 | 
			
		||||
    // destroyed in another static variable destructor, creation of this static there will cause
 | 
			
		||||
    // static deinitialization fiasco. In order to avoid it we avoid destruction of the
 | 
			
		||||
    // local_internals static. One can read more about the problem and current solution here:
 | 
			
		||||
    // https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
 | 
			
		||||
    static auto *locals = new local_internals();
 | 
			
		||||
    return *locals;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its
 | 
			
		||||
| 
						 | 
				
			
			@ -527,6 +602,25 @@ const char *c_str(Args &&...args) {
 | 
			
		|||
    return strings.front().c_str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline const char *get_function_record_capsule_name() {
 | 
			
		||||
#if PYBIND11_INTERNALS_VERSION > 4
 | 
			
		||||
    return get_internals().function_record_capsule_name.c_str();
 | 
			
		||||
#else
 | 
			
		||||
    return nullptr;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Determine whether or not the following capsule contains a pybind11 function record.
 | 
			
		||||
// Note that we use `internals` to make sure that only ABI compatible records are touched.
 | 
			
		||||
//
 | 
			
		||||
// This check is currently used in two places:
 | 
			
		||||
// - An important optimization in functional.h to avoid overhead in C++ -> Python -> C++
 | 
			
		||||
// - The sibling feature of cpp_function to allow overloads
 | 
			
		||||
inline bool is_function_record_capsule(const capsule &cap) {
 | 
			
		||||
    // Pointer equality as we rely on internals() to ensure unique pointers
 | 
			
		||||
    return cap.name() == get_function_record_capsule_name();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
 | 
			
		||||
/// Returns a named pointer that is shared among all extension modules (using the same
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -258,9 +258,9 @@ struct value_and_holder {
 | 
			
		|||
 | 
			
		||||
    // Main constructor for a found value/holder:
 | 
			
		||||
    value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)
 | 
			
		||||
        : inst{i}, index{index}, type{type}, vh{inst->simple_layout
 | 
			
		||||
                                                    ? inst->simple_value_holder
 | 
			
		||||
                                                    : &inst->nonsimple.values_and_holders[vpos]} {}
 | 
			
		||||
        : inst{i}, index{index}, type{type},
 | 
			
		||||
          vh{inst->simple_layout ? inst->simple_value_holder
 | 
			
		||||
                                 : &inst->nonsimple.values_and_holders[vpos]} {}
 | 
			
		||||
 | 
			
		||||
    // Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
 | 
			
		||||
    value_and_holder() = default;
 | 
			
		||||
| 
						 | 
				
			
			@ -822,23 +822,179 @@ using movable_cast_op_type
 | 
			
		|||
                                  typename std::add_rvalue_reference<intrinsic_t<T>>::type,
 | 
			
		||||
                                  typename std::add_lvalue_reference<intrinsic_t<T>>::type>>;
 | 
			
		||||
 | 
			
		||||
// Does the container have a mapped type and is it recursive?
 | 
			
		||||
// Implemented by specializations below.
 | 
			
		||||
template <typename Container, typename SFINAE = void>
 | 
			
		||||
struct container_mapped_type_traits {
 | 
			
		||||
    static constexpr bool has_mapped_type = false;
 | 
			
		||||
    static constexpr bool has_recursive_mapped_type = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Container>
 | 
			
		||||
struct container_mapped_type_traits<
 | 
			
		||||
    Container,
 | 
			
		||||
    typename std::enable_if<
 | 
			
		||||
        std::is_same<typename Container::mapped_type, Container>::value>::type> {
 | 
			
		||||
    static constexpr bool has_mapped_type = true;
 | 
			
		||||
    static constexpr bool has_recursive_mapped_type = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Container>
 | 
			
		||||
struct container_mapped_type_traits<
 | 
			
		||||
    Container,
 | 
			
		||||
    typename std::enable_if<
 | 
			
		||||
        negation<std::is_same<typename Container::mapped_type, Container>>::value>::type> {
 | 
			
		||||
    static constexpr bool has_mapped_type = true;
 | 
			
		||||
    static constexpr bool has_recursive_mapped_type = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Does the container have a value type and is it recursive?
 | 
			
		||||
// Implemented by specializations below.
 | 
			
		||||
template <typename Container, typename SFINAE = void>
 | 
			
		||||
struct container_value_type_traits : std::false_type {
 | 
			
		||||
    static constexpr bool has_value_type = false;
 | 
			
		||||
    static constexpr bool has_recursive_value_type = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Container>
 | 
			
		||||
struct container_value_type_traits<
 | 
			
		||||
    Container,
 | 
			
		||||
    typename std::enable_if<
 | 
			
		||||
        std::is_same<typename Container::value_type, Container>::value>::type> {
 | 
			
		||||
    static constexpr bool has_value_type = true;
 | 
			
		||||
    static constexpr bool has_recursive_value_type = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Container>
 | 
			
		||||
struct container_value_type_traits<
 | 
			
		||||
    Container,
 | 
			
		||||
    typename std::enable_if<
 | 
			
		||||
        negation<std::is_same<typename Container::value_type, Container>>::value>::type> {
 | 
			
		||||
    static constexpr bool has_value_type = true;
 | 
			
		||||
    static constexpr bool has_recursive_value_type = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Tag to be used for representing the bottom of recursively defined types.
 | 
			
		||||
 * Define this tag so we don't have to use void.
 | 
			
		||||
 */
 | 
			
		||||
struct recursive_bottom {};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Implementation detail of `recursive_container_traits` below.
 | 
			
		||||
 * `T` is the `value_type` of the container, which might need to be modified to
 | 
			
		||||
 * avoid recursive types and const types.
 | 
			
		||||
 */
 | 
			
		||||
template <typename T, bool is_this_a_map>
 | 
			
		||||
struct impl_type_to_check_recursively {
 | 
			
		||||
    /*
 | 
			
		||||
     * If the container is recursive, then no further recursion should be done.
 | 
			
		||||
     */
 | 
			
		||||
    using if_recursive = recursive_bottom;
 | 
			
		||||
    /*
 | 
			
		||||
     * Otherwise yield `T` unchanged.
 | 
			
		||||
     */
 | 
			
		||||
    using if_not_recursive = T;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * For pairs - only as value type of a map -, the first type should remove the `const`.
 | 
			
		||||
 * Also, if the map is recursive, then the recursive checking should consider
 | 
			
		||||
 * the first type only.
 | 
			
		||||
 */
 | 
			
		||||
template <typename A, typename B>
 | 
			
		||||
struct impl_type_to_check_recursively<std::pair<A, B>, /* is_this_a_map = */ true> {
 | 
			
		||||
    using if_recursive = typename std::remove_const<A>::type;
 | 
			
		||||
    using if_not_recursive = std::pair<typename std::remove_const<A>::type, B>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Implementation of `recursive_container_traits` below.
 | 
			
		||||
 */
 | 
			
		||||
template <typename Container, typename SFINAE = void>
 | 
			
		||||
struct impl_recursive_container_traits {
 | 
			
		||||
    using type_to_check_recursively = recursive_bottom;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Container>
 | 
			
		||||
struct impl_recursive_container_traits<
 | 
			
		||||
    Container,
 | 
			
		||||
    typename std::enable_if<container_value_type_traits<Container>::has_value_type>::type> {
 | 
			
		||||
    static constexpr bool is_recursive
 | 
			
		||||
        = container_mapped_type_traits<Container>::has_recursive_mapped_type
 | 
			
		||||
          || container_value_type_traits<Container>::has_recursive_value_type;
 | 
			
		||||
    /*
 | 
			
		||||
     * This member dictates which type Pybind11 should check recursively in traits
 | 
			
		||||
     * such as `is_move_constructible`, `is_copy_constructible`, `is_move_assignable`, ...
 | 
			
		||||
     * Direct access to `value_type` should be avoided:
 | 
			
		||||
     * 1. `value_type` might recursively contain the type again
 | 
			
		||||
     * 2. `value_type` of STL map types is `std::pair<A const, B>`, the `const`
 | 
			
		||||
     *    should be removed.
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    using type_to_check_recursively = typename std::conditional<
 | 
			
		||||
        is_recursive,
 | 
			
		||||
        typename impl_type_to_check_recursively<
 | 
			
		||||
            typename Container::value_type,
 | 
			
		||||
            container_mapped_type_traits<Container>::has_mapped_type>::if_recursive,
 | 
			
		||||
        typename impl_type_to_check_recursively<
 | 
			
		||||
            typename Container::value_type,
 | 
			
		||||
            container_mapped_type_traits<Container>::has_mapped_type>::if_not_recursive>::type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This trait defines the `type_to_check_recursively` which is needed to properly
 | 
			
		||||
 * handle recursively defined traits such as `is_move_constructible` without going
 | 
			
		||||
 * into an infinite recursion.
 | 
			
		||||
 * Should be used instead of directly accessing the `value_type`.
 | 
			
		||||
 * It cancels the recursion by returning the `recursive_bottom` tag.
 | 
			
		||||
 *
 | 
			
		||||
 * The default definition of `type_to_check_recursively` is as follows:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. By default, it is `recursive_bottom`, so that the recursion is canceled.
 | 
			
		||||
 * 2. If the type is non-recursive and defines a `value_type`, then the `value_type` is used.
 | 
			
		||||
 *    If the `value_type` is a pair and a `mapped_type` is defined,
 | 
			
		||||
 *    then the `const` is removed from the first type.
 | 
			
		||||
 * 3. If the type is recursive and `value_type` is not a pair, then `recursive_bottom` is returned.
 | 
			
		||||
 * 4. If the type is recursive and `value_type` is a pair and a `mapped_type` is defined,
 | 
			
		||||
 *    then `const` is removed from the first type and the first type is returned.
 | 
			
		||||
 *
 | 
			
		||||
 * This behavior can be extended by the user as seen in test_stl_binders.cpp.
 | 
			
		||||
 *
 | 
			
		||||
 * This struct is exactly the same as impl_recursive_container_traits.
 | 
			
		||||
 * The duplication achieves that user-defined specializations don't compete
 | 
			
		||||
 * with internal specializations, but take precedence.
 | 
			
		||||
 */
 | 
			
		||||
template <typename Container, typename SFINAE = void>
 | 
			
		||||
struct recursive_container_traits : impl_recursive_container_traits<Container> {};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct is_move_constructible
 | 
			
		||||
    : all_of<std::is_move_constructible<T>,
 | 
			
		||||
             is_move_constructible<
 | 
			
		||||
                 typename recursive_container_traits<T>::type_to_check_recursively>> {};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct is_move_constructible<recursive_bottom> : std::true_type {};
 | 
			
		||||
 | 
			
		||||
// Likewise for std::pair
 | 
			
		||||
// (after C++17 it is mandatory that the move constructor not exist when the two types aren't
 | 
			
		||||
// themselves move constructible, but this can not be relied upon when T1 or T2 are themselves
 | 
			
		||||
// containers).
 | 
			
		||||
template <typename T1, typename T2>
 | 
			
		||||
struct is_move_constructible<std::pair<T1, T2>>
 | 
			
		||||
    : all_of<is_move_constructible<T1>, is_move_constructible<T2>> {};
 | 
			
		||||
 | 
			
		||||
// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when
 | 
			
		||||
// T is non-copyable, but code containing such a copy constructor fails to actually compile.
 | 
			
		||||
template <typename T, typename SFINAE = void>
 | 
			
		||||
struct is_copy_constructible : std::is_copy_constructible<T> {};
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct is_copy_constructible
 | 
			
		||||
    : all_of<std::is_copy_constructible<T>,
 | 
			
		||||
             is_copy_constructible<
 | 
			
		||||
                 typename recursive_container_traits<T>::type_to_check_recursively>> {};
 | 
			
		||||
 | 
			
		||||
// Specialization for types that appear to be copy constructible but also look like stl containers
 | 
			
		||||
// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
 | 
			
		||||
// so, copy constructability depends on whether the value_type is copy constructible.
 | 
			
		||||
template <typename Container>
 | 
			
		||||
struct is_copy_constructible<
 | 
			
		||||
    Container,
 | 
			
		||||
    enable_if_t<
 | 
			
		||||
        all_of<std::is_copy_constructible<Container>,
 | 
			
		||||
               std::is_same<typename Container::value_type &, typename Container::reference>,
 | 
			
		||||
               // Avoid infinite recursion
 | 
			
		||||
               negation<std::is_same<Container, typename Container::value_type>>>::value>>
 | 
			
		||||
    : is_copy_constructible<typename Container::value_type> {};
 | 
			
		||||
template <>
 | 
			
		||||
struct is_copy_constructible<recursive_bottom> : std::true_type {};
 | 
			
		||||
 | 
			
		||||
// Likewise for std::pair
 | 
			
		||||
// (after C++17 it is mandatory that the copy constructor not exist when the two types aren't
 | 
			
		||||
| 
						 | 
				
			
			@ -849,14 +1005,16 @@ struct is_copy_constructible<std::pair<T1, T2>>
 | 
			
		|||
    : all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {};
 | 
			
		||||
 | 
			
		||||
// The same problems arise with std::is_copy_assignable, so we use the same workaround.
 | 
			
		||||
template <typename T, typename SFINAE = void>
 | 
			
		||||
struct is_copy_assignable : std::is_copy_assignable<T> {};
 | 
			
		||||
template <typename Container>
 | 
			
		||||
struct is_copy_assignable<Container,
 | 
			
		||||
                          enable_if_t<all_of<std::is_copy_assignable<Container>,
 | 
			
		||||
                                             std::is_same<typename Container::value_type &,
 | 
			
		||||
                                                          typename Container::reference>>::value>>
 | 
			
		||||
    : is_copy_assignable<typename Container::value_type> {};
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct is_copy_assignable
 | 
			
		||||
    : all_of<
 | 
			
		||||
          std::is_copy_assignable<T>,
 | 
			
		||||
          is_copy_assignable<typename recursive_container_traits<T>::type_to_check_recursively>> {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct is_copy_assignable<recursive_bottom> : std::true_type {};
 | 
			
		||||
 | 
			
		||||
template <typename T1, typename T2>
 | 
			
		||||
struct is_copy_assignable<std::pair<T1, T2>>
 | 
			
		||||
    : all_of<is_copy_assignable<T1>, is_copy_assignable<T2>> {};
 | 
			
		||||
| 
						 | 
				
			
			@ -994,7 +1152,7 @@ protected:
 | 
			
		|||
        return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T, typename = enable_if_t<std::is_move_constructible<T>::value>>
 | 
			
		||||
    template <typename T, typename = enable_if_t<is_move_constructible<T>::value>>
 | 
			
		||||
    static auto make_move_constructor(const T *)
 | 
			
		||||
        -> decltype(new T(std::declval<T &&>()), Constructor{}) {
 | 
			
		||||
        return [](const void *arg) -> void * {
 | 
			
		||||
| 
						 | 
				
			
			@ -1006,5 +1164,14 @@ protected:
 | 
			
		|||
    static Constructor make_move_constructor(...) { return nullptr; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) {
 | 
			
		||||
    if (auto *type_data = get_type_info(ti)) {
 | 
			
		||||
        handle th((PyObject *) type_data->type);
 | 
			
		||||
        return th.attr("__module__").cast<std::string>() + '.'
 | 
			
		||||
               + th.attr("__qualname__").cast<std::string>();
 | 
			
		||||
    }
 | 
			
		||||
    return clean_type_id(ti.name());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,700 +9,4 @@
 | 
			
		|||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
/* HINT: To suppress warnings originating from the Eigen headers, use -isystem.
 | 
			
		||||
   See also:
 | 
			
		||||
       https://stackoverflow.com/questions/2579576/i-dir-vs-isystem-dir
 | 
			
		||||
       https://stackoverflow.com/questions/1741816/isystem-for-ms-visual-studio-c-compiler
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "numpy.h"
 | 
			
		||||
 | 
			
		||||
// The C4127 suppression was introduced for Eigen 3.4.0. In theory we could
 | 
			
		||||
// make it version specific, or even remove it later, but considering that
 | 
			
		||||
// 1. C4127 is generally far more distracting than useful for modern template code, and
 | 
			
		||||
// 2. we definitely want to ignore any MSVC warnings originating from Eigen code,
 | 
			
		||||
//    it is probably best to keep this around indefinitely.
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#    pragma warning(push)
 | 
			
		||||
#    pragma warning(disable : 4127) // C4127: conditional expression is constant
 | 
			
		||||
#    pragma warning(disable : 5054) // https://github.com/pybind/pybind11/pull/3741
 | 
			
		||||
//       C5054: operator '&': deprecated between enumerations of different types
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <Eigen/Core>
 | 
			
		||||
#include <Eigen/SparseCore>
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#    pragma warning(pop)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
 | 
			
		||||
// move constructors that break things.  We could detect this an explicitly copy, but an extra copy
 | 
			
		||||
// of matrices seems highly undesirable.
 | 
			
		||||
static_assert(EIGEN_VERSION_AT_LEAST(3, 2, 7),
 | 
			
		||||
              "Eigen support in pybind11 requires Eigen >= 3.2.7");
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
 | 
			
		||||
// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
 | 
			
		||||
using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
 | 
			
		||||
template <typename MatrixType>
 | 
			
		||||
using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
 | 
			
		||||
template <typename MatrixType>
 | 
			
		||||
using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
 | 
			
		||||
#if EIGEN_VERSION_AT_LEAST(3, 3, 0)
 | 
			
		||||
using EigenIndex = Eigen::Index;
 | 
			
		||||
template <typename Scalar, int Flags, typename StorageIndex>
 | 
			
		||||
using EigenMapSparseMatrix = Eigen::Map<Eigen::SparseMatrix<Scalar, Flags, StorageIndex>>;
 | 
			
		||||
#else
 | 
			
		||||
using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
 | 
			
		||||
template <typename Scalar, int Flags, typename StorageIndex>
 | 
			
		||||
using EigenMapSparseMatrix = Eigen::MappedSparseMatrix<Scalar, Flags, StorageIndex>;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Matches Eigen::Map, Eigen::Ref, blocks, etc:
 | 
			
		||||
template <typename T>
 | 
			
		||||
using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>,
 | 
			
		||||
                                  std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
 | 
			
		||||
template <typename T>
 | 
			
		||||
using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
 | 
			
		||||
template <typename T>
 | 
			
		||||
using is_eigen_dense_plain
 | 
			
		||||
    = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
 | 
			
		||||
template <typename T>
 | 
			
		||||
using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
 | 
			
		||||
// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above.  This
 | 
			
		||||
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
 | 
			
		||||
// matrix data layout that can be copied from their .data().  For example, DiagonalMatrix and
 | 
			
		||||
// SelfAdjointView fall into this category.
 | 
			
		||||
template <typename T>
 | 
			
		||||
using is_eigen_other
 | 
			
		||||
    = all_of<is_template_base_of<Eigen::EigenBase, T>,
 | 
			
		||||
             negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>>;
 | 
			
		||||
 | 
			
		||||
// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
 | 
			
		||||
template <bool EigenRowMajor>
 | 
			
		||||
struct EigenConformable {
 | 
			
		||||
    bool conformable = false;
 | 
			
		||||
    EigenIndex rows = 0, cols = 0;
 | 
			
		||||
    EigenDStride stride{0, 0};    // Only valid if negativestrides is false!
 | 
			
		||||
    bool negativestrides = false; // If true, do not use stride!
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    EigenConformable(bool fits = false) : conformable{fits} {}
 | 
			
		||||
    // Matrix type:
 | 
			
		||||
    EigenConformable(EigenIndex r, EigenIndex c, EigenIndex rstride, EigenIndex cstride)
 | 
			
		||||
        : conformable{true}, rows{r}, cols{c},
 | 
			
		||||
          // TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity.
 | 
			
		||||
          // http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
 | 
			
		||||
          stride{EigenRowMajor ? (rstride > 0 ? rstride : 0)
 | 
			
		||||
                               : (cstride > 0 ? cstride : 0) /* outer stride */,
 | 
			
		||||
                 EigenRowMajor ? (cstride > 0 ? cstride : 0)
 | 
			
		||||
                               : (rstride > 0 ? rstride : 0) /* inner stride */},
 | 
			
		||||
          negativestrides{rstride < 0 || cstride < 0} {}
 | 
			
		||||
    // Vector type:
 | 
			
		||||
    EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
 | 
			
		||||
        : EigenConformable(r, c, r == 1 ? c * stride : stride, c == 1 ? r : r * stride) {}
 | 
			
		||||
 | 
			
		||||
    template <typename props>
 | 
			
		||||
    bool stride_compatible() const {
 | 
			
		||||
        // To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
 | 
			
		||||
        // matching strides, or a dimension size of 1 (in which case the stride value is
 | 
			
		||||
        // irrelevant). Alternatively, if any dimension size is 0, the strides are not relevant
 | 
			
		||||
        // (and numpy ≥ 1.23 sets the strides to 0 in that case, so we need to check explicitly).
 | 
			
		||||
        if (negativestrides) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (rows == 0 || cols == 0) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
 | 
			
		||||
                || (EigenRowMajor ? cols : rows) == 1)
 | 
			
		||||
               && (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()
 | 
			
		||||
                   || (EigenRowMajor ? rows : cols) == 1);
 | 
			
		||||
    }
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator bool() const { return conformable; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Type>
 | 
			
		||||
struct eigen_extract_stride {
 | 
			
		||||
    using type = Type;
 | 
			
		||||
};
 | 
			
		||||
template <typename PlainObjectType, int MapOptions, typename StrideType>
 | 
			
		||||
struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> {
 | 
			
		||||
    using type = StrideType;
 | 
			
		||||
};
 | 
			
		||||
template <typename PlainObjectType, int Options, typename StrideType>
 | 
			
		||||
struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> {
 | 
			
		||||
    using type = StrideType;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Helper struct for extracting information from an Eigen type
 | 
			
		||||
template <typename Type_>
 | 
			
		||||
struct EigenProps {
 | 
			
		||||
    using Type = Type_;
 | 
			
		||||
    using Scalar = typename Type::Scalar;
 | 
			
		||||
    using StrideType = typename eigen_extract_stride<Type>::type;
 | 
			
		||||
    static constexpr EigenIndex rows = Type::RowsAtCompileTime, cols = Type::ColsAtCompileTime,
 | 
			
		||||
                                size = Type::SizeAtCompileTime;
 | 
			
		||||
    static constexpr bool row_major = Type::IsRowMajor,
 | 
			
		||||
                          vector
 | 
			
		||||
                          = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
 | 
			
		||||
        fixed_rows = rows != Eigen::Dynamic, fixed_cols = cols != Eigen::Dynamic,
 | 
			
		||||
                          fixed = size != Eigen::Dynamic, // Fully-fixed size
 | 
			
		||||
        dynamic = !fixed_rows && !fixed_cols;             // Fully-dynamic size
 | 
			
		||||
 | 
			
		||||
    template <EigenIndex i, EigenIndex ifzero>
 | 
			
		||||
    using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
 | 
			
		||||
    static constexpr EigenIndex inner_stride
 | 
			
		||||
        = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
 | 
			
		||||
        outer_stride = if_zero < StrideType::OuterStrideAtCompileTime,
 | 
			
		||||
        vector      ? size
 | 
			
		||||
        : row_major ? cols
 | 
			
		||||
                    : rows > ::value;
 | 
			
		||||
    static constexpr bool dynamic_stride
 | 
			
		||||
        = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
 | 
			
		||||
    static constexpr bool requires_row_major
 | 
			
		||||
        = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
 | 
			
		||||
    static constexpr bool requires_col_major
 | 
			
		||||
        = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
 | 
			
		||||
 | 
			
		||||
    // Takes an input array and determines whether we can make it fit into the Eigen type.  If
 | 
			
		||||
    // the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
 | 
			
		||||
    // (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
 | 
			
		||||
    static EigenConformable<row_major> conformable(const array &a) {
 | 
			
		||||
        const auto dims = a.ndim();
 | 
			
		||||
        if (dims < 1 || dims > 2) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (dims == 2) { // Matrix type: require exact match (or dynamic)
 | 
			
		||||
 | 
			
		||||
            EigenIndex np_rows = a.shape(0), np_cols = a.shape(1),
 | 
			
		||||
                       np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
 | 
			
		||||
                       np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
 | 
			
		||||
            if ((PYBIND11_SILENCE_MSVC_C4127(fixed_rows) && np_rows != rows)
 | 
			
		||||
                || (PYBIND11_SILENCE_MSVC_C4127(fixed_cols) && np_cols != cols)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return {np_rows, np_cols, np_rstride, np_cstride};
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Otherwise we're storing an n-vector.  Only one of the strides will be used, but
 | 
			
		||||
        // whichever is used, we want the (single) numpy stride value.
 | 
			
		||||
        const EigenIndex n = a.shape(0),
 | 
			
		||||
                         stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
 | 
			
		||||
 | 
			
		||||
        if (vector) { // Eigen type is a compile-time vector
 | 
			
		||||
            if (PYBIND11_SILENCE_MSVC_C4127(fixed) && size != n) {
 | 
			
		||||
                return false; // Vector size mismatch
 | 
			
		||||
            }
 | 
			
		||||
            return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
 | 
			
		||||
        }
 | 
			
		||||
        if (fixed) {
 | 
			
		||||
            // The type has a fixed size, but is not a vector: abort
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (fixed_cols) {
 | 
			
		||||
            // Since this isn't a vector, cols must be != 1.  We allow this only if it exactly
 | 
			
		||||
            // equals the number of elements (rows is Dynamic, and so 1 row is allowed).
 | 
			
		||||
            if (cols != n) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            return {1, n, stride};
 | 
			
		||||
        } // Otherwise it's either fully dynamic, or column dynamic; both become a column vector
 | 
			
		||||
        if (PYBIND11_SILENCE_MSVC_C4127(fixed_rows) && rows != n) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return {n, 1, stride};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr bool show_writeable
 | 
			
		||||
        = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
 | 
			
		||||
    static constexpr bool show_order = is_eigen_dense_map<Type>::value;
 | 
			
		||||
    static constexpr bool show_c_contiguous = show_order && requires_row_major;
 | 
			
		||||
    static constexpr bool show_f_contiguous
 | 
			
		||||
        = !show_c_contiguous && show_order && requires_col_major;
 | 
			
		||||
 | 
			
		||||
    static constexpr auto descriptor
 | 
			
		||||
        = const_name("numpy.ndarray[") + npy_format_descriptor<Scalar>::name + const_name("[")
 | 
			
		||||
          + const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) + const_name(", ")
 | 
			
		||||
          + const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n")) + const_name("]")
 | 
			
		||||
          +
 | 
			
		||||
          // For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to
 | 
			
		||||
          // be satisfied: writeable=True (for a mutable reference), and, depending on the map's
 | 
			
		||||
          // stride options, possibly f_contiguous or c_contiguous.  We include them in the
 | 
			
		||||
          // descriptor output to provide some hint as to why a TypeError is occurring (otherwise
 | 
			
		||||
          // it can be confusing to see that a function accepts a 'numpy.ndarray[float64[3,2]]' and
 | 
			
		||||
          // an error message that you *gave* a numpy.ndarray of the right type and dimensions.
 | 
			
		||||
          const_name<show_writeable>(", flags.writeable", "")
 | 
			
		||||
          + const_name<show_c_contiguous>(", flags.c_contiguous", "")
 | 
			
		||||
          + const_name<show_f_contiguous>(", flags.f_contiguous", "") + const_name("]");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Casts an Eigen type to numpy array.  If given a base, the numpy array references the src data,
 | 
			
		||||
// otherwise it'll make a copy.  writeable lets you turn off the writeable flag for the array.
 | 
			
		||||
template <typename props>
 | 
			
		||||
handle
 | 
			
		||||
eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
 | 
			
		||||
    constexpr ssize_t elem_size = sizeof(typename props::Scalar);
 | 
			
		||||
    array a;
 | 
			
		||||
    if (props::vector) {
 | 
			
		||||
        a = array({src.size()}, {elem_size * src.innerStride()}, src.data(), base);
 | 
			
		||||
    } else {
 | 
			
		||||
        a = array({src.rows(), src.cols()},
 | 
			
		||||
                  {elem_size * src.rowStride(), elem_size * src.colStride()},
 | 
			
		||||
                  src.data(),
 | 
			
		||||
                  base);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!writeable) {
 | 
			
		||||
        array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return a.release();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that
 | 
			
		||||
// reference the Eigen object's data with `base` as the python-registered base class (if omitted,
 | 
			
		||||
// the base will be set to None, and lifetime management is up to the caller).  The numpy array is
 | 
			
		||||
// non-writeable if the given type is const.
 | 
			
		||||
template <typename props, typename Type>
 | 
			
		||||
handle eigen_ref_array(Type &src, handle parent = none()) {
 | 
			
		||||
    // none here is to get past array's should-we-copy detection, which currently always
 | 
			
		||||
    // copies when there is no base.  Setting the base to None should be harmless.
 | 
			
		||||
    return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a
 | 
			
		||||
// numpy array that references the encapsulated data with a python-side reference to the capsule to
 | 
			
		||||
// tie its destruction to that of any dependent python objects.  Const-ness is determined by
 | 
			
		||||
// whether or not the Type of the pointer given is const.
 | 
			
		||||
template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
 | 
			
		||||
handle eigen_encapsulate(Type *src) {
 | 
			
		||||
    capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
 | 
			
		||||
    return eigen_ref_array<props>(*src, base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
 | 
			
		||||
// types.
 | 
			
		||||
template <typename Type>
 | 
			
		||||
struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
 | 
			
		||||
    using Scalar = typename Type::Scalar;
 | 
			
		||||
    using props = EigenProps<Type>;
 | 
			
		||||
 | 
			
		||||
    bool load(handle src, bool convert) {
 | 
			
		||||
        // If we're in no-convert mode, only load if given an array of the correct type
 | 
			
		||||
        if (!convert && !isinstance<array_t<Scalar>>(src)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Coerce into an array, but don't do type conversion yet; the copy below handles it.
 | 
			
		||||
        auto buf = array::ensure(src);
 | 
			
		||||
 | 
			
		||||
        if (!buf) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto dims = buf.ndim();
 | 
			
		||||
        if (dims < 1 || dims > 2) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto fits = props::conformable(buf);
 | 
			
		||||
        if (!fits) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Allocate the new type, then build a numpy reference into it
 | 
			
		||||
        value = Type(fits.rows, fits.cols);
 | 
			
		||||
        auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
 | 
			
		||||
        if (dims == 1) {
 | 
			
		||||
            ref = ref.squeeze();
 | 
			
		||||
        } else if (ref.ndim() == 1) {
 | 
			
		||||
            buf = buf.squeeze();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
 | 
			
		||||
 | 
			
		||||
        if (result < 0) { // Copy failed!
 | 
			
		||||
            PyErr_Clear();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    // Cast implementation
 | 
			
		||||
    template <typename CType>
 | 
			
		||||
    static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        switch (policy) {
 | 
			
		||||
            case return_value_policy::take_ownership:
 | 
			
		||||
            case return_value_policy::automatic:
 | 
			
		||||
                return eigen_encapsulate<props>(src);
 | 
			
		||||
            case return_value_policy::move:
 | 
			
		||||
                return eigen_encapsulate<props>(new CType(std::move(*src)));
 | 
			
		||||
            case return_value_policy::copy:
 | 
			
		||||
                return eigen_array_cast<props>(*src);
 | 
			
		||||
            case return_value_policy::reference:
 | 
			
		||||
            case return_value_policy::automatic_reference:
 | 
			
		||||
                return eigen_ref_array<props>(*src);
 | 
			
		||||
            case return_value_policy::reference_internal:
 | 
			
		||||
                return eigen_ref_array<props>(*src, parent);
 | 
			
		||||
            default:
 | 
			
		||||
                throw cast_error("unhandled return_value_policy: should not happen!");
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    // Normal returned non-reference, non-const value:
 | 
			
		||||
    static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
 | 
			
		||||
        return cast_impl(&src, return_value_policy::move, parent);
 | 
			
		||||
    }
 | 
			
		||||
    // If you return a non-reference const, we mark the numpy array readonly:
 | 
			
		||||
    static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) {
 | 
			
		||||
        return cast_impl(&src, return_value_policy::move, parent);
 | 
			
		||||
    }
 | 
			
		||||
    // lvalue reference return; default (automatic) becomes copy
 | 
			
		||||
    static handle cast(Type &src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic
 | 
			
		||||
            || policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::copy;
 | 
			
		||||
        }
 | 
			
		||||
        return cast_impl(&src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
    // const lvalue reference return; default (automatic) becomes copy
 | 
			
		||||
    static handle cast(const Type &src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic
 | 
			
		||||
            || policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::copy;
 | 
			
		||||
        }
 | 
			
		||||
        return cast(&src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
    // non-const pointer return
 | 
			
		||||
    static handle cast(Type *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        return cast_impl(src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
    // const pointer return
 | 
			
		||||
    static handle cast(const Type *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        return cast_impl(src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr auto name = props::descriptor;
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator Type *() { return &value; }
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator Type &() { return value; }
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator Type &&() && { return std::move(value); }
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    using cast_op_type = movable_cast_op_type<T>;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Type value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Base class for casting reference/map/block/etc. objects back to python.
 | 
			
		||||
template <typename MapType>
 | 
			
		||||
struct eigen_map_caster {
 | 
			
		||||
private:
 | 
			
		||||
    using props = EigenProps<MapType>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    // Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
 | 
			
		||||
    // to stay around), but we'll allow it under the assumption that you know what you're doing
 | 
			
		||||
    // (and have an appropriate keep_alive in place).  We return a numpy array pointing directly at
 | 
			
		||||
    // the ref's data (The numpy array ends up read-only if the ref was to a const matrix type.)
 | 
			
		||||
    // Note that this means you need to ensure you don't destroy the object in some other way (e.g.
 | 
			
		||||
    // with an appropriate keep_alive, or with a reference to a statically allocated matrix).
 | 
			
		||||
    static handle cast(const MapType &src, return_value_policy policy, handle parent) {
 | 
			
		||||
        switch (policy) {
 | 
			
		||||
            case return_value_policy::copy:
 | 
			
		||||
                return eigen_array_cast<props>(src);
 | 
			
		||||
            case return_value_policy::reference_internal:
 | 
			
		||||
                return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);
 | 
			
		||||
            case return_value_policy::reference:
 | 
			
		||||
            case return_value_policy::automatic:
 | 
			
		||||
            case return_value_policy::automatic_reference:
 | 
			
		||||
                return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);
 | 
			
		||||
            default:
 | 
			
		||||
                // move, take_ownership don't make any sense for a ref/map:
 | 
			
		||||
                pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr auto name = props::descriptor;
 | 
			
		||||
 | 
			
		||||
    // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
 | 
			
		||||
    // types but not bound arguments).  We still provide them (with an explicitly delete) so that
 | 
			
		||||
    // you end up here if you try anyway.
 | 
			
		||||
    bool load(handle, bool) = delete;
 | 
			
		||||
    operator MapType() = delete;
 | 
			
		||||
    template <typename>
 | 
			
		||||
    using cast_op_type = MapType;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// We can return any map-like object (but can only load Refs, specialized next):
 | 
			
		||||
template <typename Type>
 | 
			
		||||
struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>> : eigen_map_caster<Type> {};
 | 
			
		||||
 | 
			
		||||
// Loader for Ref<...> arguments.  See the documentation for info on how to make this work without
 | 
			
		||||
// copying (it requires some extra effort in many cases).
 | 
			
		||||
template <typename PlainObjectType, typename StrideType>
 | 
			
		||||
struct type_caster<
 | 
			
		||||
    Eigen::Ref<PlainObjectType, 0, StrideType>,
 | 
			
		||||
    enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>>
 | 
			
		||||
    : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
 | 
			
		||||
private:
 | 
			
		||||
    using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
 | 
			
		||||
    using props = EigenProps<Type>;
 | 
			
		||||
    using Scalar = typename props::Scalar;
 | 
			
		||||
    using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
 | 
			
		||||
    using Array
 | 
			
		||||
        = array_t<Scalar,
 | 
			
		||||
                  array::forcecast
 | 
			
		||||
                      | ((props::row_major ? props::inner_stride : props::outer_stride) == 1
 | 
			
		||||
                             ? array::c_style
 | 
			
		||||
                         : (props::row_major ? props::outer_stride : props::inner_stride) == 1
 | 
			
		||||
                             ? array::f_style
 | 
			
		||||
                             : 0)>;
 | 
			
		||||
    static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
 | 
			
		||||
    // Delay construction (these have no default constructor)
 | 
			
		||||
    std::unique_ptr<MapType> map;
 | 
			
		||||
    std::unique_ptr<Type> ref;
 | 
			
		||||
    // Our array.  When possible, this is just a numpy array pointing to the source data, but
 | 
			
		||||
    // sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an
 | 
			
		||||
    // incompatible layout, or is an array of a type that needs to be converted).  Using a numpy
 | 
			
		||||
    // temporary (rather than an Eigen temporary) saves an extra copy when we need both type
 | 
			
		||||
    // conversion and storage order conversion.  (Note that we refuse to use this temporary copy
 | 
			
		||||
    // when loading an argument for a Ref<M> with M non-const, i.e. a read-write reference).
 | 
			
		||||
    Array copy_or_ref;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    bool load(handle src, bool convert) {
 | 
			
		||||
        // First check whether what we have is already an array of the right type.  If not, we
 | 
			
		||||
        // can't avoid a copy (because the copy is also going to do type conversion).
 | 
			
		||||
        bool need_copy = !isinstance<Array>(src);
 | 
			
		||||
 | 
			
		||||
        EigenConformable<props::row_major> fits;
 | 
			
		||||
        if (!need_copy) {
 | 
			
		||||
            // We don't need a converting copy, but we also need to check whether the strides are
 | 
			
		||||
            // compatible with the Ref's stride requirements
 | 
			
		||||
            auto aref = reinterpret_borrow<Array>(src);
 | 
			
		||||
 | 
			
		||||
            if (aref && (!need_writeable || aref.writeable())) {
 | 
			
		||||
                fits = props::conformable(aref);
 | 
			
		||||
                if (!fits) {
 | 
			
		||||
                    return false; // Incompatible dimensions
 | 
			
		||||
                }
 | 
			
		||||
                if (!fits.template stride_compatible<props>()) {
 | 
			
		||||
                    need_copy = true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    copy_or_ref = std::move(aref);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                need_copy = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (need_copy) {
 | 
			
		||||
            // We need to copy: If we need a mutable reference, or we're not supposed to convert
 | 
			
		||||
            // (either because we're in the no-convert overload pass, or because we're explicitly
 | 
			
		||||
            // instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
 | 
			
		||||
            if (!convert || need_writeable) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Array copy = Array::ensure(src);
 | 
			
		||||
            if (!copy) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            fits = props::conformable(copy);
 | 
			
		||||
            if (!fits || !fits.template stride_compatible<props>()) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            copy_or_ref = std::move(copy);
 | 
			
		||||
            loader_life_support::add_patient(copy_or_ref);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ref.reset();
 | 
			
		||||
        map.reset(new MapType(data(copy_or_ref),
 | 
			
		||||
                              fits.rows,
 | 
			
		||||
                              fits.cols,
 | 
			
		||||
                              make_stride(fits.stride.outer(), fits.stride.inner())));
 | 
			
		||||
        ref.reset(new Type(*map));
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator Type *() { return ref.get(); }
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator Type &() { return *ref; }
 | 
			
		||||
    template <typename _T>
 | 
			
		||||
    using cast_op_type = pybind11::detail::cast_op_type<_T>;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
 | 
			
		||||
    Scalar *data(Array &a) {
 | 
			
		||||
        return a.mutable_data();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
 | 
			
		||||
    const Scalar *data(Array &a) {
 | 
			
		||||
        return a.data();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Attempt to figure out a constructor of `Stride` that will work.
 | 
			
		||||
    // If both strides are fixed, use a default constructor:
 | 
			
		||||
    template <typename S>
 | 
			
		||||
    using stride_ctor_default = bool_constant<S::InnerStrideAtCompileTime != Eigen::Dynamic
 | 
			
		||||
                                              && S::OuterStrideAtCompileTime != Eigen::Dynamic
 | 
			
		||||
                                              && std::is_default_constructible<S>::value>;
 | 
			
		||||
    // Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
 | 
			
		||||
    // Eigen::Stride, and use it:
 | 
			
		||||
    template <typename S>
 | 
			
		||||
    using stride_ctor_dual
 | 
			
		||||
        = bool_constant<!stride_ctor_default<S>::value
 | 
			
		||||
                        && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
 | 
			
		||||
    // Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
 | 
			
		||||
    // it (passing whichever stride is dynamic).
 | 
			
		||||
    template <typename S>
 | 
			
		||||
    using stride_ctor_outer
 | 
			
		||||
        = bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
 | 
			
		||||
                        && S::OuterStrideAtCompileTime == Eigen::Dynamic
 | 
			
		||||
                        && S::InnerStrideAtCompileTime != Eigen::Dynamic
 | 
			
		||||
                        && std::is_constructible<S, EigenIndex>::value>;
 | 
			
		||||
    template <typename S>
 | 
			
		||||
    using stride_ctor_inner
 | 
			
		||||
        = bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
 | 
			
		||||
                        && S::InnerStrideAtCompileTime == Eigen::Dynamic
 | 
			
		||||
                        && S::OuterStrideAtCompileTime != Eigen::Dynamic
 | 
			
		||||
                        && std::is_constructible<S, EigenIndex>::value>;
 | 
			
		||||
 | 
			
		||||
    template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
 | 
			
		||||
    static S make_stride(EigenIndex, EigenIndex) {
 | 
			
		||||
        return S();
 | 
			
		||||
    }
 | 
			
		||||
    template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
 | 
			
		||||
    static S make_stride(EigenIndex outer, EigenIndex inner) {
 | 
			
		||||
        return S(outer, inner);
 | 
			
		||||
    }
 | 
			
		||||
    template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
 | 
			
		||||
    static S make_stride(EigenIndex outer, EigenIndex) {
 | 
			
		||||
        return S(outer);
 | 
			
		||||
    }
 | 
			
		||||
    template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
 | 
			
		||||
    static S make_stride(EigenIndex, EigenIndex inner) {
 | 
			
		||||
        return S(inner);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
 | 
			
		||||
// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout).
 | 
			
		||||
// load() is not supported, but we can cast them into the python domain by first copying to a
 | 
			
		||||
// regular Eigen::Matrix, then casting that.
 | 
			
		||||
template <typename Type>
 | 
			
		||||
struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
 | 
			
		||||
protected:
 | 
			
		||||
    using Matrix
 | 
			
		||||
        = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
 | 
			
		||||
    using props = EigenProps<Matrix>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
 | 
			
		||||
        handle h = eigen_encapsulate<props>(new Matrix(src));
 | 
			
		||||
        return h;
 | 
			
		||||
    }
 | 
			
		||||
    static handle cast(const Type *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        return cast(*src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr auto name = props::descriptor;
 | 
			
		||||
 | 
			
		||||
    // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
 | 
			
		||||
    // types but not bound arguments).  We still provide them (with an explicitly delete) so that
 | 
			
		||||
    // you end up here if you try anyway.
 | 
			
		||||
    bool load(handle, bool) = delete;
 | 
			
		||||
    operator Type() = delete;
 | 
			
		||||
    template <typename>
 | 
			
		||||
    using cast_op_type = Type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Type>
 | 
			
		||||
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
 | 
			
		||||
    using Scalar = typename Type::Scalar;
 | 
			
		||||
    using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;
 | 
			
		||||
    using Index = typename Type::Index;
 | 
			
		||||
    static constexpr bool rowMajor = Type::IsRowMajor;
 | 
			
		||||
 | 
			
		||||
    bool load(handle src, bool) {
 | 
			
		||||
        if (!src) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto obj = reinterpret_borrow<object>(src);
 | 
			
		||||
        object sparse_module = module_::import("scipy.sparse");
 | 
			
		||||
        object matrix_type = sparse_module.attr(rowMajor ? "csr_matrix" : "csc_matrix");
 | 
			
		||||
 | 
			
		||||
        if (!type::handle_of(obj).is(matrix_type)) {
 | 
			
		||||
            try {
 | 
			
		||||
                obj = matrix_type(obj);
 | 
			
		||||
            } catch (const error_already_set &) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto values = array_t<Scalar>((object) obj.attr("data"));
 | 
			
		||||
        auto innerIndices = array_t<StorageIndex>((object) obj.attr("indices"));
 | 
			
		||||
        auto outerIndices = array_t<StorageIndex>((object) obj.attr("indptr"));
 | 
			
		||||
        auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
 | 
			
		||||
        auto nnz = obj.attr("nnz").cast<Index>();
 | 
			
		||||
 | 
			
		||||
        if (!values || !innerIndices || !outerIndices) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        value = EigenMapSparseMatrix<Scalar,
 | 
			
		||||
                                     Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
 | 
			
		||||
                                     StorageIndex>(shape[0].cast<Index>(),
 | 
			
		||||
                                                   shape[1].cast<Index>(),
 | 
			
		||||
                                                   std::move(nnz),
 | 
			
		||||
                                                   outerIndices.mutable_data(),
 | 
			
		||||
                                                   innerIndices.mutable_data(),
 | 
			
		||||
                                                   values.mutable_data());
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
 | 
			
		||||
        const_cast<Type &>(src).makeCompressed();
 | 
			
		||||
 | 
			
		||||
        object matrix_type
 | 
			
		||||
            = module_::import("scipy.sparse").attr(rowMajor ? "csr_matrix" : "csc_matrix");
 | 
			
		||||
 | 
			
		||||
        array data(src.nonZeros(), src.valuePtr());
 | 
			
		||||
        array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
 | 
			
		||||
        array innerIndices(src.nonZeros(), src.innerIndexPtr());
 | 
			
		||||
 | 
			
		||||
        return matrix_type(pybind11::make_tuple(
 | 
			
		||||
                               std::move(data), std::move(innerIndices), std::move(outerIndices)),
 | 
			
		||||
                           pybind11::make_tuple(src.rows(), src.cols()))
 | 
			
		||||
            .release();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PYBIND11_TYPE_CASTER(Type,
 | 
			
		||||
                         const_name<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[",
 | 
			
		||||
                                                             "scipy.sparse.csc_matrix[")
 | 
			
		||||
                             + npy_format_descriptor<Scalar>::name + const_name("]"));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
 | 
			
		||||
#include "eigen/matrix.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
// Copyright (c) 2023 The pybind Community.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
// Common message for `static_assert()`s, which are useful to easily
 | 
			
		||||
// preempt much less obvious errors.
 | 
			
		||||
#define PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED                                    \
 | 
			
		||||
    "Pointer types (in particular `PyObject *`) are not supported as scalar types for Eigen "     \
 | 
			
		||||
    "types."
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,714 @@
 | 
			
		|||
/*
 | 
			
		||||
    pybind11/eigen/matrix.h: Transparent conversion for dense and sparse Eigen matrices
 | 
			
		||||
 | 
			
		||||
    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
 | 
			
		||||
 | 
			
		||||
    All rights reserved. Use of this source code is governed by a
 | 
			
		||||
    BSD-style license that can be found in the LICENSE file.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "../numpy.h"
 | 
			
		||||
#include "common.h"
 | 
			
		||||
 | 
			
		||||
/* HINT: To suppress warnings originating from the Eigen headers, use -isystem.
 | 
			
		||||
   See also:
 | 
			
		||||
       https://stackoverflow.com/questions/2579576/i-dir-vs-isystem-dir
 | 
			
		||||
       https://stackoverflow.com/questions/1741816/isystem-for-ms-visual-studio-c-compiler
 | 
			
		||||
*/
 | 
			
		||||
PYBIND11_WARNING_PUSH
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(5054) // https://github.com/pybind/pybind11/pull/3741
 | 
			
		||||
//       C5054: operator '&': deprecated between enumerations of different types
 | 
			
		||||
#if defined(__MINGW32__)
 | 
			
		||||
PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <Eigen/Core>
 | 
			
		||||
#include <Eigen/SparseCore>
 | 
			
		||||
 | 
			
		||||
PYBIND11_WARNING_POP
 | 
			
		||||
 | 
			
		||||
// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
 | 
			
		||||
// move constructors that break things.  We could detect this an explicitly copy, but an extra copy
 | 
			
		||||
// of matrices seems highly undesirable.
 | 
			
		||||
static_assert(EIGEN_VERSION_AT_LEAST(3, 2, 7),
 | 
			
		||||
              "Eigen matrix support in pybind11 requires Eigen >= 3.2.7");
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
 | 
			
		||||
 | 
			
		||||
// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
 | 
			
		||||
using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
 | 
			
		||||
template <typename MatrixType>
 | 
			
		||||
using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
 | 
			
		||||
template <typename MatrixType>
 | 
			
		||||
using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
 | 
			
		||||
#if EIGEN_VERSION_AT_LEAST(3, 3, 0)
 | 
			
		||||
using EigenIndex = Eigen::Index;
 | 
			
		||||
template <typename Scalar, int Flags, typename StorageIndex>
 | 
			
		||||
using EigenMapSparseMatrix = Eigen::Map<Eigen::SparseMatrix<Scalar, Flags, StorageIndex>>;
 | 
			
		||||
#else
 | 
			
		||||
using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
 | 
			
		||||
template <typename Scalar, int Flags, typename StorageIndex>
 | 
			
		||||
using EigenMapSparseMatrix = Eigen::MappedSparseMatrix<Scalar, Flags, StorageIndex>;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Matches Eigen::Map, Eigen::Ref, blocks, etc:
 | 
			
		||||
template <typename T>
 | 
			
		||||
using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>,
 | 
			
		||||
                                  std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
 | 
			
		||||
template <typename T>
 | 
			
		||||
using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
 | 
			
		||||
template <typename T>
 | 
			
		||||
using is_eigen_dense_plain
 | 
			
		||||
    = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
 | 
			
		||||
template <typename T>
 | 
			
		||||
using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
 | 
			
		||||
// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above.  This
 | 
			
		||||
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
 | 
			
		||||
// matrix data layout that can be copied from their .data().  For example, DiagonalMatrix and
 | 
			
		||||
// SelfAdjointView fall into this category.
 | 
			
		||||
template <typename T>
 | 
			
		||||
using is_eigen_other
 | 
			
		||||
    = all_of<is_template_base_of<Eigen::EigenBase, T>,
 | 
			
		||||
             negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>>;
 | 
			
		||||
 | 
			
		||||
// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
 | 
			
		||||
template <bool EigenRowMajor>
 | 
			
		||||
struct EigenConformable {
 | 
			
		||||
    bool conformable = false;
 | 
			
		||||
    EigenIndex rows = 0, cols = 0;
 | 
			
		||||
    EigenDStride stride{0, 0};    // Only valid if negativestrides is false!
 | 
			
		||||
    bool negativestrides = false; // If true, do not use stride!
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    EigenConformable(bool fits = false) : conformable{fits} {}
 | 
			
		||||
    // Matrix type:
 | 
			
		||||
    EigenConformable(EigenIndex r, EigenIndex c, EigenIndex rstride, EigenIndex cstride)
 | 
			
		||||
        : conformable{true}, rows{r}, cols{c},
 | 
			
		||||
          // TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity.
 | 
			
		||||
          // http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
 | 
			
		||||
          stride{EigenRowMajor ? (rstride > 0 ? rstride : 0)
 | 
			
		||||
                               : (cstride > 0 ? cstride : 0) /* outer stride */,
 | 
			
		||||
                 EigenRowMajor ? (cstride > 0 ? cstride : 0)
 | 
			
		||||
                               : (rstride > 0 ? rstride : 0) /* inner stride */},
 | 
			
		||||
          negativestrides{rstride < 0 || cstride < 0} {}
 | 
			
		||||
    // Vector type:
 | 
			
		||||
    EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
 | 
			
		||||
        : EigenConformable(r, c, r == 1 ? c * stride : stride, c == 1 ? r : r * stride) {}
 | 
			
		||||
 | 
			
		||||
    template <typename props>
 | 
			
		||||
    bool stride_compatible() const {
 | 
			
		||||
        // To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
 | 
			
		||||
        // matching strides, or a dimension size of 1 (in which case the stride value is
 | 
			
		||||
        // irrelevant). Alternatively, if any dimension size is 0, the strides are not relevant
 | 
			
		||||
        // (and numpy ≥ 1.23 sets the strides to 0 in that case, so we need to check explicitly).
 | 
			
		||||
        if (negativestrides) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (rows == 0 || cols == 0) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
 | 
			
		||||
                || (EigenRowMajor ? cols : rows) == 1)
 | 
			
		||||
               && (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()
 | 
			
		||||
                   || (EigenRowMajor ? rows : cols) == 1);
 | 
			
		||||
    }
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator bool() const { return conformable; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Type>
 | 
			
		||||
struct eigen_extract_stride {
 | 
			
		||||
    using type = Type;
 | 
			
		||||
};
 | 
			
		||||
template <typename PlainObjectType, int MapOptions, typename StrideType>
 | 
			
		||||
struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> {
 | 
			
		||||
    using type = StrideType;
 | 
			
		||||
};
 | 
			
		||||
template <typename PlainObjectType, int Options, typename StrideType>
 | 
			
		||||
struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> {
 | 
			
		||||
    using type = StrideType;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Helper struct for extracting information from an Eigen type
 | 
			
		||||
template <typename Type_>
 | 
			
		||||
struct EigenProps {
 | 
			
		||||
    using Type = Type_;
 | 
			
		||||
    using Scalar = typename Type::Scalar;
 | 
			
		||||
    using StrideType = typename eigen_extract_stride<Type>::type;
 | 
			
		||||
    static constexpr EigenIndex rows = Type::RowsAtCompileTime, cols = Type::ColsAtCompileTime,
 | 
			
		||||
                                size = Type::SizeAtCompileTime;
 | 
			
		||||
    static constexpr bool row_major = Type::IsRowMajor,
 | 
			
		||||
                          vector
 | 
			
		||||
                          = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
 | 
			
		||||
        fixed_rows = rows != Eigen::Dynamic, fixed_cols = cols != Eigen::Dynamic,
 | 
			
		||||
                          fixed = size != Eigen::Dynamic, // Fully-fixed size
 | 
			
		||||
        dynamic = !fixed_rows && !fixed_cols;             // Fully-dynamic size
 | 
			
		||||
 | 
			
		||||
    template <EigenIndex i, EigenIndex ifzero>
 | 
			
		||||
    using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
 | 
			
		||||
    static constexpr EigenIndex inner_stride
 | 
			
		||||
        = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
 | 
			
		||||
        outer_stride = if_zero < StrideType::OuterStrideAtCompileTime,
 | 
			
		||||
        vector      ? size
 | 
			
		||||
        : row_major ? cols
 | 
			
		||||
                    : rows > ::value;
 | 
			
		||||
    static constexpr bool dynamic_stride
 | 
			
		||||
        = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
 | 
			
		||||
    static constexpr bool requires_row_major
 | 
			
		||||
        = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
 | 
			
		||||
    static constexpr bool requires_col_major
 | 
			
		||||
        = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
 | 
			
		||||
 | 
			
		||||
    // Takes an input array and determines whether we can make it fit into the Eigen type.  If
 | 
			
		||||
    // the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
 | 
			
		||||
    // (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
 | 
			
		||||
    static EigenConformable<row_major> conformable(const array &a) {
 | 
			
		||||
        const auto dims = a.ndim();
 | 
			
		||||
        if (dims < 1 || dims > 2) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (dims == 2) { // Matrix type: require exact match (or dynamic)
 | 
			
		||||
 | 
			
		||||
            EigenIndex np_rows = a.shape(0), np_cols = a.shape(1),
 | 
			
		||||
                       np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
 | 
			
		||||
                       np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
 | 
			
		||||
            if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return {np_rows, np_cols, np_rstride, np_cstride};
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Otherwise we're storing an n-vector.  Only one of the strides will be used, but
 | 
			
		||||
        // whichever is used, we want the (single) numpy stride value.
 | 
			
		||||
        const EigenIndex n = a.shape(0),
 | 
			
		||||
                         stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
 | 
			
		||||
 | 
			
		||||
        if (vector) { // Eigen type is a compile-time vector
 | 
			
		||||
            if (fixed && size != n) {
 | 
			
		||||
                return false; // Vector size mismatch
 | 
			
		||||
            }
 | 
			
		||||
            return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
 | 
			
		||||
        }
 | 
			
		||||
        if (fixed) {
 | 
			
		||||
            // The type has a fixed size, but is not a vector: abort
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (fixed_cols) {
 | 
			
		||||
            // Since this isn't a vector, cols must be != 1.  We allow this only if it exactly
 | 
			
		||||
            // equals the number of elements (rows is Dynamic, and so 1 row is allowed).
 | 
			
		||||
            if (cols != n) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            return {1, n, stride};
 | 
			
		||||
        } // Otherwise it's either fully dynamic, or column dynamic; both become a column vector
 | 
			
		||||
        if (fixed_rows && rows != n) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return {n, 1, stride};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr bool show_writeable
 | 
			
		||||
        = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
 | 
			
		||||
    static constexpr bool show_order = is_eigen_dense_map<Type>::value;
 | 
			
		||||
    static constexpr bool show_c_contiguous = show_order && requires_row_major;
 | 
			
		||||
    static constexpr bool show_f_contiguous
 | 
			
		||||
        = !show_c_contiguous && show_order && requires_col_major;
 | 
			
		||||
 | 
			
		||||
    static constexpr auto descriptor
 | 
			
		||||
        = const_name("numpy.ndarray[") + npy_format_descriptor<Scalar>::name + const_name("[")
 | 
			
		||||
          + const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) + const_name(", ")
 | 
			
		||||
          + const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n")) + const_name("]")
 | 
			
		||||
          +
 | 
			
		||||
          // For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to
 | 
			
		||||
          // be satisfied: writeable=True (for a mutable reference), and, depending on the map's
 | 
			
		||||
          // stride options, possibly f_contiguous or c_contiguous.  We include them in the
 | 
			
		||||
          // descriptor output to provide some hint as to why a TypeError is occurring (otherwise
 | 
			
		||||
          // it can be confusing to see that a function accepts a 'numpy.ndarray[float64[3,2]]' and
 | 
			
		||||
          // an error message that you *gave* a numpy.ndarray of the right type and dimensions.
 | 
			
		||||
          const_name<show_writeable>(", flags.writeable", "")
 | 
			
		||||
          + const_name<show_c_contiguous>(", flags.c_contiguous", "")
 | 
			
		||||
          + const_name<show_f_contiguous>(", flags.f_contiguous", "") + const_name("]");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Casts an Eigen type to numpy array.  If given a base, the numpy array references the src data,
 | 
			
		||||
// otherwise it'll make a copy.  writeable lets you turn off the writeable flag for the array.
 | 
			
		||||
template <typename props>
 | 
			
		||||
handle
 | 
			
		||||
eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
 | 
			
		||||
    constexpr ssize_t elem_size = sizeof(typename props::Scalar);
 | 
			
		||||
    array a;
 | 
			
		||||
    if (props::vector) {
 | 
			
		||||
        a = array({src.size()}, {elem_size * src.innerStride()}, src.data(), base);
 | 
			
		||||
    } else {
 | 
			
		||||
        a = array({src.rows(), src.cols()},
 | 
			
		||||
                  {elem_size * src.rowStride(), elem_size * src.colStride()},
 | 
			
		||||
                  src.data(),
 | 
			
		||||
                  base);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!writeable) {
 | 
			
		||||
        array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return a.release();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that
 | 
			
		||||
// reference the Eigen object's data with `base` as the python-registered base class (if omitted,
 | 
			
		||||
// the base will be set to None, and lifetime management is up to the caller).  The numpy array is
 | 
			
		||||
// non-writeable if the given type is const.
 | 
			
		||||
template <typename props, typename Type>
 | 
			
		||||
handle eigen_ref_array(Type &src, handle parent = none()) {
 | 
			
		||||
    // none here is to get past array's should-we-copy detection, which currently always
 | 
			
		||||
    // copies when there is no base.  Setting the base to None should be harmless.
 | 
			
		||||
    return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a
 | 
			
		||||
// numpy array that references the encapsulated data with a python-side reference to the capsule to
 | 
			
		||||
// tie its destruction to that of any dependent python objects.  Const-ness is determined by
 | 
			
		||||
// whether or not the Type of the pointer given is const.
 | 
			
		||||
template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
 | 
			
		||||
handle eigen_encapsulate(Type *src) {
 | 
			
		||||
    capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
 | 
			
		||||
    return eigen_ref_array<props>(*src, base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
 | 
			
		||||
// types.
 | 
			
		||||
template <typename Type>
 | 
			
		||||
struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
 | 
			
		||||
    using Scalar = typename Type::Scalar;
 | 
			
		||||
    static_assert(!std::is_pointer<Scalar>::value,
 | 
			
		||||
                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
 | 
			
		||||
    using props = EigenProps<Type>;
 | 
			
		||||
 | 
			
		||||
    bool load(handle src, bool convert) {
 | 
			
		||||
        // If we're in no-convert mode, only load if given an array of the correct type
 | 
			
		||||
        if (!convert && !isinstance<array_t<Scalar>>(src)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Coerce into an array, but don't do type conversion yet; the copy below handles it.
 | 
			
		||||
        auto buf = array::ensure(src);
 | 
			
		||||
 | 
			
		||||
        if (!buf) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto dims = buf.ndim();
 | 
			
		||||
        if (dims < 1 || dims > 2) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto fits = props::conformable(buf);
 | 
			
		||||
        if (!fits) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Allocate the new type, then build a numpy reference into it
 | 
			
		||||
        value = Type(fits.rows, fits.cols);
 | 
			
		||||
        auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
 | 
			
		||||
        if (dims == 1) {
 | 
			
		||||
            ref = ref.squeeze();
 | 
			
		||||
        } else if (ref.ndim() == 1) {
 | 
			
		||||
            buf = buf.squeeze();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
 | 
			
		||||
 | 
			
		||||
        if (result < 0) { // Copy failed!
 | 
			
		||||
            PyErr_Clear();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    // Cast implementation
 | 
			
		||||
    template <typename CType>
 | 
			
		||||
    static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        switch (policy) {
 | 
			
		||||
            case return_value_policy::take_ownership:
 | 
			
		||||
            case return_value_policy::automatic:
 | 
			
		||||
                return eigen_encapsulate<props>(src);
 | 
			
		||||
            case return_value_policy::move:
 | 
			
		||||
                return eigen_encapsulate<props>(new CType(std::move(*src)));
 | 
			
		||||
            case return_value_policy::copy:
 | 
			
		||||
                return eigen_array_cast<props>(*src);
 | 
			
		||||
            case return_value_policy::reference:
 | 
			
		||||
            case return_value_policy::automatic_reference:
 | 
			
		||||
                return eigen_ref_array<props>(*src);
 | 
			
		||||
            case return_value_policy::reference_internal:
 | 
			
		||||
                return eigen_ref_array<props>(*src, parent);
 | 
			
		||||
            default:
 | 
			
		||||
                throw cast_error("unhandled return_value_policy: should not happen!");
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    // Normal returned non-reference, non-const value:
 | 
			
		||||
    static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
 | 
			
		||||
        return cast_impl(&src, return_value_policy::move, parent);
 | 
			
		||||
    }
 | 
			
		||||
    // If you return a non-reference const, we mark the numpy array readonly:
 | 
			
		||||
    static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) {
 | 
			
		||||
        return cast_impl(&src, return_value_policy::move, parent);
 | 
			
		||||
    }
 | 
			
		||||
    // lvalue reference return; default (automatic) becomes copy
 | 
			
		||||
    static handle cast(Type &src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic
 | 
			
		||||
            || policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::copy;
 | 
			
		||||
        }
 | 
			
		||||
        return cast_impl(&src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
    // const lvalue reference return; default (automatic) becomes copy
 | 
			
		||||
    static handle cast(const Type &src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic
 | 
			
		||||
            || policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::copy;
 | 
			
		||||
        }
 | 
			
		||||
        return cast(&src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
    // non-const pointer return
 | 
			
		||||
    static handle cast(Type *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        return cast_impl(src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
    // const pointer return
 | 
			
		||||
    static handle cast(const Type *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        return cast_impl(src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr auto name = props::descriptor;
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator Type *() { return &value; }
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator Type &() { return value; }
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator Type &&() && { return std::move(value); }
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    using cast_op_type = movable_cast_op_type<T>;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Type value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Base class for casting reference/map/block/etc. objects back to python.
 | 
			
		||||
template <typename MapType>
 | 
			
		||||
struct eigen_map_caster {
 | 
			
		||||
    static_assert(!std::is_pointer<typename MapType::Scalar>::value,
 | 
			
		||||
                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    using props = EigenProps<MapType>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    // Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
 | 
			
		||||
    // to stay around), but we'll allow it under the assumption that you know what you're doing
 | 
			
		||||
    // (and have an appropriate keep_alive in place).  We return a numpy array pointing directly at
 | 
			
		||||
    // the ref's data (The numpy array ends up read-only if the ref was to a const matrix type.)
 | 
			
		||||
    // Note that this means you need to ensure you don't destroy the object in some other way (e.g.
 | 
			
		||||
    // with an appropriate keep_alive, or with a reference to a statically allocated matrix).
 | 
			
		||||
    static handle cast(const MapType &src, return_value_policy policy, handle parent) {
 | 
			
		||||
        switch (policy) {
 | 
			
		||||
            case return_value_policy::copy:
 | 
			
		||||
                return eigen_array_cast<props>(src);
 | 
			
		||||
            case return_value_policy::reference_internal:
 | 
			
		||||
                return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);
 | 
			
		||||
            case return_value_policy::reference:
 | 
			
		||||
            case return_value_policy::automatic:
 | 
			
		||||
            case return_value_policy::automatic_reference:
 | 
			
		||||
                return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);
 | 
			
		||||
            default:
 | 
			
		||||
                // move, take_ownership don't make any sense for a ref/map:
 | 
			
		||||
                pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr auto name = props::descriptor;
 | 
			
		||||
 | 
			
		||||
    // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
 | 
			
		||||
    // types but not bound arguments).  We still provide them (with an explicitly delete) so that
 | 
			
		||||
    // you end up here if you try anyway.
 | 
			
		||||
    bool load(handle, bool) = delete;
 | 
			
		||||
    operator MapType() = delete;
 | 
			
		||||
    template <typename>
 | 
			
		||||
    using cast_op_type = MapType;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// We can return any map-like object (but can only load Refs, specialized next):
 | 
			
		||||
template <typename Type>
 | 
			
		||||
struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>> : eigen_map_caster<Type> {};
 | 
			
		||||
 | 
			
		||||
// Loader for Ref<...> arguments.  See the documentation for info on how to make this work without
 | 
			
		||||
// copying (it requires some extra effort in many cases).
 | 
			
		||||
template <typename PlainObjectType, typename StrideType>
 | 
			
		||||
struct type_caster<
 | 
			
		||||
    Eigen::Ref<PlainObjectType, 0, StrideType>,
 | 
			
		||||
    enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>>
 | 
			
		||||
    : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
 | 
			
		||||
private:
 | 
			
		||||
    using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
 | 
			
		||||
    using props = EigenProps<Type>;
 | 
			
		||||
    using Scalar = typename props::Scalar;
 | 
			
		||||
    static_assert(!std::is_pointer<Scalar>::value,
 | 
			
		||||
                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
 | 
			
		||||
    using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
 | 
			
		||||
    using Array
 | 
			
		||||
        = array_t<Scalar,
 | 
			
		||||
                  array::forcecast
 | 
			
		||||
                      | ((props::row_major ? props::inner_stride : props::outer_stride) == 1
 | 
			
		||||
                             ? array::c_style
 | 
			
		||||
                         : (props::row_major ? props::outer_stride : props::inner_stride) == 1
 | 
			
		||||
                             ? array::f_style
 | 
			
		||||
                             : 0)>;
 | 
			
		||||
    static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
 | 
			
		||||
    // Delay construction (these have no default constructor)
 | 
			
		||||
    std::unique_ptr<MapType> map;
 | 
			
		||||
    std::unique_ptr<Type> ref;
 | 
			
		||||
    // Our array.  When possible, this is just a numpy array pointing to the source data, but
 | 
			
		||||
    // sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an
 | 
			
		||||
    // incompatible layout, or is an array of a type that needs to be converted).  Using a numpy
 | 
			
		||||
    // temporary (rather than an Eigen temporary) saves an extra copy when we need both type
 | 
			
		||||
    // conversion and storage order conversion.  (Note that we refuse to use this temporary copy
 | 
			
		||||
    // when loading an argument for a Ref<M> with M non-const, i.e. a read-write reference).
 | 
			
		||||
    Array copy_or_ref;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    bool load(handle src, bool convert) {
 | 
			
		||||
        // First check whether what we have is already an array of the right type.  If not, we
 | 
			
		||||
        // can't avoid a copy (because the copy is also going to do type conversion).
 | 
			
		||||
        bool need_copy = !isinstance<Array>(src);
 | 
			
		||||
 | 
			
		||||
        EigenConformable<props::row_major> fits;
 | 
			
		||||
        if (!need_copy) {
 | 
			
		||||
            // We don't need a converting copy, but we also need to check whether the strides are
 | 
			
		||||
            // compatible with the Ref's stride requirements
 | 
			
		||||
            auto aref = reinterpret_borrow<Array>(src);
 | 
			
		||||
 | 
			
		||||
            if (aref && (!need_writeable || aref.writeable())) {
 | 
			
		||||
                fits = props::conformable(aref);
 | 
			
		||||
                if (!fits) {
 | 
			
		||||
                    return false; // Incompatible dimensions
 | 
			
		||||
                }
 | 
			
		||||
                if (!fits.template stride_compatible<props>()) {
 | 
			
		||||
                    need_copy = true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    copy_or_ref = std::move(aref);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                need_copy = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (need_copy) {
 | 
			
		||||
            // We need to copy: If we need a mutable reference, or we're not supposed to convert
 | 
			
		||||
            // (either because we're in the no-convert overload pass, or because we're explicitly
 | 
			
		||||
            // instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
 | 
			
		||||
            if (!convert || need_writeable) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Array copy = Array::ensure(src);
 | 
			
		||||
            if (!copy) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            fits = props::conformable(copy);
 | 
			
		||||
            if (!fits || !fits.template stride_compatible<props>()) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            copy_or_ref = std::move(copy);
 | 
			
		||||
            loader_life_support::add_patient(copy_or_ref);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ref.reset();
 | 
			
		||||
        map.reset(new MapType(data(copy_or_ref),
 | 
			
		||||
                              fits.rows,
 | 
			
		||||
                              fits.cols,
 | 
			
		||||
                              make_stride(fits.stride.outer(), fits.stride.inner())));
 | 
			
		||||
        ref.reset(new Type(*map));
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator Type *() { return ref.get(); }
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    operator Type &() { return *ref; }
 | 
			
		||||
    template <typename _T>
 | 
			
		||||
    using cast_op_type = pybind11::detail::cast_op_type<_T>;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
 | 
			
		||||
    Scalar *data(Array &a) {
 | 
			
		||||
        return a.mutable_data();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
 | 
			
		||||
    const Scalar *data(Array &a) {
 | 
			
		||||
        return a.data();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Attempt to figure out a constructor of `Stride` that will work.
 | 
			
		||||
    // If both strides are fixed, use a default constructor:
 | 
			
		||||
    template <typename S>
 | 
			
		||||
    using stride_ctor_default = bool_constant<S::InnerStrideAtCompileTime != Eigen::Dynamic
 | 
			
		||||
                                              && S::OuterStrideAtCompileTime != Eigen::Dynamic
 | 
			
		||||
                                              && std::is_default_constructible<S>::value>;
 | 
			
		||||
    // Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
 | 
			
		||||
    // Eigen::Stride, and use it:
 | 
			
		||||
    template <typename S>
 | 
			
		||||
    using stride_ctor_dual
 | 
			
		||||
        = bool_constant<!stride_ctor_default<S>::value
 | 
			
		||||
                        && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
 | 
			
		||||
    // Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
 | 
			
		||||
    // it (passing whichever stride is dynamic).
 | 
			
		||||
    template <typename S>
 | 
			
		||||
    using stride_ctor_outer
 | 
			
		||||
        = bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
 | 
			
		||||
                        && S::OuterStrideAtCompileTime == Eigen::Dynamic
 | 
			
		||||
                        && S::InnerStrideAtCompileTime != Eigen::Dynamic
 | 
			
		||||
                        && std::is_constructible<S, EigenIndex>::value>;
 | 
			
		||||
    template <typename S>
 | 
			
		||||
    using stride_ctor_inner
 | 
			
		||||
        = bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
 | 
			
		||||
                        && S::InnerStrideAtCompileTime == Eigen::Dynamic
 | 
			
		||||
                        && S::OuterStrideAtCompileTime != Eigen::Dynamic
 | 
			
		||||
                        && std::is_constructible<S, EigenIndex>::value>;
 | 
			
		||||
 | 
			
		||||
    template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
 | 
			
		||||
    static S make_stride(EigenIndex, EigenIndex) {
 | 
			
		||||
        return S();
 | 
			
		||||
    }
 | 
			
		||||
    template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
 | 
			
		||||
    static S make_stride(EigenIndex outer, EigenIndex inner) {
 | 
			
		||||
        return S(outer, inner);
 | 
			
		||||
    }
 | 
			
		||||
    template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
 | 
			
		||||
    static S make_stride(EigenIndex outer, EigenIndex) {
 | 
			
		||||
        return S(outer);
 | 
			
		||||
    }
 | 
			
		||||
    template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
 | 
			
		||||
    static S make_stride(EigenIndex, EigenIndex inner) {
 | 
			
		||||
        return S(inner);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
 | 
			
		||||
// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout).
 | 
			
		||||
// load() is not supported, but we can cast them into the python domain by first copying to a
 | 
			
		||||
// regular Eigen::Matrix, then casting that.
 | 
			
		||||
template <typename Type>
 | 
			
		||||
struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
 | 
			
		||||
    static_assert(!std::is_pointer<typename Type::Scalar>::value,
 | 
			
		||||
                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    using Matrix
 | 
			
		||||
        = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
 | 
			
		||||
    using props = EigenProps<Matrix>;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
 | 
			
		||||
        handle h = eigen_encapsulate<props>(new Matrix(src));
 | 
			
		||||
        return h;
 | 
			
		||||
    }
 | 
			
		||||
    static handle cast(const Type *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        return cast(*src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr auto name = props::descriptor;
 | 
			
		||||
 | 
			
		||||
    // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
 | 
			
		||||
    // types but not bound arguments).  We still provide them (with an explicitly delete) so that
 | 
			
		||||
    // you end up here if you try anyway.
 | 
			
		||||
    bool load(handle, bool) = delete;
 | 
			
		||||
    operator Type() = delete;
 | 
			
		||||
    template <typename>
 | 
			
		||||
    using cast_op_type = Type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Type>
 | 
			
		||||
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
 | 
			
		||||
    using Scalar = typename Type::Scalar;
 | 
			
		||||
    static_assert(!std::is_pointer<Scalar>::value,
 | 
			
		||||
                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
 | 
			
		||||
    using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;
 | 
			
		||||
    using Index = typename Type::Index;
 | 
			
		||||
    static constexpr bool rowMajor = Type::IsRowMajor;
 | 
			
		||||
 | 
			
		||||
    bool load(handle src, bool) {
 | 
			
		||||
        if (!src) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto obj = reinterpret_borrow<object>(src);
 | 
			
		||||
        object sparse_module = module_::import("scipy.sparse");
 | 
			
		||||
        object matrix_type = sparse_module.attr(rowMajor ? "csr_matrix" : "csc_matrix");
 | 
			
		||||
 | 
			
		||||
        if (!type::handle_of(obj).is(matrix_type)) {
 | 
			
		||||
            try {
 | 
			
		||||
                obj = matrix_type(obj);
 | 
			
		||||
            } catch (const error_already_set &) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto values = array_t<Scalar>((object) obj.attr("data"));
 | 
			
		||||
        auto innerIndices = array_t<StorageIndex>((object) obj.attr("indices"));
 | 
			
		||||
        auto outerIndices = array_t<StorageIndex>((object) obj.attr("indptr"));
 | 
			
		||||
        auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
 | 
			
		||||
        auto nnz = obj.attr("nnz").cast<Index>();
 | 
			
		||||
 | 
			
		||||
        if (!values || !innerIndices || !outerIndices) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        value = EigenMapSparseMatrix<Scalar,
 | 
			
		||||
                                     Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
 | 
			
		||||
                                     StorageIndex>(shape[0].cast<Index>(),
 | 
			
		||||
                                                   shape[1].cast<Index>(),
 | 
			
		||||
                                                   std::move(nnz),
 | 
			
		||||
                                                   outerIndices.mutable_data(),
 | 
			
		||||
                                                   innerIndices.mutable_data(),
 | 
			
		||||
                                                   values.mutable_data());
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
 | 
			
		||||
        const_cast<Type &>(src).makeCompressed();
 | 
			
		||||
 | 
			
		||||
        object matrix_type
 | 
			
		||||
            = module_::import("scipy.sparse").attr(rowMajor ? "csr_matrix" : "csc_matrix");
 | 
			
		||||
 | 
			
		||||
        array data(src.nonZeros(), src.valuePtr());
 | 
			
		||||
        array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
 | 
			
		||||
        array innerIndices(src.nonZeros(), src.innerIndexPtr());
 | 
			
		||||
 | 
			
		||||
        return matrix_type(pybind11::make_tuple(
 | 
			
		||||
                               std::move(data), std::move(innerIndices), std::move(outerIndices)),
 | 
			
		||||
                           pybind11::make_tuple(src.rows(), src.cols()))
 | 
			
		||||
            .release();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PYBIND11_TYPE_CASTER(Type,
 | 
			
		||||
                         const_name<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[",
 | 
			
		||||
                                                             "scipy.sparse.csc_matrix[")
 | 
			
		||||
                             + npy_format_descriptor<Scalar>::name + const_name("]"));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,516 @@
 | 
			
		|||
/*
 | 
			
		||||
    pybind11/eigen/tensor.h: Transparent conversion for Eigen tensors
 | 
			
		||||
 | 
			
		||||
    All rights reserved. Use of this source code is governed by a
 | 
			
		||||
    BSD-style license that can be found in the LICENSE file.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "../numpy.h"
 | 
			
		||||
#include "common.h"
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
 | 
			
		||||
static_assert(__GNUC__ > 5, "Eigen Tensor support in pybind11 requires GCC > 5.0");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Disable warnings for Eigen
 | 
			
		||||
PYBIND11_WARNING_PUSH
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4554)
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
 | 
			
		||||
#if defined(__MINGW32__)
 | 
			
		||||
PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <unsupported/Eigen/CXX11/Tensor>
 | 
			
		||||
 | 
			
		||||
PYBIND11_WARNING_POP
 | 
			
		||||
 | 
			
		||||
static_assert(EIGEN_VERSION_AT_LEAST(3, 3, 0),
 | 
			
		||||
              "Eigen Tensor support in pybind11 requires Eigen >= 3.3.0");
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
 | 
			
		||||
inline bool is_tensor_aligned(const void *data) {
 | 
			
		||||
    return (reinterpret_cast<std::size_t>(data) % EIGEN_DEFAULT_ALIGN_BYTES) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
constexpr int compute_array_flag_from_tensor() {
 | 
			
		||||
    static_assert((static_cast<int>(T::Layout) == static_cast<int>(Eigen::RowMajor))
 | 
			
		||||
                      || (static_cast<int>(T::Layout) == static_cast<int>(Eigen::ColMajor)),
 | 
			
		||||
                  "Layout must be row or column major");
 | 
			
		||||
    return (static_cast<int>(T::Layout) == static_cast<int>(Eigen::RowMajor)) ? array::c_style
 | 
			
		||||
                                                                              : array::f_style;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct eigen_tensor_helper {};
 | 
			
		||||
 | 
			
		||||
template <typename Scalar_, int NumIndices_, int Options_, typename IndexType>
 | 
			
		||||
struct eigen_tensor_helper<Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType>> {
 | 
			
		||||
    using Type = Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType>;
 | 
			
		||||
    using ValidType = void;
 | 
			
		||||
 | 
			
		||||
    static Eigen::DSizes<typename Type::Index, Type::NumIndices> get_shape(const Type &f) {
 | 
			
		||||
        return f.dimensions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr bool
 | 
			
		||||
    is_correct_shape(const Eigen::DSizes<typename Type::Index, Type::NumIndices> & /*shape*/) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    struct helper {};
 | 
			
		||||
 | 
			
		||||
    template <size_t... Is>
 | 
			
		||||
    struct helper<index_sequence<Is...>> {
 | 
			
		||||
        static constexpr auto value = concat(const_name(((void) Is, "?"))...);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static constexpr auto dimensions_descriptor
 | 
			
		||||
        = helper<decltype(make_index_sequence<Type::NumIndices>())>::value;
 | 
			
		||||
 | 
			
		||||
    template <typename... Args>
 | 
			
		||||
    static Type *alloc(Args &&...args) {
 | 
			
		||||
        return new Type(std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void free(Type *tensor) { delete tensor; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Scalar_, typename std::ptrdiff_t... Indices, int Options_, typename IndexType>
 | 
			
		||||
struct eigen_tensor_helper<
 | 
			
		||||
    Eigen::TensorFixedSize<Scalar_, Eigen::Sizes<Indices...>, Options_, IndexType>> {
 | 
			
		||||
    using Type = Eigen::TensorFixedSize<Scalar_, Eigen::Sizes<Indices...>, Options_, IndexType>;
 | 
			
		||||
    using ValidType = void;
 | 
			
		||||
 | 
			
		||||
    static constexpr Eigen::DSizes<typename Type::Index, Type::NumIndices>
 | 
			
		||||
    get_shape(const Type & /*f*/) {
 | 
			
		||||
        return get_shape();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr Eigen::DSizes<typename Type::Index, Type::NumIndices> get_shape() {
 | 
			
		||||
        return Eigen::DSizes<typename Type::Index, Type::NumIndices>(Indices...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static bool
 | 
			
		||||
    is_correct_shape(const Eigen::DSizes<typename Type::Index, Type::NumIndices> &shape) {
 | 
			
		||||
        return get_shape() == shape;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr auto dimensions_descriptor = concat(const_name<Indices>()...);
 | 
			
		||||
 | 
			
		||||
    template <typename... Args>
 | 
			
		||||
    static Type *alloc(Args &&...args) {
 | 
			
		||||
        Eigen::aligned_allocator<Type> allocator;
 | 
			
		||||
        return ::new (allocator.allocate(1)) Type(std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void free(Type *tensor) {
 | 
			
		||||
        Eigen::aligned_allocator<Type> allocator;
 | 
			
		||||
        tensor->~Type();
 | 
			
		||||
        allocator.deallocate(tensor, 1);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Type, bool ShowDetails, bool NeedsWriteable = false>
 | 
			
		||||
struct get_tensor_descriptor {
 | 
			
		||||
    static constexpr auto details
 | 
			
		||||
        = const_name<NeedsWriteable>(", flags.writeable", "")
 | 
			
		||||
          + const_name<static_cast<int>(Type::Layout) == static_cast<int>(Eigen::RowMajor)>(
 | 
			
		||||
              ", flags.c_contiguous", ", flags.f_contiguous");
 | 
			
		||||
    static constexpr auto value
 | 
			
		||||
        = const_name("numpy.ndarray[") + npy_format_descriptor<typename Type::Scalar>::name
 | 
			
		||||
          + const_name("[") + eigen_tensor_helper<remove_cv_t<Type>>::dimensions_descriptor
 | 
			
		||||
          + const_name("]") + const_name<ShowDetails>(details, const_name("")) + const_name("]");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// When EIGEN_AVOID_STL_ARRAY is defined, Eigen::DSizes<T, 0> does not have the begin() member
 | 
			
		||||
// function. Falling back to a simple loop works around this issue.
 | 
			
		||||
//
 | 
			
		||||
// We need to disable the type-limits warning for the inner loop when size = 0.
 | 
			
		||||
 | 
			
		||||
PYBIND11_WARNING_PUSH
 | 
			
		||||
PYBIND11_WARNING_DISABLE_GCC("-Wtype-limits")
 | 
			
		||||
 | 
			
		||||
template <typename T, int size>
 | 
			
		||||
std::vector<T> convert_dsizes_to_vector(const Eigen::DSizes<T, size> &arr) {
 | 
			
		||||
    std::vector<T> result(size);
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < size; i++) {
 | 
			
		||||
        result[i] = arr[i];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, int size>
 | 
			
		||||
Eigen::DSizes<T, size> get_shape_for_array(const array &arr) {
 | 
			
		||||
    Eigen::DSizes<T, size> result;
 | 
			
		||||
    const T *shape = arr.shape();
 | 
			
		||||
    for (size_t i = 0; i < size; i++) {
 | 
			
		||||
        result[i] = shape[i];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PYBIND11_WARNING_POP
 | 
			
		||||
 | 
			
		||||
template <typename Type>
 | 
			
		||||
struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
 | 
			
		||||
    static_assert(!std::is_pointer<typename Type::Scalar>::value,
 | 
			
		||||
                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
 | 
			
		||||
    using Helper = eigen_tensor_helper<Type>;
 | 
			
		||||
    static constexpr auto temp_name = get_tensor_descriptor<Type, false>::value;
 | 
			
		||||
    PYBIND11_TYPE_CASTER(Type, temp_name);
 | 
			
		||||
 | 
			
		||||
    bool load(handle src, bool convert) {
 | 
			
		||||
        if (!convert) {
 | 
			
		||||
            if (!isinstance<array>(src)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            array temp = array::ensure(src);
 | 
			
		||||
            if (!temp) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!temp.dtype().is(dtype::of<typename Type::Scalar>())) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()> arr(
 | 
			
		||||
            reinterpret_borrow<object>(src));
 | 
			
		||||
 | 
			
		||||
        if (arr.ndim() != Type::NumIndices) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        auto shape = get_shape_for_array<typename Type::Index, Type::NumIndices>(arr);
 | 
			
		||||
 | 
			
		||||
        if (!Helper::is_correct_shape(shape)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
 | 
			
		||||
        auto data_pointer = arr.data();
 | 
			
		||||
#else
 | 
			
		||||
        // Handle Eigen bug
 | 
			
		||||
        auto data_pointer = const_cast<typename Type::Scalar *>(arr.data());
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        if (is_tensor_aligned(arr.data())) {
 | 
			
		||||
            value = Eigen::TensorMap<const Type, Eigen::Aligned>(data_pointer, shape);
 | 
			
		||||
        } else {
 | 
			
		||||
            value = Eigen::TensorMap<const Type>(data_pointer, shape);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(Type &&src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::reference
 | 
			
		||||
            || policy == return_value_policy::reference_internal) {
 | 
			
		||||
            pybind11_fail("Cannot use a reference return value policy for an rvalue");
 | 
			
		||||
        }
 | 
			
		||||
        return cast_impl(&src, return_value_policy::move, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(const Type &&src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::reference
 | 
			
		||||
            || policy == return_value_policy::reference_internal) {
 | 
			
		||||
            pybind11_fail("Cannot use a reference return value policy for an rvalue");
 | 
			
		||||
        }
 | 
			
		||||
        return cast_impl(&src, return_value_policy::move, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(Type &src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic
 | 
			
		||||
            || policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::copy;
 | 
			
		||||
        }
 | 
			
		||||
        return cast_impl(&src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(const Type &src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic
 | 
			
		||||
            || policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::copy;
 | 
			
		||||
        }
 | 
			
		||||
        return cast(&src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(Type *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic) {
 | 
			
		||||
            policy = return_value_policy::take_ownership;
 | 
			
		||||
        } else if (policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::reference;
 | 
			
		||||
        }
 | 
			
		||||
        return cast_impl(src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(const Type *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic) {
 | 
			
		||||
            policy = return_value_policy::take_ownership;
 | 
			
		||||
        } else if (policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::reference;
 | 
			
		||||
        }
 | 
			
		||||
        return cast_impl(src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename C>
 | 
			
		||||
    static handle cast_impl(C *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        object parent_object;
 | 
			
		||||
        bool writeable = false;
 | 
			
		||||
        switch (policy) {
 | 
			
		||||
            case return_value_policy::move:
 | 
			
		||||
                if (std::is_const<C>::value) {
 | 
			
		||||
                    pybind11_fail("Cannot move from a constant reference");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                src = Helper::alloc(std::move(*src));
 | 
			
		||||
 | 
			
		||||
                parent_object
 | 
			
		||||
                    = capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });
 | 
			
		||||
                writeable = true;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case return_value_policy::take_ownership:
 | 
			
		||||
                if (std::is_const<C>::value) {
 | 
			
		||||
                    // This cast is ugly, and might be UB in some cases, but we don't have an
 | 
			
		||||
                    // alternative here as we must free that memory
 | 
			
		||||
                    Helper::free(const_cast<Type *>(src));
 | 
			
		||||
                    pybind11_fail("Cannot take ownership of a const reference");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                parent_object
 | 
			
		||||
                    = capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });
 | 
			
		||||
                writeable = true;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case return_value_policy::copy:
 | 
			
		||||
                writeable = true;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case return_value_policy::reference:
 | 
			
		||||
                parent_object = none();
 | 
			
		||||
                writeable = !std::is_const<C>::value;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case return_value_policy::reference_internal:
 | 
			
		||||
                // Default should do the right thing
 | 
			
		||||
                if (!parent) {
 | 
			
		||||
                    pybind11_fail("Cannot use reference internal when there is no parent");
 | 
			
		||||
                }
 | 
			
		||||
                parent_object = reinterpret_borrow<object>(parent);
 | 
			
		||||
                writeable = !std::is_const<C>::value;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                pybind11_fail("pybind11 bug in eigen.h, please file a bug report");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto result = array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()>(
 | 
			
		||||
            convert_dsizes_to_vector(Helper::get_shape(*src)), src->data(), parent_object);
 | 
			
		||||
 | 
			
		||||
        if (!writeable) {
 | 
			
		||||
            array_proxy(result.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result.release();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename StoragePointerType,
 | 
			
		||||
          bool needs_writeable,
 | 
			
		||||
          enable_if_t<!needs_writeable, bool> = true>
 | 
			
		||||
StoragePointerType get_array_data_for_type(array &arr) {
 | 
			
		||||
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
 | 
			
		||||
    return reinterpret_cast<StoragePointerType>(arr.data());
 | 
			
		||||
#else
 | 
			
		||||
    // Handle Eigen bug
 | 
			
		||||
    return reinterpret_cast<StoragePointerType>(const_cast<void *>(arr.data()));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename StoragePointerType,
 | 
			
		||||
          bool needs_writeable,
 | 
			
		||||
          enable_if_t<needs_writeable, bool> = true>
 | 
			
		||||
StoragePointerType get_array_data_for_type(array &arr) {
 | 
			
		||||
    return reinterpret_cast<StoragePointerType>(arr.mutable_data());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename = void>
 | 
			
		||||
struct get_storage_pointer_type;
 | 
			
		||||
 | 
			
		||||
template <typename MapType>
 | 
			
		||||
struct get_storage_pointer_type<MapType, void_t<typename MapType::StoragePointerType>> {
 | 
			
		||||
    using SPT = typename MapType::StoragePointerType;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename MapType>
 | 
			
		||||
struct get_storage_pointer_type<MapType, void_t<typename MapType::PointerArgType>> {
 | 
			
		||||
    using SPT = typename MapType::PointerArgType;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Type, int Options>
 | 
			
		||||
struct type_caster<Eigen::TensorMap<Type, Options>,
 | 
			
		||||
                   typename eigen_tensor_helper<remove_cv_t<Type>>::ValidType> {
 | 
			
		||||
    static_assert(!std::is_pointer<typename Type::Scalar>::value,
 | 
			
		||||
                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
 | 
			
		||||
    using MapType = Eigen::TensorMap<Type, Options>;
 | 
			
		||||
    using Helper = eigen_tensor_helper<remove_cv_t<Type>>;
 | 
			
		||||
 | 
			
		||||
    bool load(handle src, bool /*convert*/) {
 | 
			
		||||
        // Note that we have a lot more checks here as we want to make sure to avoid copies
 | 
			
		||||
        if (!isinstance<array>(src)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        auto arr = reinterpret_borrow<array>(src);
 | 
			
		||||
        if ((arr.flags() & compute_array_flag_from_tensor<Type>()) == 0) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!arr.dtype().is(dtype::of<typename Type::Scalar>())) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (arr.ndim() != Type::NumIndices) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        constexpr bool is_aligned = (Options & Eigen::Aligned) != 0;
 | 
			
		||||
 | 
			
		||||
        if (is_aligned && !is_tensor_aligned(arr.data())) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto shape = get_shape_for_array<typename Type::Index, Type::NumIndices>(arr);
 | 
			
		||||
 | 
			
		||||
        if (!Helper::is_correct_shape(shape)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (needs_writeable && !arr.writeable()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto result = get_array_data_for_type<typename get_storage_pointer_type<MapType>::SPT,
 | 
			
		||||
                                              needs_writeable>(arr);
 | 
			
		||||
 | 
			
		||||
        value.reset(new MapType(std::move(result), std::move(shape)));
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(MapType &&src, return_value_policy policy, handle parent) {
 | 
			
		||||
        return cast_impl(&src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(const MapType &&src, return_value_policy policy, handle parent) {
 | 
			
		||||
        return cast_impl(&src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(MapType &src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic
 | 
			
		||||
            || policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::copy;
 | 
			
		||||
        }
 | 
			
		||||
        return cast_impl(&src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(const MapType &src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic
 | 
			
		||||
            || policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::copy;
 | 
			
		||||
        }
 | 
			
		||||
        return cast(&src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(MapType *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic) {
 | 
			
		||||
            policy = return_value_policy::take_ownership;
 | 
			
		||||
        } else if (policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::reference;
 | 
			
		||||
        }
 | 
			
		||||
        return cast_impl(src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(const MapType *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (policy == return_value_policy::automatic) {
 | 
			
		||||
            policy = return_value_policy::take_ownership;
 | 
			
		||||
        } else if (policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            policy = return_value_policy::reference;
 | 
			
		||||
        }
 | 
			
		||||
        return cast_impl(src, policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename C>
 | 
			
		||||
    static handle cast_impl(C *src, return_value_policy policy, handle parent) {
 | 
			
		||||
        object parent_object;
 | 
			
		||||
        constexpr bool writeable = !std::is_const<C>::value;
 | 
			
		||||
        switch (policy) {
 | 
			
		||||
            case return_value_policy::reference:
 | 
			
		||||
                parent_object = none();
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case return_value_policy::reference_internal:
 | 
			
		||||
                // Default should do the right thing
 | 
			
		||||
                if (!parent) {
 | 
			
		||||
                    pybind11_fail("Cannot use reference internal when there is no parent");
 | 
			
		||||
                }
 | 
			
		||||
                parent_object = reinterpret_borrow<object>(parent);
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case return_value_policy::take_ownership:
 | 
			
		||||
                delete src;
 | 
			
		||||
                // fallthrough
 | 
			
		||||
            default:
 | 
			
		||||
                // move, take_ownership don't make any sense for a ref/map:
 | 
			
		||||
                pybind11_fail("Invalid return_value_policy for Eigen Map type, must be either "
 | 
			
		||||
                              "reference or reference_internal");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto result = array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()>(
 | 
			
		||||
            convert_dsizes_to_vector(Helper::get_shape(*src)),
 | 
			
		||||
            src->data(),
 | 
			
		||||
            std::move(parent_object));
 | 
			
		||||
 | 
			
		||||
        if (!writeable) {
 | 
			
		||||
            array_proxy(result.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result.release();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
 | 
			
		||||
 | 
			
		||||
    static constexpr bool needs_writeable = !std::is_const<typename std::remove_pointer<
 | 
			
		||||
        typename get_storage_pointer_type<MapType>::SPT>::type>::value;
 | 
			
		||||
#else
 | 
			
		||||
    // Handle Eigen bug
 | 
			
		||||
    static constexpr bool needs_writeable = !std::is_const<Type>::value;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    // TODO: Move to std::optional once std::optional has more support
 | 
			
		||||
    std::unique_ptr<MapType> value;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static constexpr auto name = get_tensor_descriptor<Type, true, needs_writeable>::value;
 | 
			
		||||
    explicit operator MapType *() { return value.get(); }
 | 
			
		||||
    explicit operator MapType &() { return *value; }
 | 
			
		||||
    explicit operator MapType &&() && { return std::move(*value); }
 | 
			
		||||
 | 
			
		||||
    template <typename T_>
 | 
			
		||||
    using cast_op_type = ::pybind11::detail::movable_cast_op_type<T_>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
 | 
			
		||||
| 
						 | 
				
			
			@ -86,38 +86,26 @@ inline wchar_t *widen_chars(const char *safe_arg) {
 | 
			
		|||
    return widened_arg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
 | 
			
		||||
/** \rst
 | 
			
		||||
    Initialize the Python interpreter. No other pybind11 or CPython API functions can be
 | 
			
		||||
    called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
 | 
			
		||||
    optional `init_signal_handlers` parameter can be used to skip the registration of
 | 
			
		||||
    signal handlers (see the `Python documentation`_ for details). Calling this function
 | 
			
		||||
    again after the interpreter has already been initialized is a fatal error.
 | 
			
		||||
 | 
			
		||||
    If initializing the Python interpreter fails, then the program is terminated.  (This
 | 
			
		||||
    is controlled by the CPython runtime and is an exception to pybind11's normal behavior
 | 
			
		||||
    of throwing exceptions on errors.)
 | 
			
		||||
 | 
			
		||||
    The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are
 | 
			
		||||
    used to populate ``sys.argv`` and ``sys.path``.
 | 
			
		||||
    See the |PySys_SetArgvEx documentation|_ for details.
 | 
			
		||||
 | 
			
		||||
    .. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
 | 
			
		||||
    .. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation
 | 
			
		||||
    .. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx
 | 
			
		||||
 \endrst */
 | 
			
		||||
inline void initialize_interpreter(bool init_signal_handlers = true,
 | 
			
		||||
                                   int argc = 0,
 | 
			
		||||
                                   const char *const *argv = nullptr,
 | 
			
		||||
                                   bool add_program_dir_to_path = true) {
 | 
			
		||||
inline void precheck_interpreter() {
 | 
			
		||||
    if (Py_IsInitialized() != 0) {
 | 
			
		||||
        pybind11_fail("The interpreter is already running");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if PY_VERSION_HEX < 0x030B0000
 | 
			
		||||
#if !defined(PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX)
 | 
			
		||||
#    define PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX (0x03080000)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
 | 
			
		||||
inline void initialize_interpreter_pre_pyconfig(bool init_signal_handlers,
 | 
			
		||||
                                                int argc,
 | 
			
		||||
                                                const char *const *argv,
 | 
			
		||||
                                                bool add_program_dir_to_path) {
 | 
			
		||||
    detail::precheck_interpreter();
 | 
			
		||||
    Py_InitializeEx(init_signal_handlers ? 1 : 0);
 | 
			
		||||
#    if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000
 | 
			
		||||
    PyEval_InitThreads();
 | 
			
		||||
#    endif
 | 
			
		||||
 | 
			
		||||
    // Before it was special-cased in python 3.8, passing an empty or null argv
 | 
			
		||||
    // caused a segfault, so we have to reimplement the special case ourselves.
 | 
			
		||||
| 
						 | 
				
			
			@ -147,24 +135,30 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
 | 
			
		|||
    auto *pysys_argv = widened_argv.get();
 | 
			
		||||
 | 
			
		||||
    PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
 | 
			
		||||
#else
 | 
			
		||||
    PyConfig config;
 | 
			
		||||
    PyConfig_InitIsolatedConfig(&config);
 | 
			
		||||
    config.install_signal_handlers = init_signal_handlers ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    PyStatus status = PyConfig_SetBytesArgv(&config, argc, const_cast<char *const *>(argv));
 | 
			
		||||
    if (PyStatus_Exception(status)) {
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
 | 
			
		||||
#if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
 | 
			
		||||
inline void initialize_interpreter(PyConfig *config,
 | 
			
		||||
                                   int argc = 0,
 | 
			
		||||
                                   const char *const *argv = nullptr,
 | 
			
		||||
                                   bool add_program_dir_to_path = true) {
 | 
			
		||||
    detail::precheck_interpreter();
 | 
			
		||||
    PyStatus status = PyConfig_SetBytesArgv(config, argc, const_cast<char *const *>(argv));
 | 
			
		||||
    if (PyStatus_Exception(status) != 0) {
 | 
			
		||||
        // A failure here indicates a character-encoding failure or the python
 | 
			
		||||
        // interpreter out of memory. Give up.
 | 
			
		||||
        PyConfig_Clear(&config);
 | 
			
		||||
        throw std::runtime_error(PyStatus_IsError(status) ? status.err_msg
 | 
			
		||||
                                                          : "Failed to prepare CPython");
 | 
			
		||||
        PyConfig_Clear(config);
 | 
			
		||||
        throw std::runtime_error(PyStatus_IsError(status) != 0 ? status.err_msg
 | 
			
		||||
                                                               : "Failed to prepare CPython");
 | 
			
		||||
    }
 | 
			
		||||
    status = Py_InitializeFromConfig(&config);
 | 
			
		||||
    PyConfig_Clear(&config);
 | 
			
		||||
    if (PyStatus_Exception(status)) {
 | 
			
		||||
        throw std::runtime_error(PyStatus_IsError(status) ? status.err_msg
 | 
			
		||||
                                                          : "Failed to init CPython");
 | 
			
		||||
    status = Py_InitializeFromConfig(config);
 | 
			
		||||
    if (PyStatus_Exception(status) != 0) {
 | 
			
		||||
        PyConfig_Clear(config);
 | 
			
		||||
        throw std::runtime_error(PyStatus_IsError(status) != 0 ? status.err_msg
 | 
			
		||||
                                                               : "Failed to init CPython");
 | 
			
		||||
    }
 | 
			
		||||
    if (add_program_dir_to_path) {
 | 
			
		||||
        PyRun_SimpleString("import sys, os.path; "
 | 
			
		||||
| 
						 | 
				
			
			@ -172,6 +166,44 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
 | 
			
		|||
                           "os.path.abspath(os.path.dirname(sys.argv[0])) "
 | 
			
		||||
                           "if sys.argv and os.path.exists(sys.argv[0]) else '')");
 | 
			
		||||
    }
 | 
			
		||||
    PyConfig_Clear(config);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \rst
 | 
			
		||||
    Initialize the Python interpreter. No other pybind11 or CPython API functions can be
 | 
			
		||||
    called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
 | 
			
		||||
    optional `init_signal_handlers` parameter can be used to skip the registration of
 | 
			
		||||
    signal handlers (see the `Python documentation`_ for details). Calling this function
 | 
			
		||||
    again after the interpreter has already been initialized is a fatal error.
 | 
			
		||||
 | 
			
		||||
    If initializing the Python interpreter fails, then the program is terminated.  (This
 | 
			
		||||
    is controlled by the CPython runtime and is an exception to pybind11's normal behavior
 | 
			
		||||
    of throwing exceptions on errors.)
 | 
			
		||||
 | 
			
		||||
    The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are
 | 
			
		||||
    used to populate ``sys.argv`` and ``sys.path``.
 | 
			
		||||
    See the |PySys_SetArgvEx documentation|_ for details.
 | 
			
		||||
 | 
			
		||||
    .. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
 | 
			
		||||
    .. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation
 | 
			
		||||
    .. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx
 | 
			
		||||
 \endrst */
 | 
			
		||||
inline void initialize_interpreter(bool init_signal_handlers = true,
 | 
			
		||||
                                   int argc = 0,
 | 
			
		||||
                                   const char *const *argv = nullptr,
 | 
			
		||||
                                   bool add_program_dir_to_path = true) {
 | 
			
		||||
#if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
 | 
			
		||||
    detail::initialize_interpreter_pre_pyconfig(
 | 
			
		||||
        init_signal_handlers, argc, argv, add_program_dir_to_path);
 | 
			
		||||
#else
 | 
			
		||||
    PyConfig config;
 | 
			
		||||
    PyConfig_InitPythonConfig(&config);
 | 
			
		||||
    // See PR #4473 for background
 | 
			
		||||
    config.parse_argv = 0;
 | 
			
		||||
 | 
			
		||||
    config.install_signal_handlers = init_signal_handlers ? 1 : 0;
 | 
			
		||||
    initialize_interpreter(&config, argc, argv, add_program_dir_to_path);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -211,16 +243,14 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
 | 
			
		|||
 | 
			
		||||
 \endrst */
 | 
			
		||||
inline void finalize_interpreter() {
 | 
			
		||||
    handle builtins(PyEval_GetBuiltins());
 | 
			
		||||
    const char *id = PYBIND11_INTERNALS_ID;
 | 
			
		||||
 | 
			
		||||
    // Get the internals pointer (without creating it if it doesn't exist).  It's possible for the
 | 
			
		||||
    // internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()`
 | 
			
		||||
    // during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
 | 
			
		||||
    detail::internals **internals_ptr_ptr = detail::get_internals_pp();
 | 
			
		||||
    // It could also be stashed in builtins, so look there too:
 | 
			
		||||
    if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
 | 
			
		||||
        internals_ptr_ptr = capsule(builtins[id]);
 | 
			
		||||
    // It could also be stashed in state_dict, so look there too:
 | 
			
		||||
    if (object internals_obj
 | 
			
		||||
        = get_internals_obj_from_state_dict(detail::get_python_state_dict())) {
 | 
			
		||||
        internals_ptr_ptr = detail::get_internals_pp_from_capsule(internals_obj);
 | 
			
		||||
    }
 | 
			
		||||
    // Local internals contains data managed by the current interpreter, so we must clear them to
 | 
			
		||||
    // avoid undefined behaviors when initializing another interpreter
 | 
			
		||||
| 
						 | 
				
			
			@ -259,6 +289,15 @@ public:
 | 
			
		|||
        initialize_interpreter(init_signal_handlers, argc, argv, add_program_dir_to_path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
 | 
			
		||||
    explicit scoped_interpreter(PyConfig *config,
 | 
			
		||||
                                int argc = 0,
 | 
			
		||||
                                const char *const *argv = nullptr,
 | 
			
		||||
                                bool add_program_dir_to_path = true) {
 | 
			
		||||
        initialize_interpreter(config, argc, argv, add_program_dir_to_path);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    scoped_interpreter(const scoped_interpreter &) = delete;
 | 
			
		||||
    scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; }
 | 
			
		||||
    scoped_interpreter &operator=(const scoped_interpreter &) = delete;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,9 +48,16 @@ public:
 | 
			
		|||
         */
 | 
			
		||||
        if (auto cfunc = func.cpp_function()) {
 | 
			
		||||
            auto *cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());
 | 
			
		||||
            if (isinstance<capsule>(cfunc_self)) {
 | 
			
		||||
            if (cfunc_self == nullptr) {
 | 
			
		||||
                PyErr_Clear();
 | 
			
		||||
            } else if (isinstance<capsule>(cfunc_self)) {
 | 
			
		||||
                auto c = reinterpret_borrow<capsule>(cfunc_self);
 | 
			
		||||
                auto *rec = (function_record *) c;
 | 
			
		||||
 | 
			
		||||
                function_record *rec = nullptr;
 | 
			
		||||
                // Check that we can safely reinterpret the capsule into a function_record
 | 
			
		||||
                if (detail::is_function_record_capsule(c)) {
 | 
			
		||||
                    rec = c.get_pointer<function_record>();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                while (rec != nullptr) {
 | 
			
		||||
                    if (rec->is_stateless
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +117,7 @@ public:
 | 
			
		|||
    template <typename Func>
 | 
			
		||||
    static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
 | 
			
		||||
        if (!f_) {
 | 
			
		||||
            return none().inc_ref();
 | 
			
		||||
            return none().release();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto result = f_.template target<function_type>();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,10 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "detail/common.h"
 | 
			
		||||
#include "detail/internals.h"
 | 
			
		||||
 | 
			
		||||
#if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
 | 
			
		||||
#    include "detail/internals.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +24,9 @@ PyThreadState *get_thread_state_unchecked();
 | 
			
		|||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
 | 
			
		||||
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
 | 
			
		||||
#if defined(WITH_THREAD)
 | 
			
		||||
 | 
			
		||||
#    if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
 | 
			
		||||
 | 
			
		||||
/* The functions below essentially reproduce the PyGILState_* API using a RAII
 | 
			
		||||
 * pattern, but there are a few important differences:
 | 
			
		||||
| 
						 | 
				
			
			@ -62,11 +67,11 @@ public:
 | 
			
		|||
 | 
			
		||||
        if (!tstate) {
 | 
			
		||||
            tstate = PyThreadState_New(internals.istate);
 | 
			
		||||
#    if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
#        if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
            if (!tstate) {
 | 
			
		||||
                pybind11_fail("scoped_acquire: could not create thread state!");
 | 
			
		||||
            }
 | 
			
		||||
#    endif
 | 
			
		||||
#        endif
 | 
			
		||||
            tstate->gilstate_counter = 0;
 | 
			
		||||
            PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -80,24 +85,27 @@ public:
 | 
			
		|||
        inc_ref();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    gil_scoped_acquire(const gil_scoped_acquire &) = delete;
 | 
			
		||||
    gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
 | 
			
		||||
 | 
			
		||||
    void inc_ref() { ++tstate->gilstate_counter; }
 | 
			
		||||
 | 
			
		||||
    PYBIND11_NOINLINE void dec_ref() {
 | 
			
		||||
        --tstate->gilstate_counter;
 | 
			
		||||
#    if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
#        if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
        if (detail::get_thread_state_unchecked() != tstate) {
 | 
			
		||||
            pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
 | 
			
		||||
        }
 | 
			
		||||
        if (tstate->gilstate_counter < 0) {
 | 
			
		||||
            pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
 | 
			
		||||
        }
 | 
			
		||||
#    endif
 | 
			
		||||
#        endif
 | 
			
		||||
        if (tstate->gilstate_counter == 0) {
 | 
			
		||||
#    if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
#        if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
 | 
			
		||||
            if (!release) {
 | 
			
		||||
                pybind11_fail("scoped_acquire::dec_ref(): internal error!");
 | 
			
		||||
            }
 | 
			
		||||
#    endif
 | 
			
		||||
#        endif
 | 
			
		||||
            PyThreadState_Clear(tstate);
 | 
			
		||||
            if (active) {
 | 
			
		||||
                PyThreadState_DeleteCurrent();
 | 
			
		||||
| 
						 | 
				
			
			@ -144,6 +152,9 @@ public:
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    gil_scoped_release(const gil_scoped_release &) = delete;
 | 
			
		||||
    gil_scoped_release &operator=(const gil_scoped_release &) = delete;
 | 
			
		||||
 | 
			
		||||
    /// This method will disable the PyThreadState_DeleteCurrent call and the
 | 
			
		||||
    /// GIL won't be acquired. This method should be used if the interpreter
 | 
			
		||||
    /// could be shutting down when this is called, as thread deletion is not
 | 
			
		||||
| 
						 | 
				
			
			@ -172,12 +183,16 @@ private:
 | 
			
		|||
    bool disassoc;
 | 
			
		||||
    bool active = true;
 | 
			
		||||
};
 | 
			
		||||
#elif defined(PYPY_VERSION)
 | 
			
		||||
 | 
			
		||||
#    else // PYBIND11_SIMPLE_GIL_MANAGEMENT
 | 
			
		||||
 | 
			
		||||
class gil_scoped_acquire {
 | 
			
		||||
    PyGILState_STATE state;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    gil_scoped_acquire() { state = PyGILState_Ensure(); }
 | 
			
		||||
    gil_scoped_acquire() : state{PyGILState_Ensure()} {}
 | 
			
		||||
    gil_scoped_acquire(const gil_scoped_acquire &) = delete;
 | 
			
		||||
    gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
 | 
			
		||||
    ~gil_scoped_acquire() { PyGILState_Release(state); }
 | 
			
		||||
    void disarm() {}
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -186,17 +201,39 @@ class gil_scoped_release {
 | 
			
		|||
    PyThreadState *state;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    gil_scoped_release() { state = PyEval_SaveThread(); }
 | 
			
		||||
    gil_scoped_release() : state{PyEval_SaveThread()} {}
 | 
			
		||||
    gil_scoped_release(const gil_scoped_release &) = delete;
 | 
			
		||||
    gil_scoped_release &operator=(const gil_scoped_release &) = delete;
 | 
			
		||||
    ~gil_scoped_release() { PyEval_RestoreThread(state); }
 | 
			
		||||
    void disarm() {}
 | 
			
		||||
};
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#    endif // PYBIND11_SIMPLE_GIL_MANAGEMENT
 | 
			
		||||
 | 
			
		||||
#else // WITH_THREAD
 | 
			
		||||
 | 
			
		||||
class gil_scoped_acquire {
 | 
			
		||||
public:
 | 
			
		||||
    gil_scoped_acquire() {
 | 
			
		||||
        // Trick to suppress `unused variable` error messages (at call sites).
 | 
			
		||||
        (void) (this != (this + 1));
 | 
			
		||||
    }
 | 
			
		||||
    gil_scoped_acquire(const gil_scoped_acquire &) = delete;
 | 
			
		||||
    gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
 | 
			
		||||
    void disarm() {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class gil_scoped_release {
 | 
			
		||||
public:
 | 
			
		||||
    gil_scoped_release() {
 | 
			
		||||
        // Trick to suppress `unused variable` error messages (at call sites).
 | 
			
		||||
        (void) (this != (this + 1));
 | 
			
		||||
    }
 | 
			
		||||
    gil_scoped_release(const gil_scoped_release &) = delete;
 | 
			
		||||
    gil_scoped_release &operator=(const gil_scoped_release &) = delete;
 | 
			
		||||
    void disarm() {}
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // WITH_THREAD
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,8 @@ static_assert(std::is_signed<Py_intptr_t>::value, "Py_intptr_t must be signed");
 | 
			
		|||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
 | 
			
		||||
 | 
			
		||||
class array; // Forward declaration
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
| 
						 | 
				
			
			@ -537,7 +539,7 @@ PYBIND11_NAMESPACE_END(detail)
 | 
			
		|||
 | 
			
		||||
class dtype : public object {
 | 
			
		||||
public:
 | 
			
		||||
    PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_);
 | 
			
		||||
    PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_)
 | 
			
		||||
 | 
			
		||||
    explicit dtype(const buffer_info &info) {
 | 
			
		||||
        dtype descr(_dtype_from_pep3118()(pybind11::str(info.format)));
 | 
			
		||||
| 
						 | 
				
			
			@ -562,6 +564,8 @@ public:
 | 
			
		|||
        m_ptr = from_args(args).release().ptr();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Return dtype for the given typenum (one of the NPY_TYPES).
 | 
			
		||||
    /// https://numpy.org/devdocs/reference/c-api/array.html#c.PyArray_DescrFromType
 | 
			
		||||
    explicit dtype(int typenum)
 | 
			
		||||
        : object(detail::npy_api::get().PyArray_DescrFromType_(typenum), stolen_t{}) {
 | 
			
		||||
        if (m_ptr == nullptr) {
 | 
			
		||||
| 
						 | 
				
			
			@ -875,7 +879,7 @@ public:
 | 
			
		|||
     */
 | 
			
		||||
    template <typename T, ssize_t Dims = -1>
 | 
			
		||||
    detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
 | 
			
		||||
        if (PYBIND11_SILENCE_MSVC_C4127(Dims >= 0) && ndim() != Dims) {
 | 
			
		||||
        if (Dims >= 0 && ndim() != Dims) {
 | 
			
		||||
            throw std::domain_error("array has incorrect number of dimensions: "
 | 
			
		||||
                                    + std::to_string(ndim()) + "; expected "
 | 
			
		||||
                                    + std::to_string(Dims));
 | 
			
		||||
| 
						 | 
				
			
			@ -893,7 +897,7 @@ public:
 | 
			
		|||
     */
 | 
			
		||||
    template <typename T, ssize_t Dims = -1>
 | 
			
		||||
    detail::unchecked_reference<T, Dims> unchecked() const & {
 | 
			
		||||
        if (PYBIND11_SILENCE_MSVC_C4127(Dims >= 0) && ndim() != Dims) {
 | 
			
		||||
        if (Dims >= 0 && ndim() != Dims) {
 | 
			
		||||
            throw std::domain_error("array has incorrect number of dimensions: "
 | 
			
		||||
                                    + std::to_string(ndim()) + "; expected "
 | 
			
		||||
                                    + std::to_string(Dims));
 | 
			
		||||
| 
						 | 
				
			
			@ -1119,10 +1123,10 @@ public:
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a proxy object that provides const access to the array's data without bounds or
 | 
			
		||||
     * dimensionality checking.  Unlike `unchecked()`, this does not require that the underlying
 | 
			
		||||
     * array have the `writable` flag.  Use with care: the array must not be destroyed or reshaped
 | 
			
		||||
     * for the duration of the returned object, and the caller must take care not to access invalid
 | 
			
		||||
     * dimensions or dimension indices.
 | 
			
		||||
     * dimensionality checking.  Unlike `mutable_unchecked()`, this does not require that the
 | 
			
		||||
     * underlying array have the `writable` flag.  Use with care: the array must not be destroyed
 | 
			
		||||
     * or reshaped for the duration of the returned object, and the caller must take care not to
 | 
			
		||||
     * access invalid dimensions or dimension indices.
 | 
			
		||||
     */
 | 
			
		||||
    template <ssize_t Dims = -1>
 | 
			
		||||
    detail::unchecked_reference<T, Dims> unchecked() const & {
 | 
			
		||||
| 
						 | 
				
			
			@ -1281,12 +1285,16 @@ private:
 | 
			
		|||
public:
 | 
			
		||||
    static constexpr int value = values[detail::is_fmt_numeric<T>::index];
 | 
			
		||||
 | 
			
		||||
    static pybind11::dtype dtype() {
 | 
			
		||||
        if (auto *ptr = npy_api::get().PyArray_DescrFromType_(value)) {
 | 
			
		||||
            return reinterpret_steal<pybind11::dtype>(ptr);
 | 
			
		||||
        }
 | 
			
		||||
        pybind11_fail("Unsupported buffer format!");
 | 
			
		||||
    }
 | 
			
		||||
    static pybind11::dtype dtype() { return pybind11::dtype(/*typenum*/ value); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct npy_format_descriptor<T, enable_if_t<is_same_ignoring_cvref<T, PyObject *>::value>> {
 | 
			
		||||
    static constexpr auto name = const_name("object");
 | 
			
		||||
 | 
			
		||||
    static constexpr int value = npy_api::NPY_OBJECT_;
 | 
			
		||||
 | 
			
		||||
    static pybind11::dtype dtype() { return pybind11::dtype(/*typenum*/ value); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define PYBIND11_DECL_CHAR_FMT                                                                    \
 | 
			
		||||
| 
						 | 
				
			
			@ -1401,7 +1409,7 @@ PYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor>
 | 
			
		|||
    oss << '}';
 | 
			
		||||
    auto format_str = oss.str();
 | 
			
		||||
 | 
			
		||||
    // Sanity check: verify that NumPy properly parses our buffer format string
 | 
			
		||||
    // Smoke test: verify that NumPy properly parses our buffer format string
 | 
			
		||||
    auto &api = npy_api::get();
 | 
			
		||||
    auto arr = array(buffer_info(nullptr, itemsize, format_str, 1));
 | 
			
		||||
    if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr())) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1469,7 +1477,7 @@ private:
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
// Extract name, offset and format descriptor for a struct field
 | 
			
		||||
#    define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #    Field)
 | 
			
		||||
#    define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field)
 | 
			
		||||
 | 
			
		||||
// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro
 | 
			
		||||
// (C) William Swanson, Paul Fultz
 | 
			
		||||
| 
						 | 
				
			
			@ -1866,8 +1874,13 @@ private:
 | 
			
		|||
 | 
			
		||||
        auto result = returned_array::create(trivial, shape);
 | 
			
		||||
 | 
			
		||||
        PYBIND11_WARNING_PUSH
 | 
			
		||||
#ifdef PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING
 | 
			
		||||
        PYBIND11_WARNING_DISABLE_CLANG("-Wreturn-std-move")
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        if (size == 0) {
 | 
			
		||||
            return std::move(result);
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Call the function */
 | 
			
		||||
| 
						 | 
				
			
			@ -1878,7 +1891,8 @@ private:
 | 
			
		|||
            apply_trivial(buffers, params, mutable_data, size, i_seq, vi_seq, bi_seq);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return std::move(result);
 | 
			
		||||
        return result;
 | 
			
		||||
        PYBIND11_WARNING_POP
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <size_t... Index, size_t... VIndex, size_t... BIndex>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,6 +84,7 @@ struct op_impl {};
 | 
			
		|||
/// Operator implementation generator
 | 
			
		||||
template <op_id id, op_type ot, typename L, typename R>
 | 
			
		||||
struct op_ {
 | 
			
		||||
    static constexpr bool op_enable_if_hook = true;
 | 
			
		||||
    template <typename Class, typename... Extra>
 | 
			
		||||
    void execute(Class &cl, const Extra &...extra) const {
 | 
			
		||||
        using Base = typename Class::type;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,6 +47,16 @@ public:
 | 
			
		|||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    options &disable_enum_members_docstring() & {
 | 
			
		||||
        global_state().show_enum_members_docstring = false;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    options &enable_enum_members_docstring() & {
 | 
			
		||||
        global_state().show_enum_members_docstring = true;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Getter methods (return the global state):
 | 
			
		||||
 | 
			
		||||
    static bool show_user_defined_docstrings() {
 | 
			
		||||
| 
						 | 
				
			
			@ -55,6 +65,10 @@ public:
 | 
			
		|||
 | 
			
		||||
    static bool show_function_signatures() { return global_state().show_function_signatures; }
 | 
			
		||||
 | 
			
		||||
    static bool show_enum_members_docstring() {
 | 
			
		||||
        return global_state().show_enum_members_docstring;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // This type is not meant to be allocated on the heap.
 | 
			
		||||
    void *operator new(size_t) = delete;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +77,8 @@ private:
 | 
			
		|||
        bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
 | 
			
		||||
        bool show_function_signatures = true;     //< Include auto-generated function signatures
 | 
			
		||||
                                                  //  in docstrings.
 | 
			
		||||
        bool show_enum_members_docstring = true;  //< Include auto-generated member list in enum
 | 
			
		||||
                                                  //  docstrings.
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static state &global_state() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,8 @@
 | 
			
		|||
#    include <cxxabi.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
 | 
			
		||||
/* https://stackoverflow.com/questions/46798456/handling-gccs-noexcept-type-warning
 | 
			
		||||
   This warning is about ABI compatibility, not code health.
 | 
			
		||||
   It is only actually needed in a couple places, but apparently GCC 7 "generates this warning if
 | 
			
		||||
| 
						 | 
				
			
			@ -43,11 +45,10 @@
 | 
			
		|||
   No other GCC version generates this warning.
 | 
			
		||||
 */
 | 
			
		||||
#if defined(__GNUC__) && __GNUC__ == 7
 | 
			
		||||
#    pragma GCC diagnostic push
 | 
			
		||||
#    pragma GCC diagnostic ignored "-Wnoexcept-type"
 | 
			
		||||
PYBIND11_WARNING_DISABLE_GCC("-Wnoexcept-type")
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -83,6 +84,7 @@ public:
 | 
			
		|||
    cpp_function() = default;
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    cpp_function(std::nullptr_t) {}
 | 
			
		||||
    cpp_function(std::nullptr_t, const is_setter &) {}
 | 
			
		||||
 | 
			
		||||
    /// Construct a cpp_function from a vanilla function pointer
 | 
			
		||||
    template <typename Return, typename... Args, typename... Extra>
 | 
			
		||||
| 
						 | 
				
			
			@ -177,22 +179,22 @@ protected:
 | 
			
		|||
        auto *rec = unique_rec.get();
 | 
			
		||||
 | 
			
		||||
        /* Store the capture object directly in the function record if there is enough space */
 | 
			
		||||
        if (PYBIND11_SILENCE_MSVC_C4127(sizeof(capture) <= sizeof(rec->data))) {
 | 
			
		||||
        if (sizeof(capture) <= sizeof(rec->data)) {
 | 
			
		||||
            /* Without these pragmas, GCC warns that there might not be
 | 
			
		||||
               enough space to use the placement new operator. However, the
 | 
			
		||||
               'if' statement above ensures that this is the case. */
 | 
			
		||||
#if defined(__GNUG__) && __GNUC__ >= 6 && !defined(__clang__) && !defined(__INTEL_COMPILER)
 | 
			
		||||
#    pragma GCC diagnostic push
 | 
			
		||||
#    pragma GCC diagnostic ignored "-Wplacement-new"
 | 
			
		||||
            PYBIND11_WARNING_PUSH
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUG__) && __GNUC__ >= 6
 | 
			
		||||
            PYBIND11_WARNING_DISABLE_GCC("-Wplacement-new")
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
            new ((capture *) &rec->data) capture{std::forward<Func>(f)};
 | 
			
		||||
#if defined(__GNUG__) && __GNUC__ >= 6 && !defined(__clang__) && !defined(__INTEL_COMPILER)
 | 
			
		||||
#    pragma GCC diagnostic pop
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(__GNUG__) && !PYBIND11_HAS_STD_LAUNDER && !defined(__INTEL_COMPILER)
 | 
			
		||||
#    pragma GCC diagnostic push
 | 
			
		||||
#    pragma GCC diagnostic ignored "-Wstrict-aliasing"
 | 
			
		||||
 | 
			
		||||
#if !PYBIND11_HAS_STD_LAUNDER
 | 
			
		||||
            PYBIND11_WARNING_DISABLE_GCC("-Wstrict-aliasing")
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
            // UB without std::launder, but without breaking ABI and/or
 | 
			
		||||
            // a significant refactoring it's "impossible" to solve.
 | 
			
		||||
            if (!std::is_trivially_destructible<capture>::value) {
 | 
			
		||||
| 
						 | 
				
			
			@ -202,9 +204,7 @@ protected:
 | 
			
		|||
                    data->~capture();
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
#if defined(__GNUG__) && !PYBIND11_HAS_STD_LAUNDER && !defined(__INTEL_COMPILER)
 | 
			
		||||
#    pragma GCC diagnostic pop
 | 
			
		||||
#endif
 | 
			
		||||
            PYBIND11_WARNING_POP
 | 
			
		||||
        } else {
 | 
			
		||||
            rec->data[0] = new capture{std::forward<Func>(f)};
 | 
			
		||||
            rec->free_data = [](function_record *r) { delete ((capture *) r->data[0]); };
 | 
			
		||||
| 
						 | 
				
			
			@ -245,10 +245,16 @@ protected:
 | 
			
		|||
            using Guard = extract_guard_t<Extra...>;
 | 
			
		||||
 | 
			
		||||
            /* Perform the function call */
 | 
			
		||||
            handle result
 | 
			
		||||
                = cast_out::cast(std::move(args_converter).template call<Return, Guard>(cap->f),
 | 
			
		||||
                                 policy,
 | 
			
		||||
                                 call.parent);
 | 
			
		||||
            handle result;
 | 
			
		||||
            if (call.func.is_setter) {
 | 
			
		||||
                (void) std::move(args_converter).template call<Return, Guard>(cap->f);
 | 
			
		||||
                result = none().release();
 | 
			
		||||
            } else {
 | 
			
		||||
                result = cast_out::cast(
 | 
			
		||||
                    std::move(args_converter).template call<Return, Guard>(cap->f),
 | 
			
		||||
                    policy,
 | 
			
		||||
                    call.parent);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Invoke call policy post-call hook */
 | 
			
		||||
            process_attributes<Extra...>::postcall(call, result);
 | 
			
		||||
| 
						 | 
				
			
			@ -468,13 +474,20 @@ protected:
 | 
			
		|||
        if (rec->sibling) {
 | 
			
		||||
            if (PyCFunction_Check(rec->sibling.ptr())) {
 | 
			
		||||
                auto *self = PyCFunction_GET_SELF(rec->sibling.ptr());
 | 
			
		||||
                capsule rec_capsule = isinstance<capsule>(self) ? reinterpret_borrow<capsule>(self)
 | 
			
		||||
                                                                : capsule(self);
 | 
			
		||||
                chain = (detail::function_record *) rec_capsule;
 | 
			
		||||
                /* Never append a method to an overload chain of a parent class;
 | 
			
		||||
                   instead, hide the parent's overloads in this case */
 | 
			
		||||
                if (!chain->scope.is(rec->scope)) {
 | 
			
		||||
                if (!isinstance<capsule>(self)) {
 | 
			
		||||
                    chain = nullptr;
 | 
			
		||||
                } else {
 | 
			
		||||
                    auto rec_capsule = reinterpret_borrow<capsule>(self);
 | 
			
		||||
                    if (detail::is_function_record_capsule(rec_capsule)) {
 | 
			
		||||
                        chain = rec_capsule.get_pointer<detail::function_record>();
 | 
			
		||||
                        /* Never append a method to an overload chain of a parent class;
 | 
			
		||||
                           instead, hide the parent's overloads in this case */
 | 
			
		||||
                        if (!chain->scope.is(rec->scope)) {
 | 
			
		||||
                            chain = nullptr;
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        chain = nullptr;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // Don't trigger for things like the default __init__, which are wrapper_descriptors
 | 
			
		||||
| 
						 | 
				
			
			@ -495,6 +508,7 @@ protected:
 | 
			
		|||
            rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS;
 | 
			
		||||
 | 
			
		||||
            capsule rec_capsule(unique_rec.release(),
 | 
			
		||||
                                detail::get_function_record_capsule_name(),
 | 
			
		||||
                                [](void *ptr) { destruct((detail::function_record *) ptr); });
 | 
			
		||||
            guarded_strdup.release();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -661,10 +675,13 @@ protected:
 | 
			
		|||
    /// Main dispatch logic for calls to functions bound using pybind11
 | 
			
		||||
    static PyObject *dispatcher(PyObject *self, PyObject *args_in, PyObject *kwargs_in) {
 | 
			
		||||
        using namespace detail;
 | 
			
		||||
        assert(isinstance<capsule>(self));
 | 
			
		||||
 | 
			
		||||
        /* Iterator over the list of potentially admissible overloads */
 | 
			
		||||
        const function_record *overloads = (function_record *) PyCapsule_GetPointer(self, nullptr),
 | 
			
		||||
        const function_record *overloads = reinterpret_cast<function_record *>(
 | 
			
		||||
                                  PyCapsule_GetPointer(self, get_function_record_capsule_name())),
 | 
			
		||||
                              *it = overloads;
 | 
			
		||||
        assert(overloads != nullptr);
 | 
			
		||||
 | 
			
		||||
        /* Need to know how many arguments + keyword arguments there are to pick the right
 | 
			
		||||
           overload */
 | 
			
		||||
| 
						 | 
				
			
			@ -1416,9 +1433,9 @@ template <typename T, enable_if_t<has_operator_delete<T>::value, int> = 0>
 | 
			
		|||
void call_operator_delete(T *p, size_t, size_t) {
 | 
			
		||||
    T::operator delete(p);
 | 
			
		||||
}
 | 
			
		||||
template <
 | 
			
		||||
    typename T,
 | 
			
		||||
    enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> = 0>
 | 
			
		||||
template <typename T,
 | 
			
		||||
          enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int>
 | 
			
		||||
          = 0>
 | 
			
		||||
void call_operator_delete(T *p, size_t s, size_t) {
 | 
			
		||||
    T::operator delete(p, s);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1578,14 +1595,14 @@ public:
 | 
			
		|||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
 | 
			
		||||
    class_ &def(const detail::op_<id, ot, L, R> &op, const Extra &...extra) {
 | 
			
		||||
    template <typename T, typename... Extra, detail::enable_if_t<T::op_enable_if_hook, int> = 0>
 | 
			
		||||
    class_ &def(const T &op, const Extra &...extra) {
 | 
			
		||||
        op.execute(*this, extra...);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
 | 
			
		||||
    class_ &def_cast(const detail::op_<id, ot, L, R> &op, const Extra &...extra) {
 | 
			
		||||
    template <typename T, typename... Extra, detail::enable_if_t<T::op_enable_if_hook, int> = 0>
 | 
			
		||||
    class_ &def_cast(const T &op, const Extra &...extra) {
 | 
			
		||||
        op.execute_cast(*this, extra...);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1719,7 +1736,8 @@ public:
 | 
			
		|||
    template <typename Getter, typename Setter, typename... Extra>
 | 
			
		||||
    class_ &
 | 
			
		||||
    def_property(const char *name, const Getter &fget, const Setter &fset, const Extra &...extra) {
 | 
			
		||||
        return def_property(name, fget, cpp_function(method_adaptor<type>(fset)), extra...);
 | 
			
		||||
        return def_property(
 | 
			
		||||
            name, fget, cpp_function(method_adaptor<type>(fset), is_setter()), extra...);
 | 
			
		||||
    }
 | 
			
		||||
    template <typename Getter, typename... Extra>
 | 
			
		||||
    class_ &def_property(const char *name,
 | 
			
		||||
| 
						 | 
				
			
			@ -1830,8 +1848,7 @@ private:
 | 
			
		|||
        if (holder_ptr) {
 | 
			
		||||
            init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>());
 | 
			
		||||
            v_h.set_holder_constructed();
 | 
			
		||||
        } else if (PYBIND11_SILENCE_MSVC_C4127(detail::always_construct_holder<holder_type>::value)
 | 
			
		||||
                   || inst->owned) {
 | 
			
		||||
        } else if (detail::always_construct_holder<holder_type>::value || inst->owned) {
 | 
			
		||||
            new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());
 | 
			
		||||
            v_h.set_holder_constructed();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1871,9 +1888,22 @@ private:
 | 
			
		|||
 | 
			
		||||
    static detail::function_record *get_function_record(handle h) {
 | 
			
		||||
        h = detail::get_function(h);
 | 
			
		||||
        return h ? (detail::function_record *) reinterpret_borrow<capsule>(
 | 
			
		||||
                   PyCFunction_GET_SELF(h.ptr()))
 | 
			
		||||
                 : nullptr;
 | 
			
		||||
        if (!h) {
 | 
			
		||||
            return nullptr;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        handle func_self = PyCFunction_GET_SELF(h.ptr());
 | 
			
		||||
        if (!func_self) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
        if (!isinstance<capsule>(func_self)) {
 | 
			
		||||
            return nullptr;
 | 
			
		||||
        }
 | 
			
		||||
        auto cap = reinterpret_borrow<capsule>(func_self);
 | 
			
		||||
        if (!detail::is_function_record_capsule(cap)) {
 | 
			
		||||
            return nullptr;
 | 
			
		||||
        }
 | 
			
		||||
        return cap.get_pointer<detail::function_record>();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1950,29 +1980,35 @@ struct enum_base {
 | 
			
		|||
            name("name"),
 | 
			
		||||
            is_method(m_base));
 | 
			
		||||
 | 
			
		||||
        m_base.attr("__doc__") = static_property(
 | 
			
		||||
            cpp_function(
 | 
			
		||||
                [](handle arg) -> std::string {
 | 
			
		||||
                    std::string docstring;
 | 
			
		||||
                    dict entries = arg.attr("__entries");
 | 
			
		||||
                    if (((PyTypeObject *) arg.ptr())->tp_doc) {
 | 
			
		||||
                        docstring += std::string(((PyTypeObject *) arg.ptr())->tp_doc) + "\n\n";
 | 
			
		||||
                    }
 | 
			
		||||
                    docstring += "Members:";
 | 
			
		||||
                    for (auto kv : entries) {
 | 
			
		||||
                        auto key = std::string(pybind11::str(kv.first));
 | 
			
		||||
                        auto comment = kv.second[int_(1)];
 | 
			
		||||
                        docstring += "\n\n  " + key;
 | 
			
		||||
                        if (!comment.is_none()) {
 | 
			
		||||
                            docstring += " : " + (std::string) pybind11::str(comment);
 | 
			
		||||
        if (options::show_enum_members_docstring()) {
 | 
			
		||||
            m_base.attr("__doc__") = static_property(
 | 
			
		||||
                cpp_function(
 | 
			
		||||
                    [](handle arg) -> std::string {
 | 
			
		||||
                        std::string docstring;
 | 
			
		||||
                        dict entries = arg.attr("__entries");
 | 
			
		||||
                        if (((PyTypeObject *) arg.ptr())->tp_doc) {
 | 
			
		||||
                            docstring += std::string(
 | 
			
		||||
                                reinterpret_cast<PyTypeObject *>(arg.ptr())->tp_doc);
 | 
			
		||||
                            docstring += "\n\n";
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    return docstring;
 | 
			
		||||
                },
 | 
			
		||||
                name("__doc__")),
 | 
			
		||||
            none(),
 | 
			
		||||
            none(),
 | 
			
		||||
            "");
 | 
			
		||||
                        docstring += "Members:";
 | 
			
		||||
                        for (auto kv : entries) {
 | 
			
		||||
                            auto key = std::string(pybind11::str(kv.first));
 | 
			
		||||
                            auto comment = kv.second[int_(1)];
 | 
			
		||||
                            docstring += "\n\n  ";
 | 
			
		||||
                            docstring += key;
 | 
			
		||||
                            if (!comment.is_none()) {
 | 
			
		||||
                                docstring += " : ";
 | 
			
		||||
                                docstring += pybind11::str(comment).cast<std::string>();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        return docstring;
 | 
			
		||||
                    },
 | 
			
		||||
                    name("__doc__")),
 | 
			
		||||
                none(),
 | 
			
		||||
                none(),
 | 
			
		||||
                "");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        m_base.attr("__members__") = static_property(cpp_function(
 | 
			
		||||
                                                         [](handle arg) -> dict {
 | 
			
		||||
| 
						 | 
				
			
			@ -2073,7 +2109,7 @@ struct enum_base {
 | 
			
		|||
                              + "\" already exists!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        entries[name] = std::make_pair(value, doc);
 | 
			
		||||
        entries[name] = pybind11::make_tuple(value, doc);
 | 
			
		||||
        m_base.attr(std::move(name)) = std::move(value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2333,7 +2369,7 @@ template <typename Access,
 | 
			
		|||
          typename Sentinel,
 | 
			
		||||
          typename ValueType,
 | 
			
		||||
          typename... Extra>
 | 
			
		||||
iterator make_iterator_impl(Iterator &&first, Sentinel &&last, Extra &&...extra) {
 | 
			
		||||
iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
 | 
			
		||||
    using state = detail::iterator_state<Access, Policy, Iterator, Sentinel, ValueType, Extra...>;
 | 
			
		||||
    // TODO: state captures only the types of Extra, not the values
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2359,7 +2395,7 @@ iterator make_iterator_impl(Iterator &&first, Sentinel &&last, Extra &&...extra)
 | 
			
		|||
                Policy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return cast(state{std::forward<Iterator>(first), std::forward<Sentinel>(last), true});
 | 
			
		||||
    return cast(state{first, last, true});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
| 
						 | 
				
			
			@ -2370,15 +2406,13 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
 | 
			
		|||
          typename Sentinel,
 | 
			
		||||
          typename ValueType = typename detail::iterator_access<Iterator>::result_type,
 | 
			
		||||
          typename... Extra>
 | 
			
		||||
iterator make_iterator(Iterator &&first, Sentinel &&last, Extra &&...extra) {
 | 
			
		||||
iterator make_iterator(Iterator first, Sentinel last, Extra &&...extra) {
 | 
			
		||||
    return detail::make_iterator_impl<detail::iterator_access<Iterator>,
 | 
			
		||||
                                      Policy,
 | 
			
		||||
                                      Iterator,
 | 
			
		||||
                                      Sentinel,
 | 
			
		||||
                                      ValueType,
 | 
			
		||||
                                      Extra...>(std::forward<Iterator>(first),
 | 
			
		||||
                                                std::forward<Sentinel>(last),
 | 
			
		||||
                                                std::forward<Extra>(extra)...);
 | 
			
		||||
                                      Extra...>(first, last, std::forward<Extra>(extra)...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a
 | 
			
		||||
| 
						 | 
				
			
			@ -2388,15 +2422,13 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
 | 
			
		|||
          typename Sentinel,
 | 
			
		||||
          typename KeyType = typename detail::iterator_key_access<Iterator>::result_type,
 | 
			
		||||
          typename... Extra>
 | 
			
		||||
iterator make_key_iterator(Iterator &&first, Sentinel &&last, Extra &&...extra) {
 | 
			
		||||
iterator make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) {
 | 
			
		||||
    return detail::make_iterator_impl<detail::iterator_key_access<Iterator>,
 | 
			
		||||
                                      Policy,
 | 
			
		||||
                                      Iterator,
 | 
			
		||||
                                      Sentinel,
 | 
			
		||||
                                      KeyType,
 | 
			
		||||
                                      Extra...>(std::forward<Iterator>(first),
 | 
			
		||||
                                                std::forward<Sentinel>(last),
 | 
			
		||||
                                                std::forward<Extra>(extra)...);
 | 
			
		||||
                                      Extra...>(first, last, std::forward<Extra>(extra)...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Makes a python iterator over the values (`.second`) of a iterator over pairs from a
 | 
			
		||||
| 
						 | 
				
			
			@ -2406,15 +2438,13 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
 | 
			
		|||
          typename Sentinel,
 | 
			
		||||
          typename ValueType = typename detail::iterator_value_access<Iterator>::result_type,
 | 
			
		||||
          typename... Extra>
 | 
			
		||||
iterator make_value_iterator(Iterator &&first, Sentinel &&last, Extra &&...extra) {
 | 
			
		||||
iterator make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) {
 | 
			
		||||
    return detail::make_iterator_impl<detail::iterator_value_access<Iterator>,
 | 
			
		||||
                                      Policy,
 | 
			
		||||
                                      Iterator,
 | 
			
		||||
                                      Sentinel,
 | 
			
		||||
                                      ValueType,
 | 
			
		||||
                                      Extra...>(std::forward<Iterator>(first),
 | 
			
		||||
                                                std::forward<Sentinel>(last),
 | 
			
		||||
                                                std::forward<Extra>(extra)...);
 | 
			
		||||
                                      Extra...>(first, last, std::forward<Extra>(extra)...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Makes an iterator over values of an stl container or other container supporting
 | 
			
		||||
| 
						 | 
				
			
			@ -2858,7 +2888,3 @@ inline function get_overload(const T *this_ptr, const char *name) {
 | 
			
		|||
    PYBIND11_OVERRIDE_PURE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__);
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) && __GNUC__ == 7
 | 
			
		||||
#    pragma GCC diagnostic pop // -Wnoexcept-type
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,6 +33,8 @@
 | 
			
		|||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
 | 
			
		||||
 | 
			
		||||
/* A few forward declarations */
 | 
			
		||||
class handle;
 | 
			
		||||
class object;
 | 
			
		||||
| 
						 | 
				
			
			@ -155,23 +157,23 @@ public:
 | 
			
		|||
    object operator-() const;
 | 
			
		||||
    object operator~() const;
 | 
			
		||||
    object operator+(object_api const &other) const;
 | 
			
		||||
    object operator+=(object_api const &other) const;
 | 
			
		||||
    object operator+=(object_api const &other);
 | 
			
		||||
    object operator-(object_api const &other) const;
 | 
			
		||||
    object operator-=(object_api const &other) const;
 | 
			
		||||
    object operator-=(object_api const &other);
 | 
			
		||||
    object operator*(object_api const &other) const;
 | 
			
		||||
    object operator*=(object_api const &other) const;
 | 
			
		||||
    object operator*=(object_api const &other);
 | 
			
		||||
    object operator/(object_api const &other) const;
 | 
			
		||||
    object operator/=(object_api const &other) const;
 | 
			
		||||
    object operator/=(object_api const &other);
 | 
			
		||||
    object operator|(object_api const &other) const;
 | 
			
		||||
    object operator|=(object_api const &other) const;
 | 
			
		||||
    object operator|=(object_api const &other);
 | 
			
		||||
    object operator&(object_api const &other) const;
 | 
			
		||||
    object operator&=(object_api const &other) const;
 | 
			
		||||
    object operator&=(object_api const &other);
 | 
			
		||||
    object operator^(object_api const &other) const;
 | 
			
		||||
    object operator^=(object_api const &other) const;
 | 
			
		||||
    object operator^=(object_api const &other);
 | 
			
		||||
    object operator<<(object_api const &other) const;
 | 
			
		||||
    object operator<<=(object_api const &other) const;
 | 
			
		||||
    object operator<<=(object_api const &other);
 | 
			
		||||
    object operator>>(object_api const &other) const;
 | 
			
		||||
    object operator>>=(object_api const &other) const;
 | 
			
		||||
    object operator>>=(object_api const &other);
 | 
			
		||||
 | 
			
		||||
    PYBIND11_DEPRECATED("Use py::str(obj) instead")
 | 
			
		||||
    pybind11::str str() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -230,7 +232,8 @@ public:
 | 
			
		|||
        detail::enable_if_t<detail::all_of<detail::none_of<std::is_base_of<handle, T>,
 | 
			
		||||
                                                           detail::is_pyobj_ptr_or_nullptr_t<T>>,
 | 
			
		||||
                                           std::is_convertible<T, PyObject *>>::value,
 | 
			
		||||
                            int> = 0>
 | 
			
		||||
                            int>
 | 
			
		||||
        = 0>
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    handle(T &obj) : m_ptr(obj) {}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -246,6 +249,11 @@ public:
 | 
			
		|||
    const handle &inc_ref() const & {
 | 
			
		||||
#ifdef PYBIND11_HANDLE_REF_DEBUG
 | 
			
		||||
        inc_ref_counter(1);
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF
 | 
			
		||||
        if (m_ptr != nullptr && !PyGILState_Check()) {
 | 
			
		||||
            throw_gilstate_error("pybind11::handle::inc_ref()");
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
        Py_XINCREF(m_ptr);
 | 
			
		||||
        return *this;
 | 
			
		||||
| 
						 | 
				
			
			@ -257,6 +265,11 @@ public:
 | 
			
		|||
        this function automatically. Returns a reference to itself.
 | 
			
		||||
    \endrst */
 | 
			
		||||
    const handle &dec_ref() const & {
 | 
			
		||||
#ifdef PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF
 | 
			
		||||
        if (m_ptr != nullptr && !PyGILState_Check()) {
 | 
			
		||||
            throw_gilstate_error("pybind11::handle::dec_ref()");
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
        Py_XDECREF(m_ptr);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -283,8 +296,33 @@ public:
 | 
			
		|||
protected:
 | 
			
		||||
    PyObject *m_ptr = nullptr;
 | 
			
		||||
 | 
			
		||||
#ifdef PYBIND11_HANDLE_REF_DEBUG
 | 
			
		||||
private:
 | 
			
		||||
#ifdef PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF
 | 
			
		||||
    void throw_gilstate_error(const std::string &function_name) const {
 | 
			
		||||
        fprintf(
 | 
			
		||||
            stderr,
 | 
			
		||||
            "%s is being called while the GIL is either not held or invalid. Please see "
 | 
			
		||||
            "https://pybind11.readthedocs.io/en/stable/advanced/"
 | 
			
		||||
            "misc.html#common-sources-of-global-interpreter-lock-errors for debugging advice.\n"
 | 
			
		||||
            "If you are convinced there is no bug in your code, you can #define "
 | 
			
		||||
            "PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF"
 | 
			
		||||
            "to disable this check. In that case you have to ensure this #define is consistently "
 | 
			
		||||
            "used for all translation units linked into a given pybind11 extension, otherwise "
 | 
			
		||||
            "there will be ODR violations.",
 | 
			
		||||
            function_name.c_str());
 | 
			
		||||
        fflush(stderr);
 | 
			
		||||
        if (Py_TYPE(m_ptr)->tp_name != nullptr) {
 | 
			
		||||
            fprintf(stderr,
 | 
			
		||||
                    "The failing %s call was triggered on a %s object.\n",
 | 
			
		||||
                    function_name.c_str(),
 | 
			
		||||
                    Py_TYPE(m_ptr)->tp_name);
 | 
			
		||||
            fflush(stderr);
 | 
			
		||||
        }
 | 
			
		||||
        throw std::runtime_error(function_name + " PyGILState_Check() failure.");
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef PYBIND11_HANDLE_REF_DEBUG
 | 
			
		||||
    static std::size_t inc_ref_counter(std::size_t add) {
 | 
			
		||||
        thread_local std::size_t counter = 0;
 | 
			
		||||
        counter += add;
 | 
			
		||||
| 
						 | 
				
			
			@ -334,12 +372,15 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    object &operator=(const object &other) {
 | 
			
		||||
        other.inc_ref();
 | 
			
		||||
        // Use temporary variable to ensure `*this` remains valid while
 | 
			
		||||
        // `Py_XDECREF` executes, in case `*this` is accessible from Python.
 | 
			
		||||
        handle temp(m_ptr);
 | 
			
		||||
        m_ptr = other.m_ptr;
 | 
			
		||||
        temp.dec_ref();
 | 
			
		||||
        // Skip inc_ref and dec_ref if both objects are the same
 | 
			
		||||
        if (!this->is(other)) {
 | 
			
		||||
            other.inc_ref();
 | 
			
		||||
            // Use temporary variable to ensure `*this` remains valid while
 | 
			
		||||
            // `Py_XDECREF` executes, in case `*this` is accessible from Python.
 | 
			
		||||
            handle temp(m_ptr);
 | 
			
		||||
            m_ptr = other.m_ptr;
 | 
			
		||||
            temp.dec_ref();
 | 
			
		||||
        }
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -353,6 +394,20 @@ public:
 | 
			
		|||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#define PYBIND11_INPLACE_OP(iop)                                                                  \
 | 
			
		||||
    object iop(object_api const &other) { return operator=(handle::iop(other)); }
 | 
			
		||||
 | 
			
		||||
    PYBIND11_INPLACE_OP(operator+=)
 | 
			
		||||
    PYBIND11_INPLACE_OP(operator-=)
 | 
			
		||||
    PYBIND11_INPLACE_OP(operator*=)
 | 
			
		||||
    PYBIND11_INPLACE_OP(operator/=)
 | 
			
		||||
    PYBIND11_INPLACE_OP(operator|=)
 | 
			
		||||
    PYBIND11_INPLACE_OP(operator&=)
 | 
			
		||||
    PYBIND11_INPLACE_OP(operator^=)
 | 
			
		||||
    PYBIND11_INPLACE_OP(operator<<=)
 | 
			
		||||
    PYBIND11_INPLACE_OP(operator>>=)
 | 
			
		||||
#undef PYBIND11_INPLACE_OP
 | 
			
		||||
 | 
			
		||||
    // Calling cast() on an object lvalue just copies (via handle::cast)
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    T cast() const &;
 | 
			
		||||
| 
						 | 
				
			
			@ -413,7 +468,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		|||
 | 
			
		||||
// Equivalent to obj.__class__.__name__ (or obj.__name__ if obj is a class).
 | 
			
		||||
inline const char *obj_class_name(PyObject *obj) {
 | 
			
		||||
    if (Py_TYPE(obj) == &PyType_Type) {
 | 
			
		||||
    if (PyType_Check(obj)) {
 | 
			
		||||
        return reinterpret_cast<PyTypeObject *>(obj)->tp_name;
 | 
			
		||||
    }
 | 
			
		||||
    return Py_TYPE(obj)->tp_name;
 | 
			
		||||
| 
						 | 
				
			
			@ -421,13 +476,24 @@ inline const char *obj_class_name(PyObject *obj) {
 | 
			
		|||
 | 
			
		||||
std::string error_string();
 | 
			
		||||
 | 
			
		||||
// The code in this struct is very unusual, to minimize the chances of
 | 
			
		||||
// masking bugs (elsewhere) by errors during the error handling (here).
 | 
			
		||||
// This is meant to be a lifeline for troubleshooting long-running processes
 | 
			
		||||
// that crash under conditions that are virtually impossible to reproduce.
 | 
			
		||||
// Low-level implementation alternatives are preferred to higher-level ones
 | 
			
		||||
// that might raise cascading exceptions. Last-ditch-kind-of attempts are made
 | 
			
		||||
// to report as much of the original error as possible, even if there are
 | 
			
		||||
// secondary issues obtaining some of the details.
 | 
			
		||||
struct error_fetch_and_normalize {
 | 
			
		||||
    // Immediate normalization is long-established behavior (starting with
 | 
			
		||||
    // https://github.com/pybind/pybind11/commit/135ba8deafb8bf64a15b24d1513899eb600e2011
 | 
			
		||||
    // from Sep 2016) and safest. Normalization could be deferred, but this could mask
 | 
			
		||||
    // errors elsewhere, the performance gain is very minor in typical situations
 | 
			
		||||
    // (usually the dominant bottleneck is EH unwinding), and the implementation here
 | 
			
		||||
    // would be more complex.
 | 
			
		||||
    // This comment only applies to Python <= 3.11:
 | 
			
		||||
    //     Immediate normalization is long-established behavior (starting with
 | 
			
		||||
    //     https://github.com/pybind/pybind11/commit/135ba8deafb8bf64a15b24d1513899eb600e2011
 | 
			
		||||
    //     from Sep 2016) and safest. Normalization could be deferred, but this could mask
 | 
			
		||||
    //     errors elsewhere, the performance gain is very minor in typical situations
 | 
			
		||||
    //     (usually the dominant bottleneck is EH unwinding), and the implementation here
 | 
			
		||||
    //     would be more complex.
 | 
			
		||||
    // Starting with Python 3.12, PyErr_Fetch() normalizes exceptions immediately.
 | 
			
		||||
    // Any errors during normalization are tracked under __notes__.
 | 
			
		||||
    explicit error_fetch_and_normalize(const char *called) {
 | 
			
		||||
        PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
 | 
			
		||||
        if (!m_type) {
 | 
			
		||||
| 
						 | 
				
			
			@ -442,6 +508,14 @@ struct error_fetch_and_normalize {
 | 
			
		|||
                            "of the original active exception type.");
 | 
			
		||||
        }
 | 
			
		||||
        m_lazy_error_string = exc_type_name_orig;
 | 
			
		||||
#if PY_VERSION_HEX >= 0x030C0000
 | 
			
		||||
        // The presence of __notes__ is likely due to exception normalization
 | 
			
		||||
        // errors, although that is not necessarily true, therefore insert a
 | 
			
		||||
        // hint only:
 | 
			
		||||
        if (PyObject_HasAttrString(m_value.ptr(), "__notes__")) {
 | 
			
		||||
            m_lazy_error_string += "[WITH __notes__]";
 | 
			
		||||
        }
 | 
			
		||||
#else
 | 
			
		||||
        // PyErr_NormalizeException() may change the exception type if there are cascading
 | 
			
		||||
        // failures. This can potentially be extremely confusing.
 | 
			
		||||
        PyErr_NormalizeException(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
 | 
			
		||||
| 
						 | 
				
			
			@ -451,11 +525,17 @@ struct error_fetch_and_normalize {
 | 
			
		|||
                            "active exception.");
 | 
			
		||||
        }
 | 
			
		||||
        const char *exc_type_name_norm = detail::obj_class_name(m_type.ptr());
 | 
			
		||||
        if (exc_type_name_orig == nullptr) {
 | 
			
		||||
        if (exc_type_name_norm == nullptr) {
 | 
			
		||||
            pybind11_fail("Internal error: " + std::string(called)
 | 
			
		||||
                          + " failed to obtain the name "
 | 
			
		||||
                            "of the normalized active exception type.");
 | 
			
		||||
        }
 | 
			
		||||
#    if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x07030a00
 | 
			
		||||
        // This behavior runs the risk of masking errors in the error handling, but avoids a
 | 
			
		||||
        // conflict with PyPy, which relies on the normalization here to change OSError to
 | 
			
		||||
        // FileNotFoundError (https://github.com/pybind/pybind11/issues/4075).
 | 
			
		||||
        m_lazy_error_string = exc_type_name_norm;
 | 
			
		||||
#    else
 | 
			
		||||
        if (exc_type_name_norm != m_lazy_error_string) {
 | 
			
		||||
            std::string msg = std::string(called)
 | 
			
		||||
                              + ": MISMATCH of original and normalized "
 | 
			
		||||
| 
						 | 
				
			
			@ -467,6 +547,8 @@ struct error_fetch_and_normalize {
 | 
			
		|||
            msg += ": " + format_value_and_trace();
 | 
			
		||||
            pybind11_fail(msg);
 | 
			
		||||
        }
 | 
			
		||||
#    endif
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    error_fetch_and_normalize(const error_fetch_and_normalize &) = delete;
 | 
			
		||||
| 
						 | 
				
			
			@ -477,12 +559,64 @@ struct error_fetch_and_normalize {
 | 
			
		|||
        std::string message_error_string;
 | 
			
		||||
        if (m_value) {
 | 
			
		||||
            auto value_str = reinterpret_steal<object>(PyObject_Str(m_value.ptr()));
 | 
			
		||||
            constexpr const char *message_unavailable_exc
 | 
			
		||||
                = "<MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>";
 | 
			
		||||
            if (!value_str) {
 | 
			
		||||
                message_error_string = detail::error_string();
 | 
			
		||||
                result = "<MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>";
 | 
			
		||||
                result = message_unavailable_exc;
 | 
			
		||||
            } else {
 | 
			
		||||
                result = value_str.cast<std::string>();
 | 
			
		||||
                // Not using `value_str.cast<std::string>()`, to not potentially throw a secondary
 | 
			
		||||
                // error_already_set that will then result in process termination (#4288).
 | 
			
		||||
                auto value_bytes = reinterpret_steal<object>(
 | 
			
		||||
                    PyUnicode_AsEncodedString(value_str.ptr(), "utf-8", "backslashreplace"));
 | 
			
		||||
                if (!value_bytes) {
 | 
			
		||||
                    message_error_string = detail::error_string();
 | 
			
		||||
                    result = message_unavailable_exc;
 | 
			
		||||
                } else {
 | 
			
		||||
                    char *buffer = nullptr;
 | 
			
		||||
                    Py_ssize_t length = 0;
 | 
			
		||||
                    if (PyBytes_AsStringAndSize(value_bytes.ptr(), &buffer, &length) == -1) {
 | 
			
		||||
                        message_error_string = detail::error_string();
 | 
			
		||||
                        result = message_unavailable_exc;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        result = std::string(buffer, static_cast<std::size_t>(length));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
#if PY_VERSION_HEX >= 0x030B0000
 | 
			
		||||
            auto notes
 | 
			
		||||
                = reinterpret_steal<object>(PyObject_GetAttrString(m_value.ptr(), "__notes__"));
 | 
			
		||||
            if (!notes) {
 | 
			
		||||
                PyErr_Clear(); // No notes is good news.
 | 
			
		||||
            } else {
 | 
			
		||||
                auto len_notes = PyList_Size(notes.ptr());
 | 
			
		||||
                if (len_notes < 0) {
 | 
			
		||||
                    result += "\nFAILURE obtaining len(__notes__): " + detail::error_string();
 | 
			
		||||
                } else {
 | 
			
		||||
                    result += "\n__notes__ (len=" + std::to_string(len_notes) + "):";
 | 
			
		||||
                    for (ssize_t i = 0; i < len_notes; i++) {
 | 
			
		||||
                        PyObject *note = PyList_GET_ITEM(notes.ptr(), i);
 | 
			
		||||
                        auto note_bytes = reinterpret_steal<object>(
 | 
			
		||||
                            PyUnicode_AsEncodedString(note, "utf-8", "backslashreplace"));
 | 
			
		||||
                        if (!note_bytes) {
 | 
			
		||||
                            result += "\nFAILURE obtaining __notes__[" + std::to_string(i)
 | 
			
		||||
                                      + "]: " + detail::error_string();
 | 
			
		||||
                        } else {
 | 
			
		||||
                            char *buffer = nullptr;
 | 
			
		||||
                            Py_ssize_t length = 0;
 | 
			
		||||
                            if (PyBytes_AsStringAndSize(note_bytes.ptr(), &buffer, &length)
 | 
			
		||||
                                == -1) {
 | 
			
		||||
                                result += "\nFAILURE formatting __notes__[" + std::to_string(i)
 | 
			
		||||
                                          + "]: " + detail::error_string();
 | 
			
		||||
                            } else {
 | 
			
		||||
                                result += '\n';
 | 
			
		||||
                                result += std::string(buffer, static_cast<std::size_t>(length));
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
#endif
 | 
			
		||||
        } else {
 | 
			
		||||
            result = "<MESSAGE UNAVAILABLE>";
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -581,12 +715,6 @@ inline std::string error_string() {
 | 
			
		|||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#    pragma warning(push)
 | 
			
		||||
#    pragma warning(disable : 4275 4251)
 | 
			
		||||
//     warning C4275: An exported class was derived from a class that wasn't exported.
 | 
			
		||||
//     Can be ignored when derived from a STL class.
 | 
			
		||||
#endif
 | 
			
		||||
/// Fetch and hold an error which was already set in Python.  An instance of this is typically
 | 
			
		||||
/// thrown to propagate python-side errors back through C++ which can either be caught manually or
 | 
			
		||||
/// else falls back to the function dispatcher (which then raises the captured error back to
 | 
			
		||||
| 
						 | 
				
			
			@ -646,9 +774,6 @@ private:
 | 
			
		|||
    ///          crashes (undefined behavior) if the Python interpreter is finalizing.
 | 
			
		||||
    static void m_fetched_error_deleter(detail::error_fetch_and_normalize *raw_ptr);
 | 
			
		||||
};
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#    pragma warning(pop)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/// Replaces the current Python error indicator with the chosen error, performing a
 | 
			
		||||
/// 'raise from' to indicate that the chosen error was caused by the original error.
 | 
			
		||||
| 
						 | 
				
			
			@ -851,10 +976,8 @@ object object_or_cast(T &&o);
 | 
			
		|||
// Match a PyObject*, which we want to convert directly to handle via its converting constructor
 | 
			
		||||
inline handle object_or_cast(PyObject *ptr) { return ptr; }
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && _MSC_VER < 1920
 | 
			
		||||
#    pragma warning(push)
 | 
			
		||||
#    pragma warning(disable : 4522) // warning C4522: multiple assignment operators specified
 | 
			
		||||
#endif
 | 
			
		||||
PYBIND11_WARNING_PUSH
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4522) // warning C4522: multiple assignment operators specified
 | 
			
		||||
template <typename Policy>
 | 
			
		||||
class accessor : public object_api<accessor<Policy>> {
 | 
			
		||||
    using key_type = typename Policy::key_type;
 | 
			
		||||
| 
						 | 
				
			
			@ -918,9 +1041,7 @@ private:
 | 
			
		|||
    key_type key;
 | 
			
		||||
    mutable object cache;
 | 
			
		||||
};
 | 
			
		||||
#if defined(_MSC_VER) && _MSC_VER < 1920
 | 
			
		||||
#    pragma warning(pop)
 | 
			
		||||
#endif
 | 
			
		||||
PYBIND11_WARNING_POP
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(accessor_policies)
 | 
			
		||||
struct obj_attr {
 | 
			
		||||
| 
						 | 
				
			
			@ -1266,7 +1387,7 @@ public:
 | 
			
		|||
 | 
			
		||||
#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun)                           \
 | 
			
		||||
    PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun)                                       \
 | 
			
		||||
    Name() : Parent() {}
 | 
			
		||||
    Name() = default;
 | 
			
		||||
 | 
			
		||||
#define PYBIND11_OBJECT_CHECK_FAILED(Name, o_ptr)                                                 \
 | 
			
		||||
    ::pybind11::type_error("Object of type '"                                                     \
 | 
			
		||||
| 
						 | 
				
			
			@ -1289,7 +1410,7 @@ public:
 | 
			
		|||
 | 
			
		||||
#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun)                                           \
 | 
			
		||||
    PYBIND11_OBJECT(Name, Parent, CheckFun)                                                       \
 | 
			
		||||
    Name() : Parent() {}
 | 
			
		||||
    Name() = default;
 | 
			
		||||
 | 
			
		||||
/// \addtogroup pytypes
 | 
			
		||||
/// @{
 | 
			
		||||
| 
						 | 
				
			
			@ -1358,7 +1479,7 @@ public:
 | 
			
		|||
private:
 | 
			
		||||
    void advance() {
 | 
			
		||||
        value = reinterpret_steal<object>(PyIter_Next(m_ptr));
 | 
			
		||||
        if (PyErr_Occurred()) {
 | 
			
		||||
        if (value.ptr() == nullptr && PyErr_Occurred()) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1408,6 +1529,9 @@ public:
 | 
			
		|||
    str(const char *c, const SzType &n)
 | 
			
		||||
        : object(PyUnicode_FromStringAndSize(c, ssize_t_cast(n)), stolen_t{}) {
 | 
			
		||||
        if (!m_ptr) {
 | 
			
		||||
            if (PyErr_Occurred()) {
 | 
			
		||||
                throw error_already_set();
 | 
			
		||||
            }
 | 
			
		||||
            pybind11_fail("Could not allocate string object!");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1417,6 +1541,9 @@ public:
 | 
			
		|||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    str(const char *c = "") : object(PyUnicode_FromString(c), stolen_t{}) {
 | 
			
		||||
        if (!m_ptr) {
 | 
			
		||||
            if (PyErr_Occurred()) {
 | 
			
		||||
                throw error_already_set();
 | 
			
		||||
            }
 | 
			
		||||
            pybind11_fail("Could not allocate string object!");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1574,6 +1701,9 @@ inline str::str(const bytes &b) {
 | 
			
		|||
    }
 | 
			
		||||
    auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, length));
 | 
			
		||||
    if (!obj) {
 | 
			
		||||
        if (PyErr_Occurred()) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
        pybind11_fail("Could not allocate string object!");
 | 
			
		||||
    }
 | 
			
		||||
    m_ptr = obj.release().ptr();
 | 
			
		||||
| 
						 | 
				
			
			@ -1651,7 +1781,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		|||
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
 | 
			
		||||
template <typename Unsigned>
 | 
			
		||||
Unsigned as_unsigned(PyObject *o) {
 | 
			
		||||
    if (PYBIND11_SILENCE_MSVC_C4127(sizeof(Unsigned) <= sizeof(unsigned long))) {
 | 
			
		||||
    if (sizeof(Unsigned) <= sizeof(unsigned long)) {
 | 
			
		||||
        unsigned long v = PyLong_AsUnsignedLong(o);
 | 
			
		||||
        return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1668,7 +1798,7 @@ public:
 | 
			
		|||
    template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0>
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor)
 | 
			
		||||
    int_(T value) {
 | 
			
		||||
        if (PYBIND11_SILENCE_MSVC_C4127(sizeof(T) <= sizeof(long))) {
 | 
			
		||||
        if (sizeof(T) <= sizeof(long)) {
 | 
			
		||||
            if (std::is_signed<T>::value) {
 | 
			
		||||
                m_ptr = PyLong_FromLong((long) value);
 | 
			
		||||
            } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1785,43 +1915,28 @@ public:
 | 
			
		|||
 | 
			
		||||
    explicit capsule(const void *value,
 | 
			
		||||
                     const char *name = nullptr,
 | 
			
		||||
                     void (*destructor)(PyObject *) = nullptr)
 | 
			
		||||
                     PyCapsule_Destructor destructor = nullptr)
 | 
			
		||||
        : object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
 | 
			
		||||
        if (!m_ptr) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input")
 | 
			
		||||
    capsule(const void *value, void (*destruct)(PyObject *))
 | 
			
		||||
        : object(PyCapsule_New(const_cast<void *>(value), nullptr, destruct), stolen_t{}) {
 | 
			
		||||
    PYBIND11_DEPRECATED("Please use the ctor with value, name, destructor args")
 | 
			
		||||
    capsule(const void *value, PyCapsule_Destructor destructor)
 | 
			
		||||
        : object(PyCapsule_New(const_cast<void *>(value), nullptr, destructor), stolen_t{}) {
 | 
			
		||||
        if (!m_ptr) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Capsule name is nullptr.
 | 
			
		||||
    capsule(const void *value, void (*destructor)(void *)) {
 | 
			
		||||
        m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
 | 
			
		||||
            // guard if destructor called while err indicator is set
 | 
			
		||||
            error_scope error_guard;
 | 
			
		||||
            auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
 | 
			
		||||
            if (destructor == nullptr) {
 | 
			
		||||
                if (PyErr_Occurred()) {
 | 
			
		||||
                    throw error_already_set();
 | 
			
		||||
                }
 | 
			
		||||
                pybind11_fail("Unable to get capsule context");
 | 
			
		||||
            }
 | 
			
		||||
            const char *name = get_name_in_error_scope(o);
 | 
			
		||||
            void *ptr = PyCapsule_GetPointer(o, name);
 | 
			
		||||
            if (ptr == nullptr) {
 | 
			
		||||
                throw error_already_set();
 | 
			
		||||
            }
 | 
			
		||||
            destructor(ptr);
 | 
			
		||||
        });
 | 
			
		||||
        initialize_with_void_ptr_destructor(value, nullptr, destructor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        if (!m_ptr || PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
    capsule(const void *value, const char *name, void (*destructor)(void *)) {
 | 
			
		||||
        initialize_with_void_ptr_destructor(value, name, destructor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    explicit capsule(void (*destructor)()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1889,6 +2004,32 @@ private:
 | 
			
		|||
 | 
			
		||||
        return name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void initialize_with_void_ptr_destructor(const void *value,
 | 
			
		||||
                                             const char *name,
 | 
			
		||||
                                             void (*destructor)(void *)) {
 | 
			
		||||
        m_ptr = PyCapsule_New(const_cast<void *>(value), name, [](PyObject *o) {
 | 
			
		||||
            // guard if destructor called while err indicator is set
 | 
			
		||||
            error_scope error_guard;
 | 
			
		||||
            auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
 | 
			
		||||
            if (destructor == nullptr && PyErr_Occurred()) {
 | 
			
		||||
                throw error_already_set();
 | 
			
		||||
            }
 | 
			
		||||
            const char *name = get_name_in_error_scope(o);
 | 
			
		||||
            void *ptr = PyCapsule_GetPointer(o, name);
 | 
			
		||||
            if (ptr == nullptr) {
 | 
			
		||||
                throw error_already_set();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (destructor != nullptr) {
 | 
			
		||||
                destructor(ptr);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (!m_ptr || PyCapsule_SetContext(m_ptr, reinterpret_cast<void *>(destructor)) != 0) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class tuple : public object {
 | 
			
		||||
| 
						 | 
				
			
			@ -1943,7 +2084,11 @@ public:
 | 
			
		|||
    void clear() /* py-non-const */ { PyDict_Clear(ptr()); }
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    bool contains(T &&key) const {
 | 
			
		||||
        return PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr()) == 1;
 | 
			
		||||
        auto result = PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr());
 | 
			
		||||
        if (result == -1) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
        return result == 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
| 
						 | 
				
			
			@ -1998,14 +2143,20 @@ public:
 | 
			
		|||
    detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void append(T &&val) /* py-non-const */ {
 | 
			
		||||
        PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr());
 | 
			
		||||
        if (PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) != 0) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    template <typename IdxType,
 | 
			
		||||
              typename ValType,
 | 
			
		||||
              detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>
 | 
			
		||||
    void insert(const IdxType &index, ValType &&val) /* py-non-const */ {
 | 
			
		||||
        PyList_Insert(
 | 
			
		||||
            m_ptr, ssize_t_cast(index), detail::object_or_cast(std::forward<ValType>(val)).ptr());
 | 
			
		||||
        if (PyList_Insert(m_ptr,
 | 
			
		||||
                          ssize_t_cast(index),
 | 
			
		||||
                          detail::object_or_cast(std::forward<ValType>(val)).ptr())
 | 
			
		||||
            != 0) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2023,7 +2174,11 @@ public:
 | 
			
		|||
    bool empty() const { return size() == 0; }
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    bool contains(T &&val) const {
 | 
			
		||||
        return PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 1;
 | 
			
		||||
        auto result = PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr());
 | 
			
		||||
        if (result == -1) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
        return result == 1;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2364,29 +2519,39 @@ bool object_api<D>::rich_compare(object_api const &other, int value) const {
 | 
			
		|||
        return result;                                                                            \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#define PYBIND11_MATH_OPERATOR_BINARY_INPLACE(iop, fn)                                            \
 | 
			
		||||
    template <typename D>                                                                         \
 | 
			
		||||
    object object_api<D>::iop(object_api const &other) {                                          \
 | 
			
		||||
        object result = reinterpret_steal<object>(fn(derived().ptr(), other.derived().ptr()));    \
 | 
			
		||||
        if (!result.ptr())                                                                        \
 | 
			
		||||
            throw error_already_set();                                                            \
 | 
			
		||||
        return result;                                                                            \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
PYBIND11_MATH_OPERATOR_UNARY(operator~, PyNumber_Invert)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_UNARY(operator-, PyNumber_Negative)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator+, PyNumber_Add)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator+=, PyNumber_InPlaceAdd)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator+=, PyNumber_InPlaceAdd)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator-, PyNumber_Subtract)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator-=, PyNumber_InPlaceSubtract)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator-=, PyNumber_InPlaceSubtract)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator*, PyNumber_Multiply)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator*=, PyNumber_InPlaceMultiply)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator*=, PyNumber_InPlaceMultiply)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator/, PyNumber_TrueDivide)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator/=, PyNumber_InPlaceTrueDivide)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator/=, PyNumber_InPlaceTrueDivide)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator|, PyNumber_Or)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator|=, PyNumber_InPlaceOr)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator|=, PyNumber_InPlaceOr)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator&, PyNumber_And)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator&=, PyNumber_InPlaceAnd)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator&=, PyNumber_InPlaceAnd)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator^, PyNumber_Xor)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator^=, PyNumber_InPlaceXor)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator^=, PyNumber_InPlaceXor)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator<<, PyNumber_Lshift)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator<<=, PyNumber_InPlaceLshift)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator<<=, PyNumber_InPlaceLshift)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator>>, PyNumber_Rshift)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY(operator>>=, PyNumber_InPlaceRshift)
 | 
			
		||||
PYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator>>=, PyNumber_InPlaceRshift)
 | 
			
		||||
 | 
			
		||||
#undef PYBIND11_MATH_OPERATOR_UNARY
 | 
			
		||||
#undef PYBIND11_MATH_OPERATOR_BINARY
 | 
			
		||||
#undef PYBIND11_MATH_OPERATOR_BINARY_INPLACE
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,21 +45,35 @@ using forwarded_type = conditional_t<std::is_lvalue_reference<T>::value,
 | 
			
		|||
/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
 | 
			
		||||
/// used for forwarding a container's elements.
 | 
			
		||||
template <typename T, typename U>
 | 
			
		||||
forwarded_type<T, U> forward_like(U &&u) {
 | 
			
		||||
constexpr forwarded_type<T, U> forward_like(U &&u) {
 | 
			
		||||
    return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Checks if a container has a STL style reserve method.
 | 
			
		||||
// This will only return true for a `reserve()` with a `void` return.
 | 
			
		||||
template <typename C>
 | 
			
		||||
using has_reserve_method = std::is_same<decltype(std::declval<C>().reserve(0)), void>;
 | 
			
		||||
 | 
			
		||||
template <typename Type, typename Key>
 | 
			
		||||
struct set_caster {
 | 
			
		||||
    using type = Type;
 | 
			
		||||
    using key_conv = make_caster<Key>;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
 | 
			
		||||
    void reserve_maybe(const anyset &s, Type *) {
 | 
			
		||||
        value.reserve(s.size());
 | 
			
		||||
    }
 | 
			
		||||
    void reserve_maybe(const anyset &, void *) {}
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    bool load(handle src, bool convert) {
 | 
			
		||||
        if (!isinstance<anyset>(src)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        auto s = reinterpret_borrow<anyset>(src);
 | 
			
		||||
        value.clear();
 | 
			
		||||
        reserve_maybe(s, &value);
 | 
			
		||||
        for (auto entry : s) {
 | 
			
		||||
            key_conv conv;
 | 
			
		||||
            if (!conv.load(entry, convert)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +92,7 @@ struct set_caster {
 | 
			
		|||
        pybind11::set s;
 | 
			
		||||
        for (auto &&value : src) {
 | 
			
		||||
            auto value_ = reinterpret_steal<object>(
 | 
			
		||||
                key_conv::cast(forward_like<T>(value), policy, parent));
 | 
			
		||||
                key_conv::cast(detail::forward_like<T>(value), policy, parent));
 | 
			
		||||
            if (!value_ || !s.add(std::move(value_))) {
 | 
			
		||||
                return handle();
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -94,12 +108,21 @@ struct map_caster {
 | 
			
		|||
    using key_conv = make_caster<Key>;
 | 
			
		||||
    using value_conv = make_caster<Value>;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
 | 
			
		||||
    void reserve_maybe(const dict &d, Type *) {
 | 
			
		||||
        value.reserve(d.size());
 | 
			
		||||
    }
 | 
			
		||||
    void reserve_maybe(const dict &, void *) {}
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    bool load(handle src, bool convert) {
 | 
			
		||||
        if (!isinstance<dict>(src)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        auto d = reinterpret_borrow<dict>(src);
 | 
			
		||||
        value.clear();
 | 
			
		||||
        reserve_maybe(d, &value);
 | 
			
		||||
        for (auto it : d) {
 | 
			
		||||
            key_conv kconv;
 | 
			
		||||
            value_conv vconv;
 | 
			
		||||
| 
						 | 
				
			
			@ -122,9 +145,9 @@ struct map_caster {
 | 
			
		|||
        }
 | 
			
		||||
        for (auto &&kv : src) {
 | 
			
		||||
            auto key = reinterpret_steal<object>(
 | 
			
		||||
                key_conv::cast(forward_like<T>(kv.first), policy_key, parent));
 | 
			
		||||
                key_conv::cast(detail::forward_like<T>(kv.first), policy_key, parent));
 | 
			
		||||
            auto value = reinterpret_steal<object>(
 | 
			
		||||
                value_conv::cast(forward_like<T>(kv.second), policy_value, parent));
 | 
			
		||||
                value_conv::cast(detail::forward_like<T>(kv.second), policy_value, parent));
 | 
			
		||||
            if (!key || !value) {
 | 
			
		||||
                return handle();
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -160,9 +183,7 @@ struct list_caster {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <
 | 
			
		||||
        typename T = Type,
 | 
			
		||||
        enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
 | 
			
		||||
    template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
 | 
			
		||||
    void reserve_maybe(const sequence &s, Type *) {
 | 
			
		||||
        value.reserve(s.size());
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -178,7 +199,7 @@ public:
 | 
			
		|||
        ssize_t index = 0;
 | 
			
		||||
        for (auto &&value : src) {
 | 
			
		||||
            auto value_ = reinterpret_steal<object>(
 | 
			
		||||
                value_conv::cast(forward_like<T>(value), policy, parent));
 | 
			
		||||
                value_conv::cast(detail::forward_like<T>(value), policy, parent));
 | 
			
		||||
            if (!value_) {
 | 
			
		||||
                return handle();
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -242,7 +263,7 @@ public:
 | 
			
		|||
        ssize_t index = 0;
 | 
			
		||||
        for (auto &&value : src) {
 | 
			
		||||
            auto value_ = reinterpret_steal<object>(
 | 
			
		||||
                value_conv::cast(forward_like<T>(value), policy, parent));
 | 
			
		||||
                value_conv::cast(detail::forward_like<T>(value), policy, parent));
 | 
			
		||||
            if (!value_) {
 | 
			
		||||
                return handle();
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -252,11 +273,11 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    PYBIND11_TYPE_CASTER(ArrayType,
 | 
			
		||||
                         const_name("List[") + value_conv::name
 | 
			
		||||
                         const_name<Resizable>(const_name(""), const_name("Annotated["))
 | 
			
		||||
                             + const_name("List[") + value_conv::name + const_name("]")
 | 
			
		||||
                             + const_name<Resizable>(const_name(""),
 | 
			
		||||
                                                     const_name("[") + const_name<Size>()
 | 
			
		||||
                                                         + const_name("]"))
 | 
			
		||||
                             + const_name("]"));
 | 
			
		||||
                                                     const_name(", FixedSize(")
 | 
			
		||||
                                                         + const_name<Size>() + const_name(")]")));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Type, size_t Size>
 | 
			
		||||
| 
						 | 
				
			
			@ -290,11 +311,12 @@ struct optional_caster {
 | 
			
		|||
    template <typename T>
 | 
			
		||||
    static handle cast(T &&src, return_value_policy policy, handle parent) {
 | 
			
		||||
        if (!src) {
 | 
			
		||||
            return none().inc_ref();
 | 
			
		||||
            return none().release();
 | 
			
		||||
        }
 | 
			
		||||
        if (!std::is_lvalue_reference<T>::value) {
 | 
			
		||||
            policy = return_value_policy_override<Value>::policy(policy);
 | 
			
		||||
        }
 | 
			
		||||
        // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
 | 
			
		||||
        return value_conv::cast(*std::forward<T>(src), policy, parent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,10 +10,13 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "detail/common.h"
 | 
			
		||||
#include "detail/type_caster_base.h"
 | 
			
		||||
#include "cast.h"
 | 
			
		||||
#include "operators.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
| 
						 | 
				
			
			@ -58,9 +61,11 @@ struct is_comparable<
 | 
			
		|||
/* For a vector/map data structure, recursively check the value type
 | 
			
		||||
   (which is std::pair for maps) */
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> {
 | 
			
		||||
    static constexpr const bool value = is_comparable<typename T::value_type>::value;
 | 
			
		||||
};
 | 
			
		||||
struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>>
 | 
			
		||||
    : is_comparable<typename recursive_container_traits<T>::type_to_check_recursively> {};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct is_comparable<recursive_bottom> : std::true_type {};
 | 
			
		||||
 | 
			
		||||
/* For pairs, recursively check the two data types */
 | 
			
		||||
template <typename T>
 | 
			
		||||
| 
						 | 
				
			
			@ -352,13 +357,17 @@ void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl)
 | 
			
		|||
    using DiffType = typename Vector::difference_type;
 | 
			
		||||
    using ItType = typename Vector::iterator;
 | 
			
		||||
    cl.def("__getitem__", [](const Vector &v, DiffType i) -> T {
 | 
			
		||||
        if (i < 0 && (i += v.size()) < 0) {
 | 
			
		||||
        if (i < 0) {
 | 
			
		||||
            i += v.size();
 | 
			
		||||
            if (i < 0) {
 | 
			
		||||
                throw index_error();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        auto i_st = static_cast<SizeType>(i);
 | 
			
		||||
        if (i_st >= v.size()) {
 | 
			
		||||
            throw index_error();
 | 
			
		||||
        }
 | 
			
		||||
        if ((SizeType) i >= v.size()) {
 | 
			
		||||
            throw index_error();
 | 
			
		||||
        }
 | 
			
		||||
        return v[(SizeType) i];
 | 
			
		||||
        return v[i_st];
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    cl.def(
 | 
			
		||||
| 
						 | 
				
			
			@ -636,18 +645,52 @@ auto map_if_insertion_operator(Class_ &cl, std::string const &name)
 | 
			
		|||
        "Return the canonical string representation of this map.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
template <typename KeyType>
 | 
			
		||||
struct keys_view {
 | 
			
		||||
    Map ↦
 | 
			
		||||
    virtual size_t len() = 0;
 | 
			
		||||
    virtual iterator iter() = 0;
 | 
			
		||||
    virtual bool contains(const KeyType &k) = 0;
 | 
			
		||||
    virtual bool contains(const object &k) = 0;
 | 
			
		||||
    virtual ~keys_view() = default;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
template <typename MappedType>
 | 
			
		||||
struct values_view {
 | 
			
		||||
    virtual size_t len() = 0;
 | 
			
		||||
    virtual iterator iter() = 0;
 | 
			
		||||
    virtual ~values_view() = default;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename KeyType, typename MappedType>
 | 
			
		||||
struct items_view {
 | 
			
		||||
    virtual size_t len() = 0;
 | 
			
		||||
    virtual iterator iter() = 0;
 | 
			
		||||
    virtual ~items_view() = default;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Map, typename KeysView>
 | 
			
		||||
struct KeysViewImpl : public KeysView {
 | 
			
		||||
    explicit KeysViewImpl(Map &map) : map(map) {}
 | 
			
		||||
    size_t len() override { return map.size(); }
 | 
			
		||||
    iterator iter() override { return make_key_iterator(map.begin(), map.end()); }
 | 
			
		||||
    bool contains(const typename Map::key_type &k) override { return map.find(k) != map.end(); }
 | 
			
		||||
    bool contains(const object &) override { return false; }
 | 
			
		||||
    Map ↦
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
struct items_view {
 | 
			
		||||
template <typename Map, typename ValuesView>
 | 
			
		||||
struct ValuesViewImpl : public ValuesView {
 | 
			
		||||
    explicit ValuesViewImpl(Map &map) : map(map) {}
 | 
			
		||||
    size_t len() override { return map.size(); }
 | 
			
		||||
    iterator iter() override { return make_value_iterator(map.begin(), map.end()); }
 | 
			
		||||
    Map ↦
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Map, typename ItemsView>
 | 
			
		||||
struct ItemsViewImpl : public ItemsView {
 | 
			
		||||
    explicit ItemsViewImpl(Map &map) : map(map) {}
 | 
			
		||||
    size_t len() override { return map.size(); }
 | 
			
		||||
    iterator iter() override { return make_iterator(map.begin(), map.end()); }
 | 
			
		||||
    Map ↦
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -657,9 +700,11 @@ template <typename Map, typename holder_type = std::unique_ptr<Map>, typename...
 | 
			
		|||
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
 | 
			
		||||
    using KeyType = typename Map::key_type;
 | 
			
		||||
    using MappedType = typename Map::mapped_type;
 | 
			
		||||
    using KeysView = detail::keys_view<Map>;
 | 
			
		||||
    using ValuesView = detail::values_view<Map>;
 | 
			
		||||
    using ItemsView = detail::items_view<Map>;
 | 
			
		||||
    using StrippedKeyType = detail::remove_cvref_t<KeyType>;
 | 
			
		||||
    using StrippedMappedType = detail::remove_cvref_t<MappedType>;
 | 
			
		||||
    using KeysView = detail::keys_view<StrippedKeyType>;
 | 
			
		||||
    using ValuesView = detail::values_view<StrippedMappedType>;
 | 
			
		||||
    using ItemsView = detail::items_view<StrippedKeyType, StrippedMappedType>;
 | 
			
		||||
    using Class_ = class_<Map, holder_type>;
 | 
			
		||||
 | 
			
		||||
    // If either type is a non-module-local bound type then make the map binding non-local as well;
 | 
			
		||||
| 
						 | 
				
			
			@ -673,12 +718,57 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
 | 
			
		||||
    class_<KeysView> keys_view(
 | 
			
		||||
        scope, ("KeysView[" + name + "]").c_str(), pybind11::module_local(local));
 | 
			
		||||
    class_<ValuesView> values_view(
 | 
			
		||||
        scope, ("ValuesView[" + name + "]").c_str(), pybind11::module_local(local));
 | 
			
		||||
    class_<ItemsView> items_view(
 | 
			
		||||
        scope, ("ItemsView[" + name + "]").c_str(), pybind11::module_local(local));
 | 
			
		||||
    static constexpr auto key_type_descr = detail::make_caster<KeyType>::name;
 | 
			
		||||
    static constexpr auto mapped_type_descr = detail::make_caster<MappedType>::name;
 | 
			
		||||
    std::string key_type_name(key_type_descr.text), mapped_type_name(mapped_type_descr.text);
 | 
			
		||||
 | 
			
		||||
    // If key type isn't properly wrapped, fall back to C++ names
 | 
			
		||||
    if (key_type_name == "%") {
 | 
			
		||||
        key_type_name = detail::type_info_description(typeid(KeyType));
 | 
			
		||||
    }
 | 
			
		||||
    // Similarly for value type:
 | 
			
		||||
    if (mapped_type_name == "%") {
 | 
			
		||||
        mapped_type_name = detail::type_info_description(typeid(MappedType));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Wrap KeysView[KeyType] if it wasn't already wrapped
 | 
			
		||||
    if (!detail::get_type_info(typeid(KeysView))) {
 | 
			
		||||
        class_<KeysView> keys_view(
 | 
			
		||||
            scope, ("KeysView[" + key_type_name + "]").c_str(), pybind11::module_local(local));
 | 
			
		||||
        keys_view.def("__len__", &KeysView::len);
 | 
			
		||||
        keys_view.def("__iter__",
 | 
			
		||||
                      &KeysView::iter,
 | 
			
		||||
                      keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
 | 
			
		||||
        );
 | 
			
		||||
        keys_view.def("__contains__",
 | 
			
		||||
                      static_cast<bool (KeysView::*)(const KeyType &)>(&KeysView::contains));
 | 
			
		||||
        // Fallback for when the object is not of the key type
 | 
			
		||||
        keys_view.def("__contains__",
 | 
			
		||||
                      static_cast<bool (KeysView::*)(const object &)>(&KeysView::contains));
 | 
			
		||||
    }
 | 
			
		||||
    // Similarly for ValuesView:
 | 
			
		||||
    if (!detail::get_type_info(typeid(ValuesView))) {
 | 
			
		||||
        class_<ValuesView> values_view(scope,
 | 
			
		||||
                                       ("ValuesView[" + mapped_type_name + "]").c_str(),
 | 
			
		||||
                                       pybind11::module_local(local));
 | 
			
		||||
        values_view.def("__len__", &ValuesView::len);
 | 
			
		||||
        values_view.def("__iter__",
 | 
			
		||||
                        &ValuesView::iter,
 | 
			
		||||
                        keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    // Similarly for ItemsView:
 | 
			
		||||
    if (!detail::get_type_info(typeid(ItemsView))) {
 | 
			
		||||
        class_<ItemsView> items_view(
 | 
			
		||||
            scope,
 | 
			
		||||
            ("ItemsView[" + key_type_name + ", ").append(mapped_type_name + "]").c_str(),
 | 
			
		||||
            pybind11::module_local(local));
 | 
			
		||||
        items_view.def("__len__", &ItemsView::len);
 | 
			
		||||
        items_view.def("__iter__",
 | 
			
		||||
                       &ItemsView::iter,
 | 
			
		||||
                       keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cl.def(init<>());
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -698,19 +788,25 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
 | 
			
		|||
 | 
			
		||||
    cl.def(
 | 
			
		||||
        "keys",
 | 
			
		||||
        [](Map &m) { return KeysView{m}; },
 | 
			
		||||
        [](Map &m) {
 | 
			
		||||
            return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map, KeysView>(m));
 | 
			
		||||
        },
 | 
			
		||||
        keep_alive<0, 1>() /* Essential: keep map alive while view exists */
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    cl.def(
 | 
			
		||||
        "values",
 | 
			
		||||
        [](Map &m) { return ValuesView{m}; },
 | 
			
		||||
        [](Map &m) {
 | 
			
		||||
            return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map, ValuesView>(m));
 | 
			
		||||
        },
 | 
			
		||||
        keep_alive<0, 1>() /* Essential: keep map alive while view exists */
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    cl.def(
 | 
			
		||||
        "items",
 | 
			
		||||
        [](Map &m) { return ItemsView{m}; },
 | 
			
		||||
        [](Map &m) {
 | 
			
		||||
            return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map, ItemsView>(m));
 | 
			
		||||
        },
 | 
			
		||||
        keep_alive<0, 1>() /* Essential: keep map alive while view exists */
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -749,36 +845,6 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
 | 
			
		|||
 | 
			
		||||
    cl.def("__len__", &Map::size);
 | 
			
		||||
 | 
			
		||||
    keys_view.def("__len__", [](KeysView &view) { return view.map.size(); });
 | 
			
		||||
    keys_view.def(
 | 
			
		||||
        "__iter__",
 | 
			
		||||
        [](KeysView &view) { return make_key_iterator(view.map.begin(), view.map.end()); },
 | 
			
		||||
        keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
 | 
			
		||||
    );
 | 
			
		||||
    keys_view.def("__contains__", [](KeysView &view, const KeyType &k) -> bool {
 | 
			
		||||
        auto it = view.map.find(k);
 | 
			
		||||
        if (it == view.map.end()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
    // Fallback for when the object is not of the key type
 | 
			
		||||
    keys_view.def("__contains__", [](KeysView &, const object &) -> bool { return false; });
 | 
			
		||||
 | 
			
		||||
    values_view.def("__len__", [](ValuesView &view) { return view.map.size(); });
 | 
			
		||||
    values_view.def(
 | 
			
		||||
        "__iter__",
 | 
			
		||||
        [](ValuesView &view) { return make_value_iterator(view.map.begin(), view.map.end()); },
 | 
			
		||||
        keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    items_view.def("__len__", [](ItemsView &view) { return view.map.size(); });
 | 
			
		||||
    items_view.def(
 | 
			
		||||
        "__iter__",
 | 
			
		||||
        [](ItemsView &view) { return make_iterator(view.map.begin(), view.map.end()); },
 | 
			
		||||
        keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return cl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
// Copyright (c) 2023 The pybind Community.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "detail/common.h"
 | 
			
		||||
#include "detail/descr.h"
 | 
			
		||||
#include "cast.h"
 | 
			
		||||
#include "pytypes.h"
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 | 
			
		||||
PYBIND11_NAMESPACE_BEGIN(detail)
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
class type_caster<PyObject> {
 | 
			
		||||
public:
 | 
			
		||||
    static constexpr auto name = const_name("object"); // See discussion under PR #4601.
 | 
			
		||||
 | 
			
		||||
    // This overload is purely to guard against accidents.
 | 
			
		||||
    template <typename T,
 | 
			
		||||
              detail::enable_if_t<!is_same_ignoring_cvref<T, PyObject *>::value, int> = 0>
 | 
			
		||||
    static handle cast(T &&, return_value_policy, handle /*parent*/) {
 | 
			
		||||
        static_assert(is_same_ignoring_cvref<T, PyObject *>::value,
 | 
			
		||||
                      "Invalid C++ type T for to-Python conversion (type_caster<PyObject>).");
 | 
			
		||||
        return nullptr; // Unreachable.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static handle cast(PyObject *src, return_value_policy policy, handle /*parent*/) {
 | 
			
		||||
        if (src == nullptr) {
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
        if (PyErr_Occurred()) {
 | 
			
		||||
            raise_from(PyExc_SystemError, "src != nullptr but PyErr_Occurred()");
 | 
			
		||||
            throw error_already_set();
 | 
			
		||||
        }
 | 
			
		||||
        if (policy == return_value_policy::take_ownership) {
 | 
			
		||||
            return src;
 | 
			
		||||
        }
 | 
			
		||||
        if (policy == return_value_policy::reference
 | 
			
		||||
            || policy == return_value_policy::automatic_reference) {
 | 
			
		||||
            return handle(src).inc_ref();
 | 
			
		||||
        }
 | 
			
		||||
        pybind11_fail("type_caster<PyObject>::cast(): unsupported return_value_policy: "
 | 
			
		||||
                      + std::to_string(static_cast<int>(policy)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool load(handle src, bool) {
 | 
			
		||||
        value = reinterpret_borrow<object>(src);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    using cast_op_type = PyObject *;
 | 
			
		||||
 | 
			
		||||
    explicit operator PyObject *() { return value.ptr(); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    object value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PYBIND11_NAMESPACE_END(detail)
 | 
			
		||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
 | 
			
		||||
| 
						 | 
				
			
			@ -5,7 +5,17 @@ import nox
 | 
			
		|||
nox.needs_version = ">=2022.1.7"
 | 
			
		||||
nox.options.sessions = ["lint", "tests", "tests_packaging"]
 | 
			
		||||
 | 
			
		||||
PYTHON_VERISONS = ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "pypy3.7", "pypy3.8"]
 | 
			
		||||
PYTHON_VERSIONS = [
 | 
			
		||||
    "3.6",
 | 
			
		||||
    "3.7",
 | 
			
		||||
    "3.8",
 | 
			
		||||
    "3.9",
 | 
			
		||||
    "3.10",
 | 
			
		||||
    "3.11",
 | 
			
		||||
    "pypy3.7",
 | 
			
		||||
    "pypy3.8",
 | 
			
		||||
    "pypy3.9",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
if os.environ.get("CI", None):
 | 
			
		||||
    nox.options.error_on_missing_interpreters = True
 | 
			
		||||
| 
						 | 
				
			
			@ -17,10 +27,10 @@ def lint(session: nox.Session) -> None:
 | 
			
		|||
    Lint the codebase (except for clang-format/tidy).
 | 
			
		||||
    """
 | 
			
		||||
    session.install("pre-commit")
 | 
			
		||||
    session.run("pre-commit", "run", "-a")
 | 
			
		||||
    session.run("pre-commit", "run", "-a", *session.posargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@nox.session(python=PYTHON_VERISONS)
 | 
			
		||||
@nox.session(python=PYTHON_VERSIONS)
 | 
			
		||||
def tests(session: nox.Session) -> None:
 | 
			
		||||
    """
 | 
			
		||||
    Run the tests (requires a compiler).
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +58,7 @@ def tests_packaging(session: nox.Session) -> None:
 | 
			
		|||
    """
 | 
			
		||||
 | 
			
		||||
    session.install("-r", "tests/requirements.txt", "--prefer-binary")
 | 
			
		||||
    session.run("pytest", "tests/extra_python_package")
 | 
			
		||||
    session.run("pytest", "tests/extra_python_package", *session.posargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@nox.session(reuse_venv=True)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,17 @@
 | 
			
		|||
import sys
 | 
			
		||||
 | 
			
		||||
if sys.version_info < (3, 6):
 | 
			
		||||
if sys.version_info < (3, 6):  # noqa: UP036
 | 
			
		||||
    msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5."
 | 
			
		||||
    raise ImportError(msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from ._version import __version__, version_info
 | 
			
		||||
from .commands import get_cmake_dir, get_include
 | 
			
		||||
from .commands import get_cmake_dir, get_include, get_pkgconfig_dir
 | 
			
		||||
 | 
			
		||||
__all__ = (
 | 
			
		||||
    "version_info",
 | 
			
		||||
    "__version__",
 | 
			
		||||
    "get_include",
 | 
			
		||||
    "get_cmake_dir",
 | 
			
		||||
    "get_pkgconfig_dir",
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,8 @@ import argparse
 | 
			
		|||
import sys
 | 
			
		||||
import sysconfig
 | 
			
		||||
 | 
			
		||||
from .commands import get_cmake_dir, get_include
 | 
			
		||||
from ._version import __version__
 | 
			
		||||
from .commands import get_cmake_dir, get_include, get_pkgconfig_dir
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def print_includes() -> None:
 | 
			
		||||
| 
						 | 
				
			
			@ -24,8 +25,13 @@ def print_includes() -> None:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def main() -> None:
 | 
			
		||||
 | 
			
		||||
    parser = argparse.ArgumentParser()
 | 
			
		||||
    parser.add_argument(
 | 
			
		||||
        "--version",
 | 
			
		||||
        action="version",
 | 
			
		||||
        version=__version__,
 | 
			
		||||
        help="Print the version and exit.",
 | 
			
		||||
    )
 | 
			
		||||
    parser.add_argument(
 | 
			
		||||
        "--includes",
 | 
			
		||||
        action="store_true",
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +42,11 @@ def main() -> None:
 | 
			
		|||
        action="store_true",
 | 
			
		||||
        help="Print the CMake module directory, ideal for setting -Dpybind11_ROOT in CMake.",
 | 
			
		||||
    )
 | 
			
		||||
    parser.add_argument(
 | 
			
		||||
        "--pkgconfigdir",
 | 
			
		||||
        action="store_true",
 | 
			
		||||
        help="Print the pkgconfig directory, ideal for setting $PKG_CONFIG_PATH.",
 | 
			
		||||
    )
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    if not sys.argv[1:]:
 | 
			
		||||
        parser.print_help()
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +54,8 @@ def main() -> None:
 | 
			
		|||
        print_includes()
 | 
			
		||||
    if args.cmakedir:
 | 
			
		||||
        print(get_cmake_dir())
 | 
			
		||||
    if args.pkgconfigdir:
 | 
			
		||||
        print(get_pkgconfig_dir())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,5 +8,5 @@ def _to_int(s: str) -> Union[int, str]:
 | 
			
		|||
        return s
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__version__ = "2.10.0"
 | 
			
		||||
__version__ = "2.11.1"
 | 
			
		||||
version_info = tuple(_to_int(s) for s in __version__.split("."))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@ import os
 | 
			
		|||
DIR = os.path.abspath(os.path.dirname(__file__))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_include(user: bool = False) -> str:  # pylint: disable=unused-argument
 | 
			
		||||
def get_include(user: bool = False) -> str:  # noqa: ARG001
 | 
			
		||||
    """
 | 
			
		||||
    Return the path to the pybind11 include directory. The historical "user"
 | 
			
		||||
    argument is unused, and may be removed.
 | 
			
		||||
| 
						 | 
				
			
			@ -23,3 +23,15 @@ def get_cmake_dir() -> str:
 | 
			
		|||
 | 
			
		||||
    msg = "pybind11 not installed, installation required to access the CMake files"
 | 
			
		||||
    raise ImportError(msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_pkgconfig_dir() -> str:
 | 
			
		||||
    """
 | 
			
		||||
    Return the path to the pybind11 pkgconfig directory.
 | 
			
		||||
    """
 | 
			
		||||
    pkgconfig_installed_path = os.path.join(DIR, "share", "pkgconfig")
 | 
			
		||||
    if os.path.exists(pkgconfig_installed_path):
 | 
			
		||||
        return pkgconfig_installed_path
 | 
			
		||||
 | 
			
		||||
    msg = "pybind11 not installed, installation required to access the pkgconfig files"
 | 
			
		||||
    raise ImportError(msg)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,8 +66,8 @@ try:
 | 
			
		|||
    from setuptools import Extension as _Extension
 | 
			
		||||
    from setuptools.command.build_ext import build_ext as _build_ext
 | 
			
		||||
except ImportError:
 | 
			
		||||
    from distutils.command.build_ext import build_ext as _build_ext
 | 
			
		||||
    from distutils.extension import Extension as _Extension
 | 
			
		||||
    from distutils.command.build_ext import build_ext as _build_ext  # type: ignore[assignment]
 | 
			
		||||
    from distutils.extension import Extension as _Extension  # type: ignore[assignment]
 | 
			
		||||
 | 
			
		||||
import distutils.ccompiler
 | 
			
		||||
import distutils.errors
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +84,7 @@ STD_TMPL = "/std:c++{}" if WIN else "-std=c++{}"
 | 
			
		|||
# directory into your path if it sits beside your setup.py.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Pybind11Extension(_Extension):  # type: ignore[misc]
 | 
			
		||||
class Pybind11Extension(_Extension):
 | 
			
		||||
    """
 | 
			
		||||
    Build a C++11+ Extension module with pybind11. This automatically adds the
 | 
			
		||||
    recommended flags when you init the extension and assumes C++ sources - you
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +118,6 @@ class Pybind11Extension(_Extension):  # type: ignore[misc]
 | 
			
		|||
        self.extra_link_args[:0] = flags
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args: Any, **kwargs: Any) -> None:
 | 
			
		||||
 | 
			
		||||
        self._cxx_level = 0
 | 
			
		||||
        cxx_std = kwargs.pop("cxx_std", 0)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +144,6 @@ class Pybind11Extension(_Extension):  # type: ignore[misc]
 | 
			
		|||
        self.cxx_std = cxx_std
 | 
			
		||||
 | 
			
		||||
        cflags = []
 | 
			
		||||
        ldflags = []
 | 
			
		||||
        if WIN:
 | 
			
		||||
            cflags += ["/EHsc", "/bigobj"]
 | 
			
		||||
        else:
 | 
			
		||||
| 
						 | 
				
			
			@ -155,11 +153,7 @@ class Pybind11Extension(_Extension):  # type: ignore[misc]
 | 
			
		|||
            c_cpp_flags = shlex.split(env_cflags) + shlex.split(env_cppflags)
 | 
			
		||||
            if not any(opt.startswith("-g") for opt in c_cpp_flags):
 | 
			
		||||
                cflags += ["-g0"]
 | 
			
		||||
            if MACOS:
 | 
			
		||||
                cflags += ["-stdlib=libc++"]
 | 
			
		||||
                ldflags += ["-stdlib=libc++"]
 | 
			
		||||
        self._add_cflags(cflags)
 | 
			
		||||
        self._add_ldflags(ldflags)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def cxx_std(self) -> int:
 | 
			
		||||
| 
						 | 
				
			
			@ -174,9 +168,10 @@ class Pybind11Extension(_Extension):  # type: ignore[misc]
 | 
			
		|||
 | 
			
		||||
    @cxx_std.setter
 | 
			
		||||
    def cxx_std(self, level: int) -> None:
 | 
			
		||||
 | 
			
		||||
        if self._cxx_level:
 | 
			
		||||
            warnings.warn("You cannot safely change the cxx_level after setting it!")
 | 
			
		||||
            warnings.warn(
 | 
			
		||||
                "You cannot safely change the cxx_level after setting it!", stacklevel=2
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        # MSVC 2015 Update 3 and later only have 14 (and later 17) modes, so
 | 
			
		||||
        # force a valid flag here.
 | 
			
		||||
| 
						 | 
				
			
			@ -271,7 +266,7 @@ def auto_cpp_level(compiler: Any) -> Union[str, int]:
 | 
			
		|||
    raise RuntimeError(msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class build_ext(_build_ext):  # type: ignore[misc] # noqa: N801
 | 
			
		||||
class build_ext(_build_ext):  # noqa: N801
 | 
			
		||||
    """
 | 
			
		||||
    Customized build_ext that allows an auto-search for the highest supported
 | 
			
		||||
    C++ level for Pybind11Extension. This is only needed for the auto-search
 | 
			
		||||
| 
						 | 
				
			
			@ -341,7 +336,7 @@ def naive_recompile(obj: str, src: str) -> bool:
 | 
			
		|||
    return os.stat(obj).st_mtime < os.stat(src).st_mtime
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def no_recompile(obg: str, src: str) -> bool:  # pylint: disable=unused-argument
 | 
			
		||||
def no_recompile(obg: str, src: str) -> bool:  # noqa: ARG001
 | 
			
		||||
    """
 | 
			
		||||
    This is the safest but slowest choice (and is the default) - will always
 | 
			
		||||
    recompile sources.
 | 
			
		||||
| 
						 | 
				
			
			@ -439,7 +434,6 @@ class ParallelCompile:
 | 
			
		|||
            extra_postargs: Optional[List[str]] = None,
 | 
			
		||||
            depends: Optional[List[str]] = None,
 | 
			
		||||
        ) -> Any:
 | 
			
		||||
 | 
			
		||||
            # These lines are directly from distutils.ccompiler.CCompiler
 | 
			
		||||
            macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile(  # type: ignore[attr-defined]
 | 
			
		||||
                output_dir, macros, include_dirs, sources, depends, extra_postargs
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
requires = ["setuptools>=42", "cmake>=3.18", "ninja"]
 | 
			
		||||
build-backend = "setuptools.build_meta"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[tool.check-manifest]
 | 
			
		||||
ignore = [
 | 
			
		||||
    "tests/**",
 | 
			
		||||
| 
						 | 
				
			
			@ -15,11 +16,6 @@ ignore = [
 | 
			
		|||
    "noxfile.py",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[tool.isort]
 | 
			
		||||
# Needs the compiled .so modules and env.py from tests
 | 
			
		||||
known_first_party = "env,pybind11_cross_module_tests,pybind11_tests,"
 | 
			
		||||
# For black compatibility
 | 
			
		||||
profile = "black"
 | 
			
		||||
 | 
			
		||||
[tool.mypy]
 | 
			
		||||
files = ["pybind11"]
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +26,7 @@ enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
 | 
			
		|||
warn_unreachable = true
 | 
			
		||||
 | 
			
		||||
[[tool.mypy.overrides]]
 | 
			
		||||
module = ["ghapi.*", "setuptools.*"]
 | 
			
		||||
module = ["ghapi.*"]
 | 
			
		||||
ignore_missing_imports = true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -58,4 +54,45 @@ messages_control.disable = [
 | 
			
		|||
  "invalid-name",
 | 
			
		||||
  "protected-access",
 | 
			
		||||
  "missing-module-docstring",
 | 
			
		||||
  "unused-argument",  # covered by Ruff ARG
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[tool.ruff]
 | 
			
		||||
select = [
 | 
			
		||||
  "E", "F", "W", # flake8
 | 
			
		||||
  "B",           # flake8-bugbear
 | 
			
		||||
  "I",           # isort
 | 
			
		||||
  "N",           # pep8-naming
 | 
			
		||||
  "ARG",         # flake8-unused-arguments
 | 
			
		||||
  "C4",          # flake8-comprehensions
 | 
			
		||||
  "EM",          # flake8-errmsg
 | 
			
		||||
  "ICN",         # flake8-import-conventions
 | 
			
		||||
  "ISC",         # flake8-implicit-str-concat
 | 
			
		||||
  "PGH",         # pygrep-hooks
 | 
			
		||||
  "PIE",         # flake8-pie
 | 
			
		||||
  "PL",          # pylint
 | 
			
		||||
  "PT",          # flake8-pytest-style
 | 
			
		||||
  "RET",         # flake8-return
 | 
			
		||||
  "RUF100",      # Ruff-specific
 | 
			
		||||
  "SIM",         # flake8-simplify
 | 
			
		||||
  "UP",          # pyupgrade
 | 
			
		||||
  "YTT",         # flake8-2020
 | 
			
		||||
]
 | 
			
		||||
ignore = [
 | 
			
		||||
  "PLR",    # Design related pylint
 | 
			
		||||
  "E501",   # Line too long (Black is enough)
 | 
			
		||||
  "PT011",  # Too broad with raises in pytest
 | 
			
		||||
  "PT004",  # Fixture that doesn't return needs underscore (no, it is fine)
 | 
			
		||||
  "SIM118", # iter(x) is not always the same as iter(x.keys())
 | 
			
		||||
]
 | 
			
		||||
target-version = "py37"
 | 
			
		||||
src = ["src"]
 | 
			
		||||
unfixable = ["T20"]
 | 
			
		||||
exclude = []
 | 
			
		||||
line-length = 120
 | 
			
		||||
isort.known-first-party = ["env", "pybind11_cross_module_tests", "pybind11_tests"]
 | 
			
		||||
 | 
			
		||||
[tool.ruff.per-file-ignores]
 | 
			
		||||
"tests/**" = ["EM", "N"]
 | 
			
		||||
"tests/test_call_policies.py" = ["PLC1901"]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ classifiers =
 | 
			
		|||
    Programming Language :: Python :: 3.9
 | 
			
		||||
    Programming Language :: Python :: 3.10
 | 
			
		||||
    Programming Language :: Python :: 3.11
 | 
			
		||||
    Programming Language :: Python :: 3.12
 | 
			
		||||
    License :: OSI Approved :: BSD License
 | 
			
		||||
    Programming Language :: Python :: Implementation :: PyPy
 | 
			
		||||
    Programming Language :: Python :: Implementation :: CPython
 | 
			
		||||
| 
						 | 
				
			
			@ -40,11 +41,3 @@ project_urls =
 | 
			
		|||
[options]
 | 
			
		||||
python_requires = >=3.6
 | 
			
		||||
zip_safe = False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[flake8]
 | 
			
		||||
max-line-length = 120
 | 
			
		||||
show_source = True
 | 
			
		||||
exclude = .git, __pycache__, build, dist, docs, tools, venv
 | 
			
		||||
extend-ignore = E203, E722, B950
 | 
			
		||||
extend-select = B9
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,7 +96,7 @@ def get_and_replace(
 | 
			
		|||
 | 
			
		||||
# Use our input files instead when making the SDist (and anything that depends
 | 
			
		||||
# on it, like a wheel)
 | 
			
		||||
class SDist(setuptools.command.sdist.sdist):  # type: ignore[misc]
 | 
			
		||||
class SDist(setuptools.command.sdist.sdist):
 | 
			
		||||
    def make_release_tree(self, base_dir: str, files: List[str]) -> None:
 | 
			
		||||
        super().make_release_tree(base_dir, files)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -127,6 +127,7 @@ with remove_output("pybind11/include", "pybind11/share"):
 | 
			
		|||
            "-DCMAKE_INSTALL_PREFIX=pybind11",
 | 
			
		||||
            "-DBUILD_TESTING=OFF",
 | 
			
		||||
            "-DPYBIND11_NOPYTHON=ON",
 | 
			
		||||
            "-Dprefix_for_pc_file=${pcfiledir}/../../",
 | 
			
		||||
        ]
 | 
			
		||||
        if "CMAKE_ARGS" in os.environ:
 | 
			
		||||
            fcommand = [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,20 +5,17 @@
 | 
			
		|||
# All rights reserved. Use of this source code is governed by a
 | 
			
		||||
# BSD-style license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
cmake_minimum_required(VERSION 3.4)
 | 
			
		||||
cmake_minimum_required(VERSION 3.5)
 | 
			
		||||
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` 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.26)
 | 
			
		||||
  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
 | 
			
		||||
else()
 | 
			
		||||
  cmake_policy(VERSION 3.21)
 | 
			
		||||
  cmake_policy(VERSION 3.26)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
# Only needed for CMake < 3.5 support
 | 
			
		||||
include(CMakeParseArguments)
 | 
			
		||||
 | 
			
		||||
# Filter out items; print an optional message if any items filtered. This ignores extensions.
 | 
			
		||||
#
 | 
			
		||||
# Usage:
 | 
			
		||||
| 
						 | 
				
			
			@ -128,7 +125,8 @@ set(PYBIND11_TEST_FILES
 | 
			
		|||
    test_custom_type_casters
 | 
			
		||||
    test_custom_type_setup
 | 
			
		||||
    test_docstring_options
 | 
			
		||||
    test_eigen
 | 
			
		||||
    test_eigen_matrix
 | 
			
		||||
    test_eigen_tensor
 | 
			
		||||
    test_enum
 | 
			
		||||
    test_eval
 | 
			
		||||
    test_exceptions
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +151,11 @@ set(PYBIND11_TEST_FILES
 | 
			
		|||
    test_stl_binders
 | 
			
		||||
    test_tagbased_polymorphic
 | 
			
		||||
    test_thread
 | 
			
		||||
    test_type_caster_pyobject_ptr
 | 
			
		||||
    test_union
 | 
			
		||||
    test_unnamed_namespace_a
 | 
			
		||||
    test_unnamed_namespace_b
 | 
			
		||||
    test_vector_unique_ptr_member
 | 
			
		||||
    test_virtual_functions)
 | 
			
		||||
 | 
			
		||||
# Invoking cmake with something like:
 | 
			
		||||
| 
						 | 
				
			
			@ -168,7 +170,7 @@ if(PYBIND11_TEST_OVERRIDE)
 | 
			
		|||
  # This allows the override to be done with extensions, preserving backwards compatibility.
 | 
			
		||||
  foreach(test_name ${TEST_FILES_NO_EXT})
 | 
			
		||||
    if(NOT ${test_name} IN_LIST TEST_OVERRIDE_NO_EXT
 | 
			
		||||
    )# If not in the whitelist, add to be filtered out.
 | 
			
		||||
    )# If not in the allowlist, add to be filtered out.
 | 
			
		||||
      list(APPEND PYBIND11_TEST_FILTER ${test_name})
 | 
			
		||||
    endif()
 | 
			
		||||
  endforeach()
 | 
			
		||||
| 
						 | 
				
			
			@ -233,7 +235,10 @@ list(GET PYBIND11_EIGEN_VERSION_AND_HASH 1 PYBIND11_EIGEN_VERSION_HASH)
 | 
			
		|||
# Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but
 | 
			
		||||
# keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed"
 | 
			
		||||
# skip message).
 | 
			
		||||
list(FIND PYBIND11_TEST_FILES test_eigen.cpp PYBIND11_TEST_FILES_EIGEN_I)
 | 
			
		||||
list(FIND PYBIND11_TEST_FILES test_eigen_matrix.cpp PYBIND11_TEST_FILES_EIGEN_I)
 | 
			
		||||
if(PYBIND11_TEST_FILES_EIGEN_I EQUAL -1)
 | 
			
		||||
  list(FIND PYBIND11_TEST_FILES test_eigen_tensor.cpp PYBIND11_TEST_FILES_EIGEN_I)
 | 
			
		||||
endif()
 | 
			
		||||
if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
 | 
			
		||||
  # Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake).
 | 
			
		||||
  # Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also
 | 
			
		||||
| 
						 | 
				
			
			@ -288,13 +293,34 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
 | 
			
		|||
      set(EIGEN3_VERSION ${EIGEN3_VERSION_STRING})
 | 
			
		||||
    endif()
 | 
			
		||||
    message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}")
 | 
			
		||||
 | 
			
		||||
    if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0))
 | 
			
		||||
      tests_extra_targets("test_eigen_tensor.py" "eigen_tensor_avoid_stl_array")
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
  else()
 | 
			
		||||
    list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
 | 
			
		||||
    list(FIND PYBIND11_TEST_FILES test_eigen_matrix.cpp PYBIND11_TEST_FILES_EIGEN_I)
 | 
			
		||||
    if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
 | 
			
		||||
      list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
    list(FIND PYBIND11_TEST_FILES test_eigen_tensor.cpp PYBIND11_TEST_FILES_EIGEN_I)
 | 
			
		||||
    if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
 | 
			
		||||
      list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
 | 
			
		||||
    endif()
 | 
			
		||||
    message(
 | 
			
		||||
      STATUS "Building tests WITHOUT Eigen, use -DDOWNLOAD_EIGEN=ON on CMake 3.11+ to download")
 | 
			
		||||
  endif()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
# Some code doesn't support gcc 4
 | 
			
		||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
 | 
			
		||||
  list(FIND PYBIND11_TEST_FILES test_eigen_tensor.cpp PYBIND11_TEST_FILES_EIGEN_I)
 | 
			
		||||
  if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)
 | 
			
		||||
    list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I})
 | 
			
		||||
  endif()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
# Optional dependency for some tests (boost::variant is only supported with version >= 1.56)
 | 
			
		||||
find_package(Boost 1.56)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,13 +7,36 @@ Adds docstring and exceptions message sanitizers.
 | 
			
		|||
import contextlib
 | 
			
		||||
import difflib
 | 
			
		||||
import gc
 | 
			
		||||
import multiprocessing
 | 
			
		||||
import re
 | 
			
		||||
import sys
 | 
			
		||||
import textwrap
 | 
			
		||||
import traceback
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
# Early diagnostic for failed imports
 | 
			
		||||
import pybind11_tests
 | 
			
		||||
try:
 | 
			
		||||
    import pybind11_tests
 | 
			
		||||
except Exception:
 | 
			
		||||
    # pytest does not show the traceback without this.
 | 
			
		||||
    traceback.print_exc()
 | 
			
		||||
    raise
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(scope="session", autouse=True)
 | 
			
		||||
def use_multiprocessing_forkserver_on_linux():
 | 
			
		||||
    if sys.platform != "linux":
 | 
			
		||||
        # The default on Windows and macOS is "spawn": If it's not broken, don't fix it.
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    # Full background: https://github.com/pybind/pybind11/issues/4105#issuecomment-1301004592
 | 
			
		||||
    # In a nutshell: fork() after starting threads == flakiness in the form of deadlocks.
 | 
			
		||||
    # It is actually a well-known pitfall, unfortunately without guard rails.
 | 
			
		||||
    # "forkserver" is more performant than "spawn" (~9s vs ~13s for tests/test_gil_scoped.py,
 | 
			
		||||
    # visit the issuecomment link above for details).
 | 
			
		||||
    multiprocessing.set_start_method("forkserver")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_long_marker = re.compile(r"([0-9])L")
 | 
			
		||||
_hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
 | 
			
		||||
| 
						 | 
				
			
			@ -59,9 +82,8 @@ class Output:
 | 
			
		|||
        b = _strip_and_dedent(other).splitlines()
 | 
			
		||||
        if a == b:
 | 
			
		||||
            return True
 | 
			
		||||
        else:
 | 
			
		||||
            self.explanation = _make_explanation(a, b)
 | 
			
		||||
            return False
 | 
			
		||||
        self.explanation = _make_explanation(a, b)
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Unordered(Output):
 | 
			
		||||
| 
						 | 
				
			
			@ -72,9 +94,8 @@ class Unordered(Output):
 | 
			
		|||
        b = _split_and_sort(other)
 | 
			
		||||
        if a == b:
 | 
			
		||||
            return True
 | 
			
		||||
        else:
 | 
			
		||||
            self.explanation = _make_explanation(a, b)
 | 
			
		||||
            return False
 | 
			
		||||
        self.explanation = _make_explanation(a, b)
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Capture:
 | 
			
		||||
| 
						 | 
				
			
			@ -95,9 +116,8 @@ class Capture:
 | 
			
		|||
        b = other
 | 
			
		||||
        if a == b:
 | 
			
		||||
            return True
 | 
			
		||||
        else:
 | 
			
		||||
            self.explanation = a.explanation
 | 
			
		||||
            return False
 | 
			
		||||
        self.explanation = a.explanation
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return self.out
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +134,7 @@ class Capture:
 | 
			
		|||
        return Output(self.err)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
@pytest.fixture()
 | 
			
		||||
def capture(capsys):
 | 
			
		||||
    """Extended `capsys` with context manager and custom equality operators"""
 | 
			
		||||
    return Capture(capsys)
 | 
			
		||||
| 
						 | 
				
			
			@ -135,25 +155,22 @@ class SanitizedString:
 | 
			
		|||
        b = _strip_and_dedent(other)
 | 
			
		||||
        if a == b:
 | 
			
		||||
            return True
 | 
			
		||||
        else:
 | 
			
		||||
            self.explanation = _make_explanation(a.splitlines(), b.splitlines())
 | 
			
		||||
            return False
 | 
			
		||||
        self.explanation = _make_explanation(a.splitlines(), b.splitlines())
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _sanitize_general(s):
 | 
			
		||||
    s = s.strip()
 | 
			
		||||
    s = s.replace("pybind11_tests.", "m.")
 | 
			
		||||
    s = _long_marker.sub(r"\1", s)
 | 
			
		||||
    return s
 | 
			
		||||
    return _long_marker.sub(r"\1", s)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _sanitize_docstring(thing):
 | 
			
		||||
    s = thing.__doc__
 | 
			
		||||
    s = _sanitize_general(s)
 | 
			
		||||
    return s
 | 
			
		||||
    return _sanitize_general(s)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
@pytest.fixture()
 | 
			
		||||
def doc():
 | 
			
		||||
    """Sanitize docstrings and add custom failure explanation"""
 | 
			
		||||
    return SanitizedString(_sanitize_docstring)
 | 
			
		||||
| 
						 | 
				
			
			@ -162,30 +179,20 @@ def doc():
 | 
			
		|||
def _sanitize_message(thing):
 | 
			
		||||
    s = str(thing)
 | 
			
		||||
    s = _sanitize_general(s)
 | 
			
		||||
    s = _hexadecimal.sub("0", s)
 | 
			
		||||
    return s
 | 
			
		||||
    return _hexadecimal.sub("0", s)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
@pytest.fixture()
 | 
			
		||||
def msg():
 | 
			
		||||
    """Sanitize messages and add custom failure explanation"""
 | 
			
		||||
    return SanitizedString(_sanitize_message)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# noinspection PyUnusedLocal
 | 
			
		||||
def pytest_assertrepr_compare(op, left, right):
 | 
			
		||||
def pytest_assertrepr_compare(op, left, right):  # noqa: ARG001
 | 
			
		||||
    """Hook to insert custom failure explanation"""
 | 
			
		||||
    if hasattr(left, "explanation"):
 | 
			
		||||
        return left.explanation
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@contextlib.contextmanager
 | 
			
		||||
def suppress(exception):
 | 
			
		||||
    """Suppress the desired exception"""
 | 
			
		||||
    try:
 | 
			
		||||
        yield
 | 
			
		||||
    except exception:
 | 
			
		||||
        pass
 | 
			
		||||
    return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gc_collect():
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +203,7 @@ def gc_collect():
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def pytest_configure():
 | 
			
		||||
    pytest.suppress = suppress
 | 
			
		||||
    pytest.suppress = contextlib.suppress
 | 
			
		||||
    pytest.gc_collect = gc_collect
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -210,4 +217,5 @@ def pytest_report_header(config):
 | 
			
		|||
        f" {pybind11_tests.compiler_info}"
 | 
			
		||||
        f" {pybind11_tests.cpp_std}"
 | 
			
		||||
        f" {pybind11_tests.PYBIND11_INTERNALS_ID}"
 | 
			
		||||
        f" PYBIND11_SIMPLE_GIL_MANAGEMENT={pybind11_tests.PYBIND11_SIMPLE_GIL_MANAGEMENT}"
 | 
			
		||||
    )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,7 +115,7 @@ public:
 | 
			
		|||
#if defined(PYPY_VERSION)
 | 
			
		||||
        PyObject *globals = PyEval_GetGlobals();
 | 
			
		||||
        PyObject *result = PyRun_String("import gc\n"
 | 
			
		||||
                                        "for i in range(2):"
 | 
			
		||||
                                        "for i in range(2):\n"
 | 
			
		||||
                                        "    gc.collect()\n",
 | 
			
		||||
                                        Py_file_input,
 | 
			
		||||
                                        globals,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,9 +6,15 @@
 | 
			
		|||
    All rights reserved. Use of this source code is governed by a
 | 
			
		||||
    BSD-style license that can be found in the LICENSE file.
 | 
			
		||||
*/
 | 
			
		||||
#if defined(PYBIND11_INTERNALS_VERSION)
 | 
			
		||||
#    undef PYBIND11_INTERNALS_VERSION
 | 
			
		||||
#endif
 | 
			
		||||
#define PYBIND11_INTERNALS_VERSION 21814642 // Ensure this module has its own `internals` instance.
 | 
			
		||||
#include <pybind11/pybind11.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
// This file mimics a DSO that makes pybind11 calls but does not define a
 | 
			
		||||
// PYBIND11_MODULE. The purpose is to test that such a DSO can create a
 | 
			
		||||
| 
						 | 
				
			
			@ -21,8 +27,54 @@
 | 
			
		|||
namespace {
 | 
			
		||||
 | 
			
		||||
namespace py = pybind11;
 | 
			
		||||
 | 
			
		||||
void gil_acquire() { py::gil_scoped_acquire gil; }
 | 
			
		||||
 | 
			
		||||
std::string gil_multi_acquire_release(unsigned bits) {
 | 
			
		||||
    if ((bits & 0x1u) != 0u) {
 | 
			
		||||
        py::gil_scoped_acquire gil;
 | 
			
		||||
    }
 | 
			
		||||
    if ((bits & 0x2u) != 0u) {
 | 
			
		||||
        py::gil_scoped_release gil;
 | 
			
		||||
    }
 | 
			
		||||
    if ((bits & 0x4u) != 0u) {
 | 
			
		||||
        py::gil_scoped_acquire gil;
 | 
			
		||||
    }
 | 
			
		||||
    if ((bits & 0x8u) != 0u) {
 | 
			
		||||
        py::gil_scoped_release gil;
 | 
			
		||||
    }
 | 
			
		||||
    return PYBIND11_INTERNALS_ID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct CustomAutoGIL {
 | 
			
		||||
    CustomAutoGIL() : gstate(PyGILState_Ensure()) {}
 | 
			
		||||
    ~CustomAutoGIL() { PyGILState_Release(gstate); }
 | 
			
		||||
 | 
			
		||||
    PyGILState_STATE gstate;
 | 
			
		||||
};
 | 
			
		||||
struct CustomAutoNoGIL {
 | 
			
		||||
    CustomAutoNoGIL() : save(PyEval_SaveThread()) {}
 | 
			
		||||
    ~CustomAutoNoGIL() { PyEval_RestoreThread(save); }
 | 
			
		||||
 | 
			
		||||
    PyThreadState *save;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Acquire, typename Release>
 | 
			
		||||
void gil_acquire_inner() {
 | 
			
		||||
    Acquire acquire_outer;
 | 
			
		||||
    Acquire acquire_inner;
 | 
			
		||||
    Release release;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Acquire, typename Release>
 | 
			
		||||
void gil_acquire_nested() {
 | 
			
		||||
    Acquire acquire_outer;
 | 
			
		||||
    Acquire acquire_inner;
 | 
			
		||||
    Release release;
 | 
			
		||||
    auto thread = std::thread(&gil_acquire_inner<Acquire, Release>);
 | 
			
		||||
    thread.join();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr char kModuleName[] = "cross_module_gil_utils";
 | 
			
		||||
 | 
			
		||||
struct PyModuleDef moduledef = {
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +82,9 @@ struct PyModuleDef moduledef = {
 | 
			
		|||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
#define ADD_FUNCTION(Name, ...)                                                                   \
 | 
			
		||||
    PyModule_AddObject(m, Name, PyLong_FromVoidPtr(reinterpret_cast<void *>(&__VA_ARGS__)));
 | 
			
		||||
 | 
			
		||||
extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() {
 | 
			
		||||
 | 
			
		||||
    PyObject *m = PyModule_Create(&moduledef);
 | 
			
		||||
| 
						 | 
				
			
			@ -37,8 +92,16 @@ extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() {
 | 
			
		|||
    if (m != nullptr) {
 | 
			
		||||
        static_assert(sizeof(&gil_acquire) == sizeof(void *),
 | 
			
		||||
                      "Function pointer must have the same size as void*");
 | 
			
		||||
        PyModule_AddObject(
 | 
			
		||||
            m, "gil_acquire_funcaddr", PyLong_FromVoidPtr(reinterpret_cast<void *>(&gil_acquire)));
 | 
			
		||||
        ADD_FUNCTION("gil_acquire_funcaddr", gil_acquire)
 | 
			
		||||
        ADD_FUNCTION("gil_multi_acquire_release_funcaddr", gil_multi_acquire_release)
 | 
			
		||||
        ADD_FUNCTION("gil_acquire_inner_custom_funcaddr",
 | 
			
		||||
                     gil_acquire_inner<CustomAutoGIL, CustomAutoNoGIL>)
 | 
			
		||||
        ADD_FUNCTION("gil_acquire_nested_custom_funcaddr",
 | 
			
		||||
                     gil_acquire_nested<CustomAutoGIL, CustomAutoNoGIL>)
 | 
			
		||||
        ADD_FUNCTION("gil_acquire_inner_pybind11_funcaddr",
 | 
			
		||||
                     gil_acquire_inner<py::gil_scoped_acquire, py::gil_scoped_release>)
 | 
			
		||||
        ADD_FUNCTION("gil_acquire_nested_pybind11_funcaddr",
 | 
			
		||||
                     gil_acquire_nested<py::gil_scoped_acquire, py::gil_scoped_release>)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return m;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
/*
 | 
			
		||||
    tests/eigen_tensor.cpp -- automatic conversion of Eigen Tensor
 | 
			
		||||
 | 
			
		||||
    All rights reserved. Use of this source code is governed by a
 | 
			
		||||
    BSD-style license that can be found in the LICENSE file.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef EIGEN_AVOID_STL_ARRAY
 | 
			
		||||
#    define EIGEN_AVOID_STL_ARRAY
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "test_eigen_tensor.inl"
 | 
			
		||||
 | 
			
		||||
PYBIND11_MODULE(eigen_tensor_avoid_stl_array, m) { eigen_tensor_test::test_module(m); }
 | 
			
		||||
| 
						 | 
				
			
			@ -24,5 +24,4 @@ def deprecated_call():
 | 
			
		|||
    pytest_major_minor = (int(pieces[0]), int(pieces[1]))
 | 
			
		||||
    if pytest_major_minor < (3, 9):
 | 
			
		||||
        return pytest.warns((DeprecationWarning, PendingDeprecationWarning))
 | 
			
		||||
    else:
 | 
			
		||||
        return pytest.deprecated_call()
 | 
			
		||||
    return pytest.deprecated_call()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,16 @@ import zipfile
 | 
			
		|||
DIR = os.path.abspath(os.path.dirname(__file__))
 | 
			
		||||
MAIN_DIR = os.path.dirname(os.path.dirname(DIR))
 | 
			
		||||
 | 
			
		||||
PKGCONFIG = """\
 | 
			
		||||
prefix=${{pcfiledir}}/../../
 | 
			
		||||
includedir=${{prefix}}/include
 | 
			
		||||
 | 
			
		||||
Name: pybind11
 | 
			
		||||
Description: Seamless operability between C++11 and Python
 | 
			
		||||
Version: {VERSION}
 | 
			
		||||
Cflags: -I${{includedir}}
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
main_headers = {
 | 
			
		||||
    "include/pybind11/attr.h",
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +43,7 @@ main_headers = {
 | 
			
		|||
    "include/pybind11/pytypes.h",
 | 
			
		||||
    "include/pybind11/stl.h",
 | 
			
		||||
    "include/pybind11/stl_bind.h",
 | 
			
		||||
    "include/pybind11/type_caster_pyobject_ptr.h",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
detail_headers = {
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +56,12 @@ detail_headers = {
 | 
			
		|||
    "include/pybind11/detail/typeid.h",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
eigen_headers = {
 | 
			
		||||
    "include/pybind11/eigen/common.h",
 | 
			
		||||
    "include/pybind11/eigen/matrix.h",
 | 
			
		||||
    "include/pybind11/eigen/tensor.h",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
stl_headers = {
 | 
			
		||||
    "include/pybind11/stl/filesystem.h",
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -59,6 +76,10 @@ cmake_files = {
 | 
			
		|||
    "share/cmake/pybind11/pybind11Tools.cmake",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pkgconfig_files = {
 | 
			
		||||
    "share/pkgconfig/pybind11.pc",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_files = {
 | 
			
		||||
    "__init__.py",
 | 
			
		||||
    "__main__.py",
 | 
			
		||||
| 
						 | 
				
			
			@ -68,8 +89,8 @@ py_files = {
 | 
			
		|||
    "setup_helpers.py",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
headers = main_headers | detail_headers | stl_headers
 | 
			
		||||
src_files = headers | cmake_files
 | 
			
		||||
headers = main_headers | detail_headers | eigen_headers | stl_headers
 | 
			
		||||
src_files = headers | cmake_files | pkgconfig_files
 | 
			
		||||
all_files = src_files | py_files
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -78,10 +99,12 @@ sdist_files = {
 | 
			
		|||
    "pybind11/include",
 | 
			
		||||
    "pybind11/include/pybind11",
 | 
			
		||||
    "pybind11/include/pybind11/detail",
 | 
			
		||||
    "pybind11/include/pybind11/eigen",
 | 
			
		||||
    "pybind11/include/pybind11/stl",
 | 
			
		||||
    "pybind11/share",
 | 
			
		||||
    "pybind11/share/cmake",
 | 
			
		||||
    "pybind11/share/cmake/pybind11",
 | 
			
		||||
    "pybind11/share/pkgconfig",
 | 
			
		||||
    "pyproject.toml",
 | 
			
		||||
    "setup.cfg",
 | 
			
		||||
    "setup.py",
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +112,7 @@ sdist_files = {
 | 
			
		|||
    "MANIFEST.in",
 | 
			
		||||
    "README.rst",
 | 
			
		||||
    "PKG-INFO",
 | 
			
		||||
    "SECURITY.md",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local_sdist_files = {
 | 
			
		||||
| 
						 | 
				
			
			@ -101,22 +125,24 @@ local_sdist_files = {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_build_sdist(monkeypatch, tmpdir):
 | 
			
		||||
def read_tz_file(tar: tarfile.TarFile, name: str) -> bytes:
 | 
			
		||||
    start = tar.getnames()[0] + "/"
 | 
			
		||||
    inner_file = tar.extractfile(tar.getmember(f"{start}{name}"))
 | 
			
		||||
    assert inner_file
 | 
			
		||||
    with contextlib.closing(inner_file) as f:
 | 
			
		||||
        return f.read()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def normalize_line_endings(value: bytes) -> bytes:
 | 
			
		||||
    return value.replace(os.linesep.encode("utf-8"), b"\n")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_build_sdist(monkeypatch, tmpdir):
 | 
			
		||||
    monkeypatch.chdir(MAIN_DIR)
 | 
			
		||||
 | 
			
		||||
    out = subprocess.check_output(
 | 
			
		||||
        [
 | 
			
		||||
            sys.executable,
 | 
			
		||||
            "-m",
 | 
			
		||||
            "build",
 | 
			
		||||
            "--sdist",
 | 
			
		||||
            "--outdir",
 | 
			
		||||
            str(tmpdir),
 | 
			
		||||
        ]
 | 
			
		||||
    subprocess.run(
 | 
			
		||||
        [sys.executable, "-m", "build", "--sdist", f"--outdir={tmpdir}"], check=True
 | 
			
		||||
    )
 | 
			
		||||
    if hasattr(out, "decode"):
 | 
			
		||||
        out = out.decode()
 | 
			
		||||
 | 
			
		||||
    (sdist,) = tmpdir.visit("*.tar.gz")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -125,25 +151,17 @@ def test_build_sdist(monkeypatch, tmpdir):
 | 
			
		|||
        version = start[9:-1]
 | 
			
		||||
        simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
 | 
			
		||||
 | 
			
		||||
        with contextlib.closing(
 | 
			
		||||
            tar.extractfile(tar.getmember(start + "setup.py"))
 | 
			
		||||
        ) as f:
 | 
			
		||||
            setup_py = f.read()
 | 
			
		||||
        setup_py = read_tz_file(tar, "setup.py")
 | 
			
		||||
        pyproject_toml = read_tz_file(tar, "pyproject.toml")
 | 
			
		||||
        pkgconfig = read_tz_file(tar, "pybind11/share/pkgconfig/pybind11.pc")
 | 
			
		||||
        cmake_cfg = read_tz_file(
 | 
			
		||||
            tar, "pybind11/share/cmake/pybind11/pybind11Config.cmake"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        with contextlib.closing(
 | 
			
		||||
            tar.extractfile(tar.getmember(start + "pyproject.toml"))
 | 
			
		||||
        ) as f:
 | 
			
		||||
            pyproject_toml = f.read()
 | 
			
		||||
 | 
			
		||||
        with contextlib.closing(
 | 
			
		||||
            tar.extractfile(
 | 
			
		||||
                tar.getmember(
 | 
			
		||||
                    start + "pybind11/share/cmake/pybind11/pybind11Config.cmake"
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        ) as f:
 | 
			
		||||
            contents = f.read().decode("utf8")
 | 
			
		||||
        assert 'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")' in contents
 | 
			
		||||
    assert (
 | 
			
		||||
        'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")'
 | 
			
		||||
        in cmake_cfg.decode("utf-8")
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    files = {f"pybind11/{n}" for n in all_files}
 | 
			
		||||
    files |= sdist_files
 | 
			
		||||
| 
						 | 
				
			
			@ -154,9 +172,9 @@ def test_build_sdist(monkeypatch, tmpdir):
 | 
			
		|||
 | 
			
		||||
    with open(os.path.join(MAIN_DIR, "tools", "setup_main.py.in"), "rb") as f:
 | 
			
		||||
        contents = (
 | 
			
		||||
            string.Template(f.read().decode())
 | 
			
		||||
            string.Template(f.read().decode("utf-8"))
 | 
			
		||||
            .substitute(version=version, extra_cmd="")
 | 
			
		||||
            .encode()
 | 
			
		||||
            .encode("utf-8")
 | 
			
		||||
        )
 | 
			
		||||
    assert setup_py == contents
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -164,25 +182,18 @@ def test_build_sdist(monkeypatch, tmpdir):
 | 
			
		|||
        contents = f.read()
 | 
			
		||||
    assert pyproject_toml == contents
 | 
			
		||||
 | 
			
		||||
    simple_version = ".".join(version.split(".")[:3])
 | 
			
		||||
    pkgconfig_expected = PKGCONFIG.format(VERSION=simple_version).encode("utf-8")
 | 
			
		||||
    assert normalize_line_endings(pkgconfig) == pkgconfig_expected
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_build_global_dist(monkeypatch, tmpdir):
 | 
			
		||||
 | 
			
		||||
    monkeypatch.chdir(MAIN_DIR)
 | 
			
		||||
    monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
 | 
			
		||||
    out = subprocess.check_output(
 | 
			
		||||
        [
 | 
			
		||||
            sys.executable,
 | 
			
		||||
            "-m",
 | 
			
		||||
            "build",
 | 
			
		||||
            "--sdist",
 | 
			
		||||
            "--outdir",
 | 
			
		||||
            str(tmpdir),
 | 
			
		||||
        ]
 | 
			
		||||
    subprocess.run(
 | 
			
		||||
        [sys.executable, "-m", "build", "--sdist", "--outdir", str(tmpdir)], check=True
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    if hasattr(out, "decode"):
 | 
			
		||||
        out = out.decode()
 | 
			
		||||
 | 
			
		||||
    (sdist,) = tmpdir.visit("*.tar.gz")
 | 
			
		||||
 | 
			
		||||
    with tarfile.open(str(sdist), "r:gz") as tar:
 | 
			
		||||
| 
						 | 
				
			
			@ -190,15 +201,17 @@ def test_build_global_dist(monkeypatch, tmpdir):
 | 
			
		|||
        version = start[16:-1]
 | 
			
		||||
        simpler = {n.split("/", 1)[-1] for n in tar.getnames()[1:]}
 | 
			
		||||
 | 
			
		||||
        with contextlib.closing(
 | 
			
		||||
            tar.extractfile(tar.getmember(start + "setup.py"))
 | 
			
		||||
        ) as f:
 | 
			
		||||
            setup_py = f.read()
 | 
			
		||||
        setup_py = read_tz_file(tar, "setup.py")
 | 
			
		||||
        pyproject_toml = read_tz_file(tar, "pyproject.toml")
 | 
			
		||||
        pkgconfig = read_tz_file(tar, "pybind11/share/pkgconfig/pybind11.pc")
 | 
			
		||||
        cmake_cfg = read_tz_file(
 | 
			
		||||
            tar, "pybind11/share/cmake/pybind11/pybind11Config.cmake"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        with contextlib.closing(
 | 
			
		||||
            tar.extractfile(tar.getmember(start + "pyproject.toml"))
 | 
			
		||||
        ) as f:
 | 
			
		||||
            pyproject_toml = f.read()
 | 
			
		||||
    assert (
 | 
			
		||||
        'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")'
 | 
			
		||||
        in cmake_cfg.decode("utf-8")
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    files = {f"pybind11/{n}" for n in all_files}
 | 
			
		||||
    files |= sdist_files
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +222,7 @@ def test_build_global_dist(monkeypatch, tmpdir):
 | 
			
		|||
        contents = (
 | 
			
		||||
            string.Template(f.read().decode())
 | 
			
		||||
            .substitute(version=version, extra_cmd="")
 | 
			
		||||
            .encode()
 | 
			
		||||
            .encode("utf-8")
 | 
			
		||||
        )
 | 
			
		||||
        assert setup_py == contents
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -217,12 +230,16 @@ def test_build_global_dist(monkeypatch, tmpdir):
 | 
			
		|||
        contents = f.read()
 | 
			
		||||
        assert pyproject_toml == contents
 | 
			
		||||
 | 
			
		||||
    simple_version = ".".join(version.split(".")[:3])
 | 
			
		||||
    pkgconfig_expected = PKGCONFIG.format(VERSION=simple_version).encode("utf-8")
 | 
			
		||||
    assert normalize_line_endings(pkgconfig) == pkgconfig_expected
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def tests_build_wheel(monkeypatch, tmpdir):
 | 
			
		||||
    monkeypatch.chdir(MAIN_DIR)
 | 
			
		||||
 | 
			
		||||
    subprocess.check_output(
 | 
			
		||||
        [sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)]
 | 
			
		||||
    subprocess.run(
 | 
			
		||||
        [sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)], check=True
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    (wheel,) = tmpdir.visit("*.whl")
 | 
			
		||||
| 
						 | 
				
			
			@ -249,8 +266,8 @@ def tests_build_global_wheel(monkeypatch, tmpdir):
 | 
			
		|||
    monkeypatch.chdir(MAIN_DIR)
 | 
			
		||||
    monkeypatch.setenv("PYBIND11_GLOBAL_SDIST", "1")
 | 
			
		||||
 | 
			
		||||
    subprocess.check_output(
 | 
			
		||||
        [sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)]
 | 
			
		||||
    subprocess.run(
 | 
			
		||||
        [sys.executable, "-m", "pip", "wheel", ".", "-w", str(tmpdir)], check=True
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    (wheel,) = tmpdir.visit("*.whl")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,6 +89,12 @@ PYBIND11_MODULE(pybind11_tests, m) {
 | 
			
		|||
#endif
 | 
			
		||||
    m.attr("cpp_std") = cpp_std();
 | 
			
		||||
    m.attr("PYBIND11_INTERNALS_ID") = PYBIND11_INTERNALS_ID;
 | 
			
		||||
    m.attr("PYBIND11_SIMPLE_GIL_MANAGEMENT") =
 | 
			
		||||
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
 | 
			
		||||
        true;
 | 
			
		||||
#else
 | 
			
		||||
        false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    bind_ConstructorStats(m);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,4 +6,4 @@ numpy==1.22.2; platform_python_implementation!="PyPy" and python_version>="3.10"
 | 
			
		|||
pytest==7.0.0
 | 
			
		||||
pytest-timeout
 | 
			
		||||
scipy==1.5.4; platform_python_implementation!="PyPy" and python_version<"3.10"
 | 
			
		||||
scipy==1.8.0; platform_python_implementation!="PyPy" and python_version=="3.10"
 | 
			
		||||
scipy==1.10.0; platform_python_implementation!="PyPy" and python_version=="3.10"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ asyncio = pytest.importorskip("asyncio")
 | 
			
		|||
m = pytest.importorskip("pybind11_tests.async_module")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
@pytest.fixture()
 | 
			
		||||
def event_loop():
 | 
			
		||||
    loop = asyncio.new_event_loop()
 | 
			
		||||
    yield loop
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ async def get_await_result(x):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def test_await(event_loop):
 | 
			
		||||
    assert 5 == event_loop.run_until_complete(get_await_result(m.SupportsAsync()))
 | 
			
		||||
    assert event_loop.run_until_complete(get_await_result(m.SupportsAsync())) == 5
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_await_missing(event_loop):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,12 +7,47 @@
 | 
			
		|||
    BSD-style license that can be found in the LICENSE file.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <pybind11/complex.h>
 | 
			
		||||
#include <pybind11/stl.h>
 | 
			
		||||
 | 
			
		||||
#include "constructor_stats.h"
 | 
			
		||||
#include "pybind11_tests.h"
 | 
			
		||||
 | 
			
		||||
TEST_SUBMODULE(buffers, m) {
 | 
			
		||||
    m.attr("long_double_and_double_have_same_size") = (sizeof(long double) == sizeof(double));
 | 
			
		||||
 | 
			
		||||
    m.def("format_descriptor_format_buffer_info_equiv",
 | 
			
		||||
          [](const std::string &cpp_name, const py::buffer &buffer) {
 | 
			
		||||
              // https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
 | 
			
		||||
              static auto *format_table = new std::map<std::string, std::string>;
 | 
			
		||||
              static auto *equiv_table
 | 
			
		||||
                  = new std::map<std::string, bool (py::buffer_info::*)() const>;
 | 
			
		||||
              if (format_table->empty()) {
 | 
			
		||||
#define PYBIND11_ASSIGN_HELPER(...)                                                               \
 | 
			
		||||
    (*format_table)[#__VA_ARGS__] = py::format_descriptor<__VA_ARGS__>::format();                 \
 | 
			
		||||
    (*equiv_table)[#__VA_ARGS__] = &py::buffer_info::item_type_is_equivalent_to<__VA_ARGS__>;
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(PyObject *)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(bool)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(std::int8_t)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(std::uint8_t)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(std::int16_t)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(std::uint16_t)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(std::int32_t)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(std::uint32_t)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(std::int64_t)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(std::uint64_t)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(float)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(double)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(long double)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(std::complex<float>)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(std::complex<double>)
 | 
			
		||||
                  PYBIND11_ASSIGN_HELPER(std::complex<long double>)
 | 
			
		||||
#undef PYBIND11_ASSIGN_HELPER
 | 
			
		||||
              }
 | 
			
		||||
              return std::pair<std::string, bool>(
 | 
			
		||||
                  (*format_table)[cpp_name], (buffer.request().*((*equiv_table)[cpp_name]))());
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
    // test_from_python / test_to_python:
 | 
			
		||||
    class Matrix {
 | 
			
		||||
    public:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,63 @@ from pybind11_tests import buffers as m
 | 
			
		|||
 | 
			
		||||
np = pytest.importorskip("numpy")
 | 
			
		||||
 | 
			
		||||
if m.long_double_and_double_have_same_size:
 | 
			
		||||
    # Determined by the compiler used to build the pybind11 tests
 | 
			
		||||
    # (e.g. MSVC gets here, but MinGW might not).
 | 
			
		||||
    np_float128 = None
 | 
			
		||||
    np_complex256 = None
 | 
			
		||||
else:
 | 
			
		||||
    # Determined by the compiler used to build numpy (e.g. MinGW).
 | 
			
		||||
    np_float128 = getattr(np, *["float128"] * 2)
 | 
			
		||||
    np_complex256 = getattr(np, *["complex256"] * 2)
 | 
			
		||||
 | 
			
		||||
CPP_NAME_FORMAT_NP_DTYPE_TABLE = [
 | 
			
		||||
    ("PyObject *", "O", object),
 | 
			
		||||
    ("bool", "?", np.bool_),
 | 
			
		||||
    ("std::int8_t", "b", np.int8),
 | 
			
		||||
    ("std::uint8_t", "B", np.uint8),
 | 
			
		||||
    ("std::int16_t", "h", np.int16),
 | 
			
		||||
    ("std::uint16_t", "H", np.uint16),
 | 
			
		||||
    ("std::int32_t", "i", np.int32),
 | 
			
		||||
    ("std::uint32_t", "I", np.uint32),
 | 
			
		||||
    ("std::int64_t", "q", np.int64),
 | 
			
		||||
    ("std::uint64_t", "Q", np.uint64),
 | 
			
		||||
    ("float", "f", np.float32),
 | 
			
		||||
    ("double", "d", np.float64),
 | 
			
		||||
    ("long double", "g", np_float128),
 | 
			
		||||
    ("std::complex<float>", "Zf", np.complex64),
 | 
			
		||||
    ("std::complex<double>", "Zd", np.complex128),
 | 
			
		||||
    ("std::complex<long double>", "Zg", np_complex256),
 | 
			
		||||
]
 | 
			
		||||
CPP_NAME_FORMAT_TABLE = [
 | 
			
		||||
    (cpp_name, format)
 | 
			
		||||
    for cpp_name, format, np_dtype in CPP_NAME_FORMAT_NP_DTYPE_TABLE
 | 
			
		||||
    if np_dtype is not None
 | 
			
		||||
]
 | 
			
		||||
CPP_NAME_NP_DTYPE_TABLE = [
 | 
			
		||||
    (cpp_name, np_dtype) for cpp_name, _, np_dtype in CPP_NAME_FORMAT_NP_DTYPE_TABLE
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize(("cpp_name", "np_dtype"), CPP_NAME_NP_DTYPE_TABLE)
 | 
			
		||||
def test_format_descriptor_format_buffer_info_equiv(cpp_name, np_dtype):
 | 
			
		||||
    if np_dtype is None:
 | 
			
		||||
        pytest.skip(
 | 
			
		||||
            f"cpp_name=`{cpp_name}`: `long double` and `double` have same size."
 | 
			
		||||
        )
 | 
			
		||||
    if isinstance(np_dtype, str):
 | 
			
		||||
        pytest.skip(f"np.{np_dtype} does not exist.")
 | 
			
		||||
    np_array = np.array([], dtype=np_dtype)
 | 
			
		||||
    for other_cpp_name, expected_format in CPP_NAME_FORMAT_TABLE:
 | 
			
		||||
        format, np_array_is_matching = m.format_descriptor_format_buffer_info_equiv(
 | 
			
		||||
            other_cpp_name, np_array
 | 
			
		||||
        )
 | 
			
		||||
        assert format == expected_format
 | 
			
		||||
        if other_cpp_name == cpp_name:
 | 
			
		||||
            assert np_array_is_matching
 | 
			
		||||
        else:
 | 
			
		||||
            assert not np_array_is_matching
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_from_python():
 | 
			
		||||
    with pytest.raises(RuntimeError) as excinfo:
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +111,8 @@ def test_to_python():
 | 
			
		|||
    mat2 = np.array(mat, copy=False)
 | 
			
		||||
    assert mat2.shape == (5, 4)
 | 
			
		||||
    assert abs(mat2).sum() == 11
 | 
			
		||||
    assert mat2[2, 3] == 4 and mat2[3, 2] == 7
 | 
			
		||||
    assert mat2[2, 3] == 4
 | 
			
		||||
    assert mat2[3, 2] == 7
 | 
			
		||||
    mat2[2, 3] = 5
 | 
			
		||||
    assert mat2[2, 3] == 5
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,6 +73,9 @@ PYBIND11_NAMESPACE_END(detail)
 | 
			
		|||
PYBIND11_NAMESPACE_END(pybind11)
 | 
			
		||||
 | 
			
		||||
TEST_SUBMODULE(builtin_casters, m) {
 | 
			
		||||
    PYBIND11_WARNING_PUSH
 | 
			
		||||
    PYBIND11_WARNING_DISABLE_MSVC(4127)
 | 
			
		||||
 | 
			
		||||
    // test_simple_string
 | 
			
		||||
    m.def("string_roundtrip", [](const char *s) { return s; });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +89,7 @@ TEST_SUBMODULE(builtin_casters, m) {
 | 
			
		|||
    std::wstring wstr;
 | 
			
		||||
    wstr.push_back(0x61);   // a
 | 
			
		||||
    wstr.push_back(0x2e18); // ⸘
 | 
			
		||||
    if (PYBIND11_SILENCE_MSVC_C4127(sizeof(wchar_t) == 2)) {
 | 
			
		||||
    if (sizeof(wchar_t) == 2) {
 | 
			
		||||
        wstr.push_back(mathbfA16_1);
 | 
			
		||||
        wstr.push_back(mathbfA16_2);
 | 
			
		||||
    } // 𝐀, utf16
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +116,7 @@ TEST_SUBMODULE(builtin_casters, m) {
 | 
			
		|||
    // Under Python 2.7, invalid unicode UTF-32 characters didn't appear to trigger
 | 
			
		||||
    // UnicodeDecodeError
 | 
			
		||||
    m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
 | 
			
		||||
    if (PYBIND11_SILENCE_MSVC_C4127(sizeof(wchar_t) == 2)) {
 | 
			
		||||
    if (sizeof(wchar_t) == 2) {
 | 
			
		||||
        m.def("bad_wchar_string", [=]() {
 | 
			
		||||
            return std::wstring({wchar_t(0x61), wchar_t(0xd800)});
 | 
			
		||||
        });
 | 
			
		||||
| 
						 | 
				
			
			@ -266,9 +269,14 @@ TEST_SUBMODULE(builtin_casters, m) {
 | 
			
		|||
    });
 | 
			
		||||
    m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
 | 
			
		||||
 | 
			
		||||
    static std::pair<int, std::string> int_string_pair{2, "items"};
 | 
			
		||||
    m.def(
 | 
			
		||||
        "int_string_pair", []() { return &int_string_pair; }, py::return_value_policy::reference);
 | 
			
		||||
        "int_string_pair",
 | 
			
		||||
        []() {
 | 
			
		||||
            // Using no-destructor idiom to side-step warnings from overzealous compilers.
 | 
			
		||||
            static auto *int_string_pair = new std::pair<int, std::string>{2, "items"};
 | 
			
		||||
            return int_string_pair;
 | 
			
		||||
        },
 | 
			
		||||
        py::return_value_policy::reference);
 | 
			
		||||
 | 
			
		||||
    // test_builtins_cast_return_none
 | 
			
		||||
    m.def("return_none_string", []() -> std::string * { return nullptr; });
 | 
			
		||||
| 
						 | 
				
			
			@ -379,4 +387,6 @@ TEST_SUBMODULE(builtin_casters, m) {
 | 
			
		|||
    m.def("takes_const_ref", [](const ConstRefCasted &x) { return x.tag; });
 | 
			
		||||
    m.def("takes_const_ref_wrap",
 | 
			
		||||
          [](std::reference_wrapper<const ConstRefCasted> x) { return x.get().tag; });
 | 
			
		||||
 | 
			
		||||
    PYBIND11_WARNING_POP
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -126,8 +126,8 @@ def test_bytes_to_string():
 | 
			
		|||
 | 
			
		||||
    assert m.strlen(b"hi") == 2
 | 
			
		||||
    assert m.string_length(b"world") == 5
 | 
			
		||||
    assert m.string_length("a\x00b".encode()) == 3
 | 
			
		||||
    assert m.strlen("a\x00b".encode()) == 1  # C-string limitation
 | 
			
		||||
    assert m.string_length(b"a\x00b") == 3
 | 
			
		||||
    assert m.strlen(b"a\x00b") == 1  # C-string limitation
 | 
			
		||||
 | 
			
		||||
    # passing in a utf8 encoded string should work
 | 
			
		||||
    assert m.string_length("💩".encode()) == 4
 | 
			
		||||
| 
						 | 
				
			
			@ -421,13 +421,15 @@ def test_reference_wrapper():
 | 
			
		|||
    a2 = m.refwrap_list(copy=True)
 | 
			
		||||
    assert [x.value for x in a1] == [2, 3]
 | 
			
		||||
    assert [x.value for x in a2] == [2, 3]
 | 
			
		||||
    assert not a1[0] is a2[0] and not a1[1] is a2[1]
 | 
			
		||||
    assert a1[0] is not a2[0]
 | 
			
		||||
    assert a1[1] is not a2[1]
 | 
			
		||||
 | 
			
		||||
    b1 = m.refwrap_list(copy=False)
 | 
			
		||||
    b2 = m.refwrap_list(copy=False)
 | 
			
		||||
    assert [x.value for x in b1] == [1, 2]
 | 
			
		||||
    assert [x.value for x in b2] == [1, 2]
 | 
			
		||||
    assert b1[0] is b2[0] and b1[1] is b2[1]
 | 
			
		||||
    assert b1[0] is b2[0]
 | 
			
		||||
    assert b1[1] is b2[1]
 | 
			
		||||
 | 
			
		||||
    assert m.refwrap_iiw(IncType(5)) == 5
 | 
			
		||||
    assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -240,4 +240,41 @@ TEST_SUBMODULE(callbacks, m) {
 | 
			
		|||
            f();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    auto *custom_def = []() {
 | 
			
		||||
        static PyMethodDef def;
 | 
			
		||||
        def.ml_name = "example_name";
 | 
			
		||||
        def.ml_doc = "Example doc";
 | 
			
		||||
        def.ml_meth = [](PyObject *, PyObject *args) -> PyObject * {
 | 
			
		||||
            if (PyTuple_Size(args) != 1) {
 | 
			
		||||
                throw std::runtime_error("Invalid number of arguments for example_name");
 | 
			
		||||
            }
 | 
			
		||||
            PyObject *first = PyTuple_GetItem(args, 0);
 | 
			
		||||
            if (!PyLong_Check(first)) {
 | 
			
		||||
                throw std::runtime_error("Invalid argument to example_name");
 | 
			
		||||
            }
 | 
			
		||||
            auto result = py::cast(PyLong_AsLong(first) * 9);
 | 
			
		||||
            return result.release().ptr();
 | 
			
		||||
        };
 | 
			
		||||
        def.ml_flags = METH_VARARGS;
 | 
			
		||||
        return &def;
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    // rec_capsule with name that has the same value (but not pointer) as our internal one
 | 
			
		||||
    // This capsule should be detected by our code as foreign and not inspected as the pointers
 | 
			
		||||
    // shouldn't match
 | 
			
		||||
    constexpr const char *rec_capsule_name
 | 
			
		||||
        = pybind11::detail::internals_function_record_capsule_name;
 | 
			
		||||
    py::capsule rec_capsule(std::malloc(1), [](void *data) { std::free(data); });
 | 
			
		||||
    rec_capsule.set_name(rec_capsule_name);
 | 
			
		||||
    m.add_object("custom_function", PyCFunction_New(custom_def, rec_capsule.ptr()));
 | 
			
		||||
 | 
			
		||||
    // This test requires a new ABI version to pass
 | 
			
		||||
#if PYBIND11_INTERNALS_VERSION > 4
 | 
			
		||||
    // rec_capsule with nullptr name
 | 
			
		||||
    py::capsule rec_capsule2(std::malloc(1), [](void *data) { std::free(data); });
 | 
			
		||||
    m.add_object("custom_function2", PyCFunction_New(custom_def, rec_capsule2.ptr()));
 | 
			
		||||
#else
 | 
			
		||||
    m.add_object("custom_function2", py::none());
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ import pytest
 | 
			
		|||
 | 
			
		||||
import env  # noqa: F401
 | 
			
		||||
from pybind11_tests import callbacks as m
 | 
			
		||||
from pybind11_tests import detailed_error_messages_enabled
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_callbacks():
 | 
			
		||||
| 
						 | 
				
			
			@ -70,11 +71,20 @@ def test_keyword_args_and_generalized_unpacking():
 | 
			
		|||
 | 
			
		||||
    with pytest.raises(RuntimeError) as excinfo:
 | 
			
		||||
        m.test_arg_conversion_error1(f)
 | 
			
		||||
    assert "Unable to convert call argument" in str(excinfo.value)
 | 
			
		||||
    assert str(excinfo.value) == "Unable to convert call argument " + (
 | 
			
		||||
        "'1' of type 'UnregisteredType' to Python object"
 | 
			
		||||
        if detailed_error_messages_enabled
 | 
			
		||||
        else "'1' to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    with pytest.raises(RuntimeError) as excinfo:
 | 
			
		||||
        m.test_arg_conversion_error2(f)
 | 
			
		||||
    assert "Unable to convert call argument" in str(excinfo.value)
 | 
			
		||||
    assert str(excinfo.value) == "Unable to convert call argument " + (
 | 
			
		||||
        "'expected_name' of type 'UnregisteredType' to Python object"
 | 
			
		||||
        if detailed_error_messages_enabled
 | 
			
		||||
        else "'expected_name' to Python object "
 | 
			
		||||
        "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_lambda_closure_cleanup():
 | 
			
		||||
| 
						 | 
				
			
			@ -193,3 +203,16 @@ def test_callback_num_times():
 | 
			
		|||
    if len(rates) > 1:
 | 
			
		||||
        print("Min    Mean   Max")
 | 
			
		||||
        print(f"{min(rates):6.3f} {sum(rates) / len(rates):6.3f} {max(rates):6.3f}")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_custom_func():
 | 
			
		||||
    assert m.custom_function(4) == 36
 | 
			
		||||
    assert m.roundtrip(m.custom_function)(4) == 36
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.skipif(
 | 
			
		||||
    m.custom_function2 is None, reason="Current PYBIND11_INTERNALS_VERSION too low"
 | 
			
		||||
)
 | 
			
		||||
def test_custom_func2():
 | 
			
		||||
    assert m.custom_function2(3) == 27
 | 
			
		||||
    assert m.roundtrip(m.custom_function2)(3) == 27
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,6 @@ from pybind11_tests import chrono as m
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def test_chrono_system_clock():
 | 
			
		||||
 | 
			
		||||
    # Get the time from both c++ and datetime
 | 
			
		||||
    date0 = datetime.datetime.today()
 | 
			
		||||
    date1 = m.test_chrono1()
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +121,6 @@ def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def test_chrono_duration_roundtrip():
 | 
			
		||||
 | 
			
		||||
    # Get the difference between two times (a timedelta)
 | 
			
		||||
    date1 = datetime.datetime.today()
 | 
			
		||||
    date2 = datetime.datetime.today()
 | 
			
		||||
| 
						 | 
				
			
			@ -143,7 +141,6 @@ def test_chrono_duration_roundtrip():
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def test_chrono_duration_subtraction_equivalence():
 | 
			
		||||
 | 
			
		||||
    date1 = datetime.datetime.today()
 | 
			
		||||
    date2 = datetime.datetime.today()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +151,6 @@ def test_chrono_duration_subtraction_equivalence():
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def test_chrono_duration_subtraction_equivalence_date():
 | 
			
		||||
 | 
			
		||||
    date1 = datetime.date.today()
 | 
			
		||||
    date2 = datetime.date.today()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,10 +22,8 @@
 | 
			
		|||
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#    pragma warning(disable : 4324)
 | 
			
		||||
PYBIND11_WARNING_DISABLE_MSVC(4324)
 | 
			
		||||
//     warning C4324: structure was padded due to alignment specifier
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// test_brace_initialization
 | 
			
		||||
struct NoBraceInitialization {
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +34,29 @@ struct NoBraceInitialization {
 | 
			
		|||
    std::vector<int> vec;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace test_class {
 | 
			
		||||
namespace pr4220_tripped_over_this { // PR #4227
 | 
			
		||||
 | 
			
		||||
template <int>
 | 
			
		||||
struct SoEmpty {};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
std::string get_msg(const T &) {
 | 
			
		||||
    return "This is really only meant to exercise successful compilation.";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
using Empty0 = SoEmpty<0x0>;
 | 
			
		||||
 | 
			
		||||
void bind_empty0(py::module_ &m) {
 | 
			
		||||
    py::class_<Empty0>(m, "Empty0").def(py::init<>()).def("get_msg", get_msg<Empty0>);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace pr4220_tripped_over_this
 | 
			
		||||
} // namespace test_class
 | 
			
		||||
 | 
			
		||||
TEST_SUBMODULE(class_, m) {
 | 
			
		||||
    m.def("obj_class_name", [](py::handle obj) { return py::detail::obj_class_name(obj.ptr()); });
 | 
			
		||||
 | 
			
		||||
    // test_instance
 | 
			
		||||
    struct NoConstructor {
 | 
			
		||||
        NoConstructor() = default;
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +85,7 @@ TEST_SUBMODULE(class_, m) {
 | 
			
		|||
        .def_static("new_instance", &NoConstructor::new_instance, "Return an instance");
 | 
			
		||||
 | 
			
		||||
    py::class_<NoConstructorNew>(m, "NoConstructorNew")
 | 
			
		||||
        .def(py::init([](const NoConstructorNew &self) { return self; })) // Need a NOOP __init__
 | 
			
		||||
        .def(py::init([]() { return nullptr; })) // Need a NOOP __init__
 | 
			
		||||
        .def_static("__new__",
 | 
			
		||||
                    [](const py::object &) { return NoConstructorNew::new_instance(); });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -364,6 +384,8 @@ TEST_SUBMODULE(class_, m) {
 | 
			
		|||
 | 
			
		||||
    protected:
 | 
			
		||||
        virtual int foo() const { return value; }
 | 
			
		||||
        virtual void *void_foo() { return static_cast<void *>(&value); }
 | 
			
		||||
        virtual void *get_self() { return static_cast<void *>(this); }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        int value = 42;
 | 
			
		||||
| 
						 | 
				
			
			@ -372,6 +394,8 @@ TEST_SUBMODULE(class_, m) {
 | 
			
		|||
    class TrampolineB : public ProtectedB {
 | 
			
		||||
    public:
 | 
			
		||||
        int foo() const override { PYBIND11_OVERRIDE(int, ProtectedB, foo, ); }
 | 
			
		||||
        void *void_foo() override { PYBIND11_OVERRIDE(void *, ProtectedB, void_foo, ); }
 | 
			
		||||
        void *get_self() override { PYBIND11_OVERRIDE(void *, ProtectedB, get_self, ); }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class PublicistB : public ProtectedB {
 | 
			
		||||
| 
						 | 
				
			
			@ -381,11 +405,23 @@ TEST_SUBMODULE(class_, m) {
 | 
			
		|||
        // (in Debug builds only, tested with icpc (ICC) 2021.1 Beta 20200827)
 | 
			
		||||
        ~PublicistB() override{}; // NOLINT(modernize-use-equals-default)
 | 
			
		||||
        using ProtectedB::foo;
 | 
			
		||||
        using ProtectedB::get_self;
 | 
			
		||||
        using ProtectedB::void_foo;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    m.def("read_foo", [](const void *original) {
 | 
			
		||||
        const int *ptr = reinterpret_cast<const int *>(original);
 | 
			
		||||
        return *ptr;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    m.def("pointers_equal",
 | 
			
		||||
          [](const void *original, const void *comparison) { return original == comparison; });
 | 
			
		||||
 | 
			
		||||
    py::class_<ProtectedB, TrampolineB>(m, "ProtectedB")
 | 
			
		||||
        .def(py::init<>())
 | 
			
		||||
        .def("foo", &PublicistB::foo);
 | 
			
		||||
        .def("foo", &PublicistB::foo)
 | 
			
		||||
        .def("void_foo", &PublicistB::void_foo)
 | 
			
		||||
        .def("get_self", &PublicistB::get_self);
 | 
			
		||||
 | 
			
		||||
    // test_brace_initialization
 | 
			
		||||
    struct BraceInitialization {
 | 
			
		||||
| 
						 | 
				
			
			@ -517,6 +553,8 @@ TEST_SUBMODULE(class_, m) {
 | 
			
		|||
        py::class_<OtherDuplicateNested>(gt, "OtherDuplicateNested");
 | 
			
		||||
        py::class_<OtherDuplicateNested>(gt, "YetAnotherDuplicateNested");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test_class::pr4220_tripped_over_this::bind_empty0(m);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <int N>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,16 @@
 | 
			
		|||
import pytest
 | 
			
		||||
 | 
			
		||||
import env  # noqa: F401
 | 
			
		||||
import env
 | 
			
		||||
from pybind11_tests import ConstructorStats, UserType
 | 
			
		||||
from pybind11_tests import class_ as m
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_obj_class_name():
 | 
			
		||||
    expected_name = "UserType" if env.PYPY else "pybind11_tests.UserType"
 | 
			
		||||
    assert m.obj_class_name(UserType(1)) == expected_name
 | 
			
		||||
    assert m.obj_class_name(UserType) == expected_name
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_repr():
 | 
			
		||||
    assert "pybind11_type" in repr(type(UserType))
 | 
			
		||||
    assert "UserType" in repr(UserType)
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +29,7 @@ def test_instance(msg):
 | 
			
		|||
    assert cstats.alive() == 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_instance_new(msg):
 | 
			
		||||
def test_instance_new():
 | 
			
		||||
    instance = m.NoConstructorNew()  # .__new__(m.NoConstructor.__class__)
 | 
			
		||||
    cstats = ConstructorStats.get(m.NoConstructorNew)
 | 
			
		||||
    assert cstats.alive() == 1
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +182,6 @@ def test_inheritance(msg):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def test_inheritance_init(msg):
 | 
			
		||||
 | 
			
		||||
    # Single base
 | 
			
		||||
    class Python(m.Pet):
 | 
			
		||||
        def __init__(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -213,7 +218,7 @@ def test_automatic_upcasting():
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def test_isinstance():
 | 
			
		||||
    objects = [tuple(), dict(), m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4
 | 
			
		||||
    objects = [(), {}, m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4
 | 
			
		||||
    expected = (True, True, True, True, True, False, False)
 | 
			
		||||
    assert m.check_instances(objects) == expected
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -313,6 +318,8 @@ def test_bind_protected_functions():
 | 
			
		|||
 | 
			
		||||
    b = m.ProtectedB()
 | 
			
		||||
    assert b.foo() == 42
 | 
			
		||||
    assert m.read_foo(b.void_foo()) == 42
 | 
			
		||||
    assert m.pointers_equal(b.get_self(), b)
 | 
			
		||||
 | 
			
		||||
    class C(m.ProtectedB):
 | 
			
		||||
        def __init__(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -417,7 +424,7 @@ def test_exception_rvalue_abort():
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
# https://github.com/pybind/pybind11/issues/1568
 | 
			
		||||
def test_multiple_instances_with_same_pointer(capture):
 | 
			
		||||
def test_multiple_instances_with_same_pointer():
 | 
			
		||||
    n = 100
 | 
			
		||||
    instances = [m.SamePointer() for _ in range(n)]
 | 
			
		||||
    for i in range(n):
 | 
			
		||||
| 
						 | 
				
			
			@ -469,3 +476,10 @@ def test_register_duplicate_class():
 | 
			
		|||
        m.register_duplicate_nested_class_type(ClassScope)
 | 
			
		||||
    expected = 'generic_type: type "YetAnotherDuplicateNested" is already registered!'
 | 
			
		||||
    assert str(exc_info.value) == expected
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_pr4220_tripped_over_this():
 | 
			
		||||
    assert (
 | 
			
		||||
        m.Empty0().get_msg()
 | 
			
		||||
        == "This is really only meant to exercise successful compilation."
 | 
			
		||||
    )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,3 @@
 | 
			
		|||
# Built-in in CMake 3.5+
 | 
			
		||||
include(CMakeParseArguments)
 | 
			
		||||
 | 
			
		||||
add_custom_target(test_cmake_build)
 | 
			
		||||
 | 
			
		||||
function(pybind11_add_build_test name)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,12 @@
 | 
			
		|||
cmake_minimum_required(VERSION 3.4)
 | 
			
		||||
cmake_minimum_required(VERSION 3.5)
 | 
			
		||||
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` 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.18)
 | 
			
		||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
 | 
			
		||||
  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
 | 
			
		||||
else()
 | 
			
		||||
  cmake_policy(VERSION 3.18)
 | 
			
		||||
  cmake_policy(VERSION 3.26)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
project(test_installed_embed CXX)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,13 @@
 | 
			
		|||
cmake_minimum_required(VERSION 3.4)
 | 
			
		||||
cmake_minimum_required(VERSION 3.5)
 | 
			
		||||
project(test_installed_module CXX)
 | 
			
		||||
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` 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.18)
 | 
			
		||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
 | 
			
		||||
  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
 | 
			
		||||
else()
 | 
			
		||||
  cmake_policy(VERSION 3.18)
 | 
			
		||||
  cmake_policy(VERSION 3.26)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
project(test_installed_function CXX)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,12 @@
 | 
			
		|||
cmake_minimum_required(VERSION 3.4)
 | 
			
		||||
cmake_minimum_required(VERSION 3.5)
 | 
			
		||||
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` 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.18)
 | 
			
		||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
 | 
			
		||||
  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
 | 
			
		||||
else()
 | 
			
		||||
  cmake_policy(VERSION 3.18)
 | 
			
		||||
  cmake_policy(VERSION 3.26)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
project(test_installed_target CXX)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,12 @@
 | 
			
		|||
cmake_minimum_required(VERSION 3.4)
 | 
			
		||||
cmake_minimum_required(VERSION 3.5)
 | 
			
		||||
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` 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.18)
 | 
			
		||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
 | 
			
		||||
  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
 | 
			
		||||
else()
 | 
			
		||||
  cmake_policy(VERSION 3.18)
 | 
			
		||||
  cmake_policy(VERSION 3.26)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
project(test_subdirectory_embed CXX)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,12 @@
 | 
			
		|||
cmake_minimum_required(VERSION 3.4)
 | 
			
		||||
cmake_minimum_required(VERSION 3.5)
 | 
			
		||||
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` 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.18)
 | 
			
		||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
 | 
			
		||||
  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
 | 
			
		||||
else()
 | 
			
		||||
  cmake_policy(VERSION 3.18)
 | 
			
		||||
  cmake_policy(VERSION 3.26)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
project(test_subdirectory_function CXX)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,12 @@
 | 
			
		|||
cmake_minimum_required(VERSION 3.4)
 | 
			
		||||
cmake_minimum_required(VERSION 3.5)
 | 
			
		||||
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.4...3.18)` syntax does not work with
 | 
			
		||||
# The `cmake_minimum_required(VERSION 3.5...3.26)` 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.18)
 | 
			
		||||
if(${CMAKE_VERSION} VERSION_LESS 3.26)
 | 
			
		||||
  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
 | 
			
		||||
else()
 | 
			
		||||
  cmake_policy(VERSION 3.18)
 | 
			
		||||
  cmake_policy(VERSION 3.26)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
project(test_subdirectory_target CXX)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue