├── .bazelignore ├── .bazelrc ├── .github ├── auto_assign-issues.yml └── workflows │ ├── actions.yml │ ├── amd64_linux_bazel.yml │ ├── amd64_linux_cmake.yml │ ├── amd64_macos_bazel.yml │ ├── amd64_macos_cmake.yml │ ├── amd64_windows_bazel.yml │ ├── amd64_windows_cmake.yml │ ├── arm64_macos_bazel.yml │ ├── arm64_macos_cmake.yml │ ├── pre-commit.yml │ └── ubuntu-build.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CMakeLists.txt ├── LICENSE ├── MODULE.bazel ├── README.md ├── WORKSPACE ├── WORKSPACE.bzlmod ├── cmake └── dependencies │ └── CMakeLists.txt ├── pybind11_abseil ├── BUILD ├── CMakeLists.txt ├── __init__.py ├── absl_casters.h ├── check_status_module_imported.h ├── compat │ ├── BUILD │ ├── CMakeLists.txt │ ├── README.md │ ├── py_base_utilities.cc │ ├── py_base_utilities.h │ ├── status_from_core_py_exc.cc │ ├── status_from_core_py_exc.h │ ├── status_from_py_exc.cc │ └── status_from_py_exc.h ├── cpp_capsule_tools │ ├── BUILD │ ├── CMakeLists.txt │ ├── make_shared_ptr_capsule.h │ ├── raw_ptr_from_capsule.h │ ├── shared_ptr_from_capsule.h │ ├── void_ptr_from_capsule.cc │ └── void_ptr_from_capsule.h ├── display_source_location_in_python.cc ├── display_source_location_in_python.h ├── import_status_module.cc ├── import_status_module.h ├── init_from_tag.h ├── no_throw_status.h ├── ok_status_singleton_lib.cc ├── ok_status_singleton_lib.h ├── ok_status_singleton_py_extension_stub.cc ├── ok_status_singleton_pyinit_google3.cc ├── register_status_bindings.cc ├── register_status_bindings.h ├── requirements │ ├── BUILD │ ├── requirements.in │ ├── requirements_lock_3_10.txt │ ├── requirements_lock_3_11.txt │ ├── requirements_lock_3_12.txt │ ├── requirements_lock_3_8.txt │ └── requirements_lock_3_9.txt ├── status_caster.h ├── status_casters.h ├── status_not_ok_exception.h ├── status_py_extension_stub.cc ├── status_pyinit_google3.cc ├── statusor_caster.h ├── tests │ ├── BUILD │ ├── CMakeLists.txt │ ├── absl_example.cc │ ├── absl_test.py │ ├── cpp_capsule_tools_testing.cc │ ├── cpp_capsule_tools_testing_test.py │ ├── missing_import.cc │ ├── missing_import_test.py │ ├── ok_status_singleton_test.py │ ├── status_example.cc │ ├── status_example_test.py │ ├── status_test.py │ ├── status_testing_no_cpp_eh_lib.h │ ├── status_testing_no_cpp_eh_pybind.cc │ ├── status_testing_no_cpp_eh_test.py │ └── status_testing_no_cpp_eh_test_lib.py ├── utils_pybind11_absl.cc └── utils_pybind11_absl.h └── scripts ├── build_and_run_tests_bazel.sh └── build_and_run_tests_cmake.sh /.bazelignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /.bazelrc: -------------------------------------------------------------------------------- 1 | # Enable logging rc options. 2 | common --announce_rc 3 | 4 | # Enable verbose failures for testing only. 5 | build --verbose_failures 6 | 7 | # Set the default Apple platform to macOS. 8 | build --apple_platform_type=macos 9 | 10 | # Abseil requires C++14 at minimum. 11 | build --enable_platform_specific_config 12 | build:linux --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 13 | build:macos --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 14 | build:macos --cxxopt=-mmacos-version-min=10.15 --host_cxxopt=-mmacos-version-min=10.15 15 | build:windows --cxxopt=/std:c++17 --host_cxxopt=/std:c++17 16 | 17 | # Enable the runfiles symlink tree on Windows. This makes it possible to build 18 | # the pip package on Windows without an intermediate data-file archive, as the 19 | # build_pip_package script in its current form (as of Aug 2023) uses the 20 | # runfiles symlink tree to decide what to put into the Python wheel. 21 | startup --windows_enable_symlinks 22 | build:windows --enable_runfiles 23 | 24 | # Enable logging error output. 25 | test --test_output=errors 26 | test --test_summary=detailed 27 | 28 | # https://bazel.build/configure/best-practices#bazelrc-file 29 | try-import %workspace%/user.bazelrc 30 | -------------------------------------------------------------------------------- /.github/auto_assign-issues.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/apps/auto-assign-issues 2020-11-30+2000 2 | 3 | # If enabled, auto-assigns users when a new issue is created 4 | # Defaults to true, allows you to install the app globally, and disable on a per-repo basis 5 | addAssignees: true 6 | 7 | # The list of users to assign to new issues. 8 | # If empty or not provided, the repository owner is assigned 9 | assignees: 10 | - rwgk 11 | -------------------------------------------------------------------------------- /.github/workflows/actions.yml: -------------------------------------------------------------------------------- 1 | # ref: https://github.com/actions/runner-images 2 | name: build_and_test 3 | 4 | # Controls when the action will run. 5 | on: [push, pull_request, workflow_dispatch] 6 | 7 | env: 8 | PIP_BREAK_SYSTEM_PACKAGES: 1 9 | 10 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 11 | jobs: 12 | unix: 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | runs-on: [ubuntu-latest] 17 | build_tool: [bazel, cmake] 18 | 19 | name: "script ${{matrix.build_tool}}" 20 | runs-on: ${{matrix.runs-on}} 21 | 22 | # Steps represent a sequence of tasks that will be executed as part of the job 23 | steps: 24 | - name: Show env 25 | run: env 26 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 27 | - uses: actions/checkout@v4 28 | 29 | - name: Setup bazel 30 | if: matrix.build_tool == 'bazel' 31 | uses: bazel-contrib/setup-bazel@0.8.4 32 | with: 33 | bazelisk-cache: true 34 | disk-cache: ${{ github.workflow }} 35 | repository-cache: true 36 | 37 | - name: Show bazel version 38 | if: matrix.build_tool == 'bazel' 39 | run: bazel --version 40 | 41 | - name: Show cmake version 42 | if: matrix.build_tool == 'cmake' 43 | run: cmake --version 44 | 45 | - name: Show platform info 46 | run: python -m platform 47 | 48 | - name: Install virtualenv 49 | run: | 50 | sudo apt-get install python3-pip -y 51 | sudo pip3 install virtualenv 52 | 53 | - name: Show nproc 54 | run: echo nproc=$(nproc) 55 | 56 | - name: Build and run tests 57 | run: bash ./scripts/build_and_run_tests_${{matrix.build_tool}}.sh -j $(nproc) 58 | -------------------------------------------------------------------------------- /.github/workflows/amd64_linux_bazel.yml: -------------------------------------------------------------------------------- 1 | # ref: https://github.com/actions/runner-images 2 | name: amd64 Linux Bazel 3 | 4 | on: [push, pull_request, workflow_dispatch] 5 | 6 | # Building using the github runner environement directly. 7 | jobs: 8 | native: 9 | strategy: 10 | matrix: 11 | bazel: [ 12 | {compilation_mode: opt}, 13 | {compilation_mode: dbg}, 14 | ] 15 | cpp: [ 16 | {version: 14, flags: "-std=c++14"}, 17 | {version: 17, flags: "-std=c++17"}, 18 | {version: 20, flags: "-std=c++20"}, 19 | ] 20 | python: [ 21 | {version: '3.11'}, 22 | ] 23 | exclude: 24 | # only test `-c dbg` build with C++17 25 | - cpp: {version: 14} 26 | bazel: {compilation_mode: dbg} 27 | - cpp: {version: 20} 28 | bazel: {compilation_mode: dbg} 29 | fail-fast: false 30 | name: Linux•Bazel(${{ matrix.bazel.compilation_mode }})•C++${{ matrix.cpp.version }}•Python${{ matrix.python.version }} 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@v4 34 | - name: Check Java 35 | run: java -version 36 | - name: Setup Python 37 | uses: actions/setup-python@v5 38 | with: 39 | python-version: ${{ matrix.python.version }} 40 | - name: Check Python 41 | run: | 42 | python --version 43 | python -m platform 44 | - uses: bazel-contrib/setup-bazel@0.8.4 45 | with: 46 | bazelisk-cache: true 47 | disk-cache: ${{ github.workflow }} 48 | repository-cache: true 49 | - name: Check Bazel 50 | run: bazel version 51 | - name: Build 52 | run: > 53 | bazel build 54 | -c ${{ matrix.bazel.compilation_mode }} 55 | --cxxopt=${{ matrix.cpp.flags }} --host_cxxopt=${{ matrix.cpp.flags }} 56 | --subcommands=pretty_print 57 | --enable_bzlmod 58 | //... 59 | - name: Test 60 | run: > 61 | bazel test 62 | -c ${{ matrix.bazel.compilation_mode }} 63 | --cxxopt=${{ matrix.cpp.flags }} --host_cxxopt=${{ matrix.cpp.flags }} 64 | --subcommands=pretty_print 65 | --enable_bzlmod 66 | //... 67 | 68 | amd64_linux_bazel: 69 | runs-on: ubuntu-latest 70 | needs: native 71 | steps: 72 | - uses: actions/checkout@v4 73 | -------------------------------------------------------------------------------- /.github/workflows/amd64_linux_cmake.yml: -------------------------------------------------------------------------------- 1 | # ref: https://github.com/actions/runner-images 2 | name: amd64 Linux CMake 3 | 4 | on: [push, pull_request, workflow_dispatch] 5 | 6 | # Building using the github runner environement directly. 7 | jobs: 8 | native: 9 | strategy: 10 | matrix: 11 | python: [ 12 | {version: '3.9'}, 13 | {version: '3.10'}, 14 | {version: '3.11'}, 15 | {version: '3.12'}, 16 | #{version: '3.13'}, 17 | ] 18 | cmake: [ 19 | {generator: "Unix Makefiles", config: "Release"}, 20 | {generator: "Ninja", config: "Release"}, 21 | #{generator: "Ninja Multi-Config", config: "Release"}, 22 | ] 23 | fail-fast: false 24 | name: Linux•CMake(${{ matrix.cmake.generator }})•Python${{ matrix.python.version }} 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v4 28 | - name: Setup Python 29 | uses: actions/setup-python@v5 30 | with: 31 | python-version: ${{ matrix.python.version }} 32 | - name: Check Python 33 | run: | 34 | python --version 35 | python -m platform 36 | - name: Install Python requirements 37 | run: python -m pip install --upgrade -r $(python -c 'import sys; print("./pybind11_abseil/requirements/requirements_lock_%d_%d.txt" % (sys.version_info[:2]))') 38 | - name: Install Ninja 39 | run: | 40 | sudo apt-get update 41 | sudo apt-get install ninja-build 42 | - name: Check CMake 43 | run: cmake --version 44 | - name: Configure 45 | run: > 46 | cmake -S. -Bbuild 47 | -G "${{ matrix.cmake.generator }}" 48 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake.config }} 49 | -DCMAKE_INSTALL_PREFIX=install 50 | - name: Build 51 | run: > 52 | cmake --build build 53 | --config ${{ matrix.cmake.config }} 54 | --target all 55 | -v -j2 56 | - name: Test 57 | run: > 58 | CTEST_OUTPUT_ON_FAILURE=1 59 | cmake --build build 60 | --config ${{ matrix.cmake.config }} 61 | --target test 62 | -v 63 | - name: Install 64 | run: > 65 | cmake --build build 66 | --config ${{ matrix.cmake.config }} 67 | --target install 68 | -v 69 | 70 | amd64_linux_cmake: 71 | runs-on: ubuntu-latest 72 | needs: native 73 | steps: 74 | - uses: actions/checkout@v4 75 | -------------------------------------------------------------------------------- /.github/workflows/amd64_macos_bazel.yml: -------------------------------------------------------------------------------- 1 | # ref: https://github.com/actions/runner-images 2 | name: amd64 MacOS Bazel 3 | 4 | on: [push, pull_request, workflow_dispatch] 5 | 6 | # Building using the github runner environement directly. 7 | jobs: 8 | native: 9 | strategy: 10 | matrix: 11 | bazel: [ 12 | {compilation_mode: opt}, 13 | {compilation_mode: dbg}, 14 | ] 15 | cpp: [ 16 | #{version: 14, flags: "-std=c++14"}, 17 | {version: 17, flags: "-std=c++17"}, 18 | #{version: 20, flags: "-std=c++20"}, 19 | ] 20 | python: [ 21 | {version: '3.11'}, 22 | ] 23 | exclude: 24 | # only test `-c dbg` build with C++17 25 | - cpp: {version: 14} 26 | bazel: {compilation_mode: dbg} 27 | - cpp: {version: 20} 28 | bazel: {compilation_mode: dbg} 29 | fail-fast: false 30 | name: MacOS•Bazel(${{ matrix.bazel.compilation_mode }})•C++${{ matrix.cpp.version }}•Python${{ matrix.python.version }} 31 | runs-on: macos-13 # last macos intel based runner 32 | steps: 33 | - uses: actions/checkout@v4 34 | - name: Set Java to OpenJDK 17 (Temurin) 35 | uses: actions/setup-java@v3 36 | with: 37 | distribution: 'temurin' 38 | java-version: '17' 39 | - name: Setup Python 40 | uses: actions/setup-python@v5 41 | with: 42 | python-version: ${{ matrix.python.version }} 43 | - name: Check Python 44 | run: | 45 | python --version 46 | python -m platform 47 | - name: Check Bazel 48 | run: bazel version 49 | - name: Change Python in MODULE.bazel 50 | run: | 51 | sed -i '' -e 's/\(DEFAULT_PYTHON =\) "3.[0-9]*"/\1 "${{ matrix.python.version }}"/g' MODULE.bazel 52 | cat MODULE.bazel 53 | - name: Build 54 | run: > 55 | bazel build 56 | -c ${{ matrix.bazel.compilation_mode }} 57 | --cxxopt=${{ matrix.cpp.flags }} --host_cxxopt=${{ matrix.cpp.flags }} 58 | --subcommands=pretty_print 59 | --enable_bzlmod 60 | //... 61 | - name: Test 62 | run: > 63 | bazel test 64 | -c ${{ matrix.bazel.compilation_mode }} 65 | --cxxopt=${{ matrix.cpp.flags }} --host_cxxopt=${{ matrix.cpp.flags }} 66 | --subcommands=pretty_print 67 | --enable_bzlmod 68 | //... 69 | 70 | amd64_macos_bazel: 71 | runs-on: ubuntu-latest 72 | needs: native 73 | steps: 74 | - uses: actions/checkout@v4 75 | -------------------------------------------------------------------------------- /.github/workflows/amd64_macos_cmake.yml: -------------------------------------------------------------------------------- 1 | # ref: https://github.com/actions/runner-images 2 | name: amd64 MacOS CMake 3 | 4 | on: [push, pull_request, workflow_dispatch] 5 | 6 | # Building using the github runner environement directly. 7 | jobs: 8 | native: 9 | strategy: 10 | matrix: 11 | python: [ 12 | {version: '3.9'}, 13 | {version: '3.10'}, 14 | {version: '3.11'}, 15 | {version: '3.12'}, 16 | #{version: '3.13'}, 17 | ] 18 | cmake: [ 19 | #{generator: "Xcode", config: Release, build_target: ALL_BUILD, test_target: RUN_TESTS, install_target: install}, 20 | {generator: "Unix Makefiles", config: Release, build_target: all, test_target: test, install_target: install}, 21 | ] 22 | fail-fast: false 23 | name: MacOS•CMake(${{ matrix.cmake.generator }})•Python${{ matrix.python.version }} 24 | runs-on: macos-13 # last macos intel based runner 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Setup Python 28 | uses: actions/setup-python@v5 29 | with: 30 | python-version: ${{ matrix.python.version }} 31 | - name: Update Path 32 | run: | 33 | echo "$HOME/Library/Python/${{ matrix.python.version }}/bin" >> $GITHUB_PATH 34 | echo "$HOME/.local/bin" >> $GITHUB_PATH 35 | - name: Check Python 36 | run: python --version 37 | - name: Install Python requirements 38 | run: python -m pip install --upgrade -r $(python -c 'import sys; print("./pybind11_abseil/requirements/requirements_lock_%d_%d.txt" % (sys.version_info[:2]))') 39 | - name: Check CMake 40 | run: cmake --version 41 | - name: Configure 42 | run: > 43 | cmake -S. -Bbuild 44 | -G "${{ matrix.cmake.generator }}" 45 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake.config }} 46 | -DCMAKE_INSTALL_PREFIX=install 47 | - name: Build 48 | run: > 49 | cmake --build build 50 | --config ${{ matrix.cmake.config }} 51 | --target ${{ matrix.cmake.build_target }} 52 | -v -j2 53 | - name: Test 54 | run: > 55 | CTEST_OUTPUT_ON_FAILURE=1 56 | cmake --build build 57 | --config ${{ matrix.cmake.config }} 58 | --target ${{ matrix.cmake.test_target }} 59 | -v 60 | - name: Install 61 | run: > 62 | cmake --build build 63 | --config ${{ matrix.cmake.config }} 64 | --target ${{ matrix.cmake.install_target }} 65 | -v 66 | 67 | amd64_macos_cmake: 68 | runs-on: ubuntu-latest 69 | needs: native 70 | steps: 71 | - uses: actions/checkout@v4 72 | -------------------------------------------------------------------------------- /.github/workflows/amd64_windows_bazel.yml: -------------------------------------------------------------------------------- 1 | # ref: https://github.com/actions/runner-images 2 | name: amd64 Windows Bazel 3 | 4 | on: [push, pull_request, workflow_dispatch] 5 | 6 | # Building using the github runner environement directly. 7 | jobs: 8 | native: 9 | strategy: 10 | matrix: 11 | runner: [ 12 | windows-2022, 13 | #windows-2019, 14 | ] 15 | bazel: [ 16 | {compilation_mode: opt}, 17 | {compilation_mode: dbg}, 18 | ] 19 | cpp: [ 20 | {version: 14, flags: "/std:c++14"}, 21 | {version: 17, flags: "/std:c++17"}, 22 | #{version: 20, flags: "/std:c++20"}, 23 | ] 24 | python: [ 25 | {version: '3.11'}, 26 | ] 27 | exclude: 28 | - runner: windows-2019 29 | cpp: {version: 20} 30 | # only test -c dbg with VS 2022 version 17 to save compute time 31 | - runner: windows-2019 32 | bazel: {compilation_mode: dbg} 33 | - cpp: {version: 14} 34 | bazel: {compilation_mode: dbg} 35 | - cpp: {version: 20} 36 | bazel: {compilation_mode: dbg} 37 | fail-fast: false # Don't cancel all jobs if one fails. 38 | name: ${{ matrix.runner }}•Bazel(${{ matrix.bazel.compilation_mode }})•C++${{ matrix.cpp.version }}•Python${{ matrix.python.version }} 39 | runs-on: ${{ matrix.runner }} 40 | steps: 41 | - uses: actions/checkout@v4 42 | - name: Setup Python 43 | uses: actions/setup-python@v5 44 | with: 45 | python-version: ${{ matrix.python.version }} 46 | - name: Check Python 47 | run: | 48 | python --version 49 | python -m platform 50 | - name: Install Bazel 51 | run: choco install bazel 52 | - name: Check Bazel 53 | run: bazel version 54 | - name: Build 55 | run: > 56 | bazel build 57 | -c ${{ matrix.bazel.compilation_mode }} 58 | --cxxopt=${{ matrix.cpp.flags }} --host_cxxopt=${{ matrix.cpp.flags }} 59 | --subcommands=pretty_print 60 | --enable_bzlmod 61 | //... 62 | - name: Test 63 | run: > 64 | bazel test 65 | -c ${{ matrix.bazel.compilation_mode }} 66 | --cxxopt=${{ matrix.cpp.flags }} --host_cxxopt=${{ matrix.cpp.flags }} 67 | --subcommands=pretty_print 68 | --enable_bzlmod 69 | //... 70 | 71 | amd64_windows_bazel: 72 | runs-on: ubuntu-latest 73 | needs: native 74 | steps: 75 | - uses: actions/checkout@v4 76 | -------------------------------------------------------------------------------- /.github/workflows/amd64_windows_cmake.yml: -------------------------------------------------------------------------------- 1 | # ref: https://github.com/actions/runner-images 2 | name: amd64 Windows CMake 3 | 4 | on: [push, pull_request, workflow_dispatch] 5 | 6 | # Building using the github runner environement directly. 7 | jobs: 8 | native: 9 | strategy: 10 | matrix: 11 | python: [ 12 | {version: '3.11'}, 13 | #{version: '3.12'}, 14 | #{version: '3.13'}, 15 | ] 16 | cmake: [ 17 | {generator: "Visual Studio 17 2022", config: Release, build_target: ALL_BUILD, test_target: RUN_TESTS, install_target: INSTALL}, 18 | ] 19 | fail-fast: false 20 | name: Windows•CMake(${{ matrix.cmake.generator }})•Python${{ matrix.python.version }} 21 | runs-on: windows-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Setup Python 25 | uses: actions/setup-python@v5 26 | with: 27 | python-version: ${{ matrix.python.version }} 28 | - name: Check Python 29 | run: | 30 | python --version 31 | python -m platform 32 | - name: Install Python requirements 33 | run: python -m pip install --upgrade -r $(python -c 'import sys; print("./pybind11_abseil/requirements/requirements_lock_%d_%d.txt" % (sys.version_info[:2]))') 34 | - name: Check CMake 35 | run: | 36 | cmake --version 37 | cmake -G || true 38 | - name: Configure 39 | run: > 40 | cmake -S. -Bbuild 41 | -G "${{ matrix.cmake.generator }}" 42 | -DCMAKE_CONFIGURATION_TYPES=${{ matrix.cmake.config }} 43 | -DCMAKE_INSTALL_PREFIX=install 44 | - name: Build 45 | run: > 46 | cmake --build build 47 | --config ${{ matrix.cmake.config }} 48 | --target ${{ matrix.cmake.build_target }} 49 | -v -j2 50 | - name: Test 51 | shell: bash 52 | run: > 53 | CTEST_OUTPUT_ON_FAILURE=1 54 | cmake --build build 55 | --config ${{ matrix.cmake.config }} 56 | --target ${{ matrix.cmake.test_target }} 57 | -v 58 | - name: Install 59 | run: > 60 | cmake --build build 61 | --config ${{ matrix.cmake.config }} 62 | --target ${{ matrix.cmake.install_target }} 63 | -v 64 | 65 | amd64_windows_cmake: 66 | runs-on: ubuntu-latest 67 | needs: native 68 | steps: 69 | - uses: actions/checkout@v4 70 | -------------------------------------------------------------------------------- /.github/workflows/arm64_macos_bazel.yml: -------------------------------------------------------------------------------- 1 | # ref: https://github.com/actions/runner-images 2 | name: arm64 MacOS Bazel 3 | 4 | on: [push, pull_request, workflow_dispatch] 5 | 6 | # Building using the github runner environement directly. 7 | jobs: 8 | native: 9 | strategy: 10 | matrix: 11 | bazel: [ 12 | {compilation_mode: opt}, 13 | {compilation_mode: dbg}, 14 | ] 15 | cpp: [ 16 | #{version: 14, flags: "-std=c++14"}, 17 | {version: 17, flags: "-std=c++17"}, 18 | #{version: 20, flags: "-std=c++20"}, 19 | ] 20 | python: [ 21 | {version: '3.11'}, 22 | ] 23 | exclude: 24 | # only test `-c dbg` build with C++17 25 | - cpp: {version: 14} 26 | bazel: {compilation_mode: dbg} 27 | - cpp: {version: 20} 28 | bazel: {compilation_mode: dbg} 29 | fail-fast: false 30 | name: MacOS•Bazel(${{ matrix.bazel.compilation_mode }})•C++${{ matrix.cpp.version }}•Python${{ matrix.python.version }} 31 | runs-on: macos-latest 32 | steps: 33 | - uses: actions/checkout@v4 34 | - name: Set Java to OpenJDK 17 (Temurin) 35 | uses: actions/setup-java@v3 36 | with: 37 | distribution: 'temurin' 38 | java-version: '17' 39 | - name: Setup Python 40 | uses: actions/setup-python@v5 41 | with: 42 | python-version: ${{ matrix.python.version }} 43 | - name: Check Python 44 | run: | 45 | python --version 46 | python -m platform 47 | - name: Check Bazel 48 | run: bazel version 49 | - name: Change Python in MODULE.bazel 50 | run: | 51 | sed -i '' -e 's/\(DEFAULT_PYTHON =\) "3.[0-9]*"/\1 "${{ matrix.python.version }}"/g' MODULE.bazel 52 | cat MODULE.bazel 53 | - name: Build 54 | run: > 55 | bazel build 56 | -c ${{ matrix.bazel.compilation_mode }} 57 | --cxxopt=${{ matrix.cpp.flags }} --host_cxxopt=${{ matrix.cpp.flags }} 58 | --subcommands=pretty_print 59 | --enable_bzlmod 60 | //... 61 | - name: Test 62 | run: > 63 | bazel test 64 | -c ${{ matrix.bazel.compilation_mode }} 65 | --cxxopt=${{ matrix.cpp.flags }} --host_cxxopt=${{ matrix.cpp.flags }} 66 | --subcommands=pretty_print 67 | --enable_bzlmod 68 | //... 69 | 70 | arm64_macos_bazel: 71 | runs-on: ubuntu-latest 72 | needs: native 73 | steps: 74 | - uses: actions/checkout@v4 75 | -------------------------------------------------------------------------------- /.github/workflows/arm64_macos_cmake.yml: -------------------------------------------------------------------------------- 1 | # ref: https://github.com/actions/runner-images 2 | name: arm64 MacOS CMake 3 | 4 | on: [push, pull_request, workflow_dispatch] 5 | 6 | # Building using the github runner environement directly. 7 | jobs: 8 | native: 9 | strategy: 10 | matrix: 11 | python: [ 12 | {version: '3.9'}, 13 | {version: '3.10'}, 14 | {version: '3.11'}, 15 | {version: '3.12'}, 16 | #{version: '3.13'}, 17 | ] 18 | cmake: [ 19 | #{generator: "Xcode", config: Release, build_target: ALL_BUILD, test_target: RUN_TESTS, install_target: install}, 20 | {generator: "Unix Makefiles", config: Release, build_target: all, test_target: test, install_target: install}, 21 | ] 22 | fail-fast: false 23 | name: MacOS•CMake(${{ matrix.cmake.generator }})•Python${{ matrix.python.version }} 24 | runs-on: macos-latest 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Setup Python 28 | uses: actions/setup-python@v5 29 | with: 30 | python-version: ${{ matrix.python.version }} 31 | - name: Update Path 32 | run: | 33 | echo "$HOME/Library/Python/${{ matrix.python.version }}/bin" >> $GITHUB_PATH 34 | echo "$HOME/.local/bin" >> $GITHUB_PATH 35 | - name: Check Python 36 | run: python --version 37 | - name: Install Python requirements 38 | run: python -m pip install --upgrade -r $(python -c 'import sys; print("./pybind11_abseil/requirements/requirements_lock_%d_%d.txt" % (sys.version_info[:2]))') 39 | - name: Check CMake 40 | run: cmake --version 41 | - name: Configure 42 | run: > 43 | cmake -S. -Bbuild 44 | -G "${{ matrix.cmake.generator }}" 45 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake.config }} 46 | -DCMAKE_INSTALL_PREFIX=install 47 | - name: Build 48 | run: > 49 | cmake --build build 50 | --config ${{ matrix.cmake.config }} 51 | --target ${{ matrix.cmake.build_target }} 52 | -v -j2 53 | - name: Test 54 | run: > 55 | CTEST_OUTPUT_ON_FAILURE=1 56 | cmake --build build 57 | --config ${{ matrix.cmake.config }} 58 | --target ${{ matrix.cmake.test_target }} 59 | -v 60 | - name: Install 61 | run: > 62 | cmake --build build 63 | --config ${{ matrix.cmake.config }} 64 | --target ${{ matrix.cmake.install_target }} 65 | -v 66 | 67 | arm64_macos_cmake: 68 | runs-on: ubuntu-latest 69 | needs: native 70 | steps: 71 | - uses: actions/checkout@v4 72 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | # ref: https://github.com/actions/runner-images 2 | name: pre-commit 3 | 4 | # Controls when the action will run. 5 | on: [push, pull_request, workflow_dispatch] 6 | 7 | jobs: 8 | pre-commit: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-python@v5 13 | - uses: pre-commit/action@v3.0.0 14 | with: 15 | # Slow hooks are marked with manual - slow is okay here, run them too 16 | extra_args: --hook-stage manual --all-files 17 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu-build.yml: -------------------------------------------------------------------------------- 1 | # ref: https://github.com/actions/runner-images 2 | name: ubuntu-build 3 | 4 | on: [push, pull_request, workflow_dispatch] 5 | 6 | concurrency: 7 | group: ci-${{github.workflow}}-${{ github.ref }} 8 | cancel-in-progress: true 9 | 10 | jobs: 11 | cmake: 12 | name: ubuntu-latest cmake 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Show env 16 | run: env 17 | - uses: actions/checkout@v4 18 | - name: Install Build Dependencies 19 | run: > 20 | sudo apt update && 21 | sudo apt install --no-install-recommends -y 22 | cmake make 23 | - name: Show Python version and platform info 24 | run: | 25 | python --version 26 | python -m platform 27 | - name: Show CMake version 28 | run: cmake --version 29 | - name: CMake Configure 30 | run: cmake -S. -Bbuild -DCMAKE_VERBOSE_MAKEFILE=ON 31 | - name: CMake Build 32 | run: cmake --build build -j$(nproc) 33 | 34 | bazel_inner: 35 | strategy: 36 | matrix: 37 | options: [ 38 | {version: 14, flags: "-std=c++14"}, 39 | {version: 17, flags: "-std=c++17"}, 40 | {version: 20, flags: "-std=c++20"}, 41 | ] 42 | fail-fast: false # Don't cancel all jobs if one fails. 43 | name: bazel c++${{ matrix.options.version }} 44 | runs-on: ubuntu-22.04 45 | steps: 46 | - uses: actions/checkout@v4 47 | - name: Setup Python 48 | uses: actions/setup-python@v5 49 | with: 50 | python-version: 3.11 # Current default version in MODULE.bazel 51 | - name: Show Python version and platform info 52 | run: | 53 | python --version 54 | python -m platform 55 | - uses: bazel-contrib/setup-bazel@0.8.4 56 | with: 57 | bazelisk-cache: true 58 | disk-cache: ${{ github.workflow }} 59 | repository-cache: true 60 | - name: Show Bazel version 61 | run: bazel --version 62 | - name: Bazel Build 63 | shell: bash 64 | run: > 65 | bazel build 66 | --cxxopt=${{ matrix.options.flags }} --host_cxxopt=${{ matrix.options.flags }} 67 | --subcommands=pretty_print 68 | --enable_bzlmod 69 | //... 70 | - name: Bazel Test 71 | shell: bash 72 | run: > 73 | bazel test 74 | --cxxopt=${{ matrix.options.flags }} --host_cxxopt=${{ matrix.options.flags }} 75 | --subcommands=pretty_print 76 | --enable_bzlmod 77 | //... 78 | 79 | bazel: 80 | name: ubuntu-latest bazel 81 | runs-on: ubuntu-latest 82 | needs: bazel_inner 83 | steps: 84 | - uses: actions/checkout@v4 85 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bazel-* 2 | /build 3 | /tmp_build 4 | 5 | user.bazelrc 6 | .*.swp 7 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | ###################################################################### 2 | # PLEASE KEEP IN SYNC WITH pybind11_protobuf/.pre-commit-config.yaml # 3 | ###################################################################### 4 | # 5 | # To use: 6 | # 7 | # pre-commit run -a 8 | # 9 | # Or: 10 | # 11 | # pre-commit install # (runs every time you commit in git) 12 | # 13 | # To update this file: 14 | # 15 | # pre-commit autoupdate 16 | # 17 | # See https://github.com/pre-commit/pre-commit 18 | 19 | 20 | ci: 21 | autoupdate_commit_msg: "chore(deps): update pre-commit hooks" 22 | autofix_commit_msg: "style: pre-commit fixes" 23 | autoupdate_schedule: quarterly 24 | 25 | repos: 26 | 27 | - repo: https://github.com/pre-commit/pre-commit-hooks 28 | rev: "v4.4.0" 29 | hooks: 30 | - id: check-added-large-files 31 | - id: check-case-conflict 32 | - id: check-docstring-first 33 | - id: check-merge-conflict 34 | - id: check-symlinks 35 | - id: check-toml 36 | - id: check-yaml 37 | - id: debug-statements 38 | - id: end-of-file-fixer 39 | - id: mixed-line-ending 40 | - id: requirements-txt-fixer 41 | - id: trailing-whitespace 42 | exclude: \.patch?$ 43 | 44 | - repo: https://github.com/cheshirekow/cmake-format-precommit 45 | rev: "v0.6.13" 46 | hooks: 47 | - id: cmake-format 48 | additional_dependencies: [pyyaml] 49 | types: [file] 50 | files: (\.cmake|CMakeLists.txt)(.in)?$ 51 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | project(pybind11_abseil LANGUAGES CXX) 3 | 4 | if(NOT DEFINED CMAKE_CXX_STANDARD) 5 | set(CMAKE_CXX_STANDARD 17) 6 | endif() 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | set(CMAKE_CXX_EXTENSIONS OFF) 9 | 10 | set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) 11 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION FALSE) 12 | 13 | if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24) 14 | cmake_policy(SET CMP0135 NEW) 15 | endif() 16 | 17 | # ============================================================================ 18 | # Options 19 | 20 | option(USE_SYSTEM_ABSEIL "Force usage of system provided abseil-cpp" OFF) 21 | option(USE_SYSTEM_PYBIND "Force usage of system provided pybind11" OFF) 22 | 23 | # ============================================================================ 24 | # Testing 25 | include(CTest) 26 | 27 | # ============================================================================ 28 | # Find Python 29 | find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module) 30 | 31 | # ============================================================================ 32 | # Build dependencies 33 | add_subdirectory(cmake/dependencies dependencies) 34 | 35 | set(TOP_LEVEL_DIR ${CMAKE_CURRENT_LIST_DIR}) 36 | include_directories(${TOP_LEVEL_DIR} ${pybind11_INCLUDE_DIRS}) 37 | add_subdirectory(pybind11_abseil) 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019-2021 The Pybind Development Team. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software 15 | without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | You are under no obligation whatsoever to provide any bug fixes, patches, or 29 | upgrades to the features, functionality or performance of the source code 30 | ("Enhancements") to anyone; however, if you choose to make your Enhancements 31 | available either publicly, or directly to the author of this software, without 32 | imposing a separate written license agreement for such Enhancements, then you 33 | hereby grant the following license: a non-exclusive, royalty-free perpetual 34 | license to install, use, modify, prepare derivative works, incorporate into 35 | other computer software, distribute, and sublicense such enhancements or 36 | derivative works thereof, in binary and source code form. 37 | -------------------------------------------------------------------------------- /MODULE.bazel: -------------------------------------------------------------------------------- 1 | module( 2 | name = "pybind11_abseil", 3 | version = "head", 4 | ) 5 | 6 | # Only direct dependencies need to be listed below. 7 | # Please keep the versions in sync with the versions in the WORKSPACE file. 8 | # see https://registry.bazel.build/ 9 | bazel_dep(name = "bazel_skylib", version = "1.7.1") 10 | bazel_dep(name = "abseil-cpp", version = "20240722.1", repo_name = "com_google_absl") 11 | bazel_dep(name = "platforms", version = "0.0.10") 12 | bazel_dep(name = "rules_cc", version = "0.1.1") 13 | bazel_dep(name = "rules_python", version = "0.40.0") 14 | bazel_dep(name = "pybind11_bazel", version = "2.13.6") 15 | 16 | #### DEV ONLY DEPENDENCIES BELOW HERE #### 17 | 18 | SUPPORTED_PYTHON_VERSIONS = [ 19 | "3.12", 20 | "3.11", 21 | "3.10", 22 | "3.9", 23 | "3.8", 24 | ] 25 | 26 | DEFAULT_PYTHON = "3.11" 27 | 28 | python = use_extension("@rules_python//python/extensions:python.bzl", "python", dev_dependency = True) 29 | 30 | [ 31 | python.toolchain( 32 | ignore_root_user_error = True, # needed for CI 33 | is_default = version == DEFAULT_PYTHON, 34 | python_version = version, 35 | ) 36 | for version in SUPPORTED_PYTHON_VERSIONS 37 | ] 38 | 39 | use_repo(python, python = "python_versions") 40 | 41 | pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True) 42 | 43 | [ 44 | pip.parse( 45 | hub_name = "pypi", 46 | python_version = version, 47 | requirements_lock = "//pybind11_abseil/requirements:requirements_lock_" + version.replace(".", "_") + ".txt", 48 | ) 49 | for version in SUPPORTED_PYTHON_VERSIONS 50 | ] 51 | 52 | use_repo(pip, "pypi") 53 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "pybind11_abseil") 2 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository") 3 | 4 | ################################################################################ 5 | # 6 | # WORKSPACE is being deprecated in favor of the new Bzlmod dependency system. 7 | # It will be removed at some point in the future. 8 | # 9 | ################################################################################ 10 | 11 | ## `bazel_skylib` 12 | # Needed for Abseil. 13 | git_repository( 14 | name = "bazel_skylib", 15 | commit = "27d429d8d036af3d010be837cc5924de1ca8d163", 16 | #tag = "1.7.1", 17 | remote = "https://github.com/bazelbuild/bazel-skylib.git", 18 | ) 19 | load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") 20 | bazel_skylib_workspace() 21 | 22 | ## Bazel rules... 23 | git_repository( 24 | name = "platforms", 25 | commit = "05ec3a3df23fde62471f8288e344cc021dd87bab", 26 | #tag = "0.0.10", 27 | remote = "https://github.com/bazelbuild/platforms.git", 28 | ) 29 | 30 | git_repository( 31 | name = "rules_java", 32 | commit = "767e4410850453a10ccf89aa1cededf9de05c72e", 33 | #tag = "8.6.3", 34 | remote = "https://github.com/bazelbuild/rules_java.git", 35 | ) 36 | 37 | load("@rules_java//java:rules_java_deps.bzl", "rules_java_dependencies") 38 | rules_java_dependencies() 39 | 40 | # note that the following line is what is minimally required from protobuf for the java rules 41 | # consider using the protobuf_deps() public API from @com_google_protobuf//:protobuf_deps.bzl 42 | load("@com_google_protobuf//bazel/private:proto_bazel_features.bzl", "proto_bazel_features") # buildifier: disable=bzl-visibility 43 | proto_bazel_features(name = "proto_bazel_features") 44 | 45 | # register toolchains 46 | load("@rules_java//java:repositories.bzl", "rules_java_toolchains") 47 | rules_java_toolchains() 48 | 49 | ## abseil-cpp 50 | # https://github.com/abseil/abseil-cpp 51 | ## Abseil-cpp 52 | git_repository( 53 | name = "com_google_absl", 54 | commit = "4447c7562e3bc702ade25105912dce503f0c4010", 55 | #tag = "20240722.0", 56 | remote = "https://github.com/abseil/abseil-cpp.git", 57 | ) 58 | 59 | git_repository( 60 | name = "rules_python", 61 | commit = "1944874f6ba507f70d8c5e70df84622e0c783254", 62 | #tag = "0.40.0", 63 | remote = "https://github.com/bazelbuild/rules_python.git", 64 | ) 65 | 66 | load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_multi_toolchains") 67 | py_repositories() 68 | 69 | load("@rules_python//python/pip_install:repositories.bzl", "pip_install_dependencies") 70 | pip_install_dependencies() 71 | 72 | DEFAULT_PYTHON = "3.11" 73 | 74 | python_register_multi_toolchains( 75 | name = "python", 76 | default_version = DEFAULT_PYTHON, 77 | python_versions = [ 78 | "3.12", 79 | "3.11", 80 | "3.10", 81 | "3.9", 82 | "3.8" 83 | ], 84 | ) 85 | 86 | load("@python//:pip.bzl", "multi_pip_parse") 87 | 88 | multi_pip_parse( 89 | name = "pypi", 90 | default_version = DEFAULT_PYTHON, 91 | python_interpreter_target = { 92 | "3.12": "@python_3_12_host//:python", 93 | "3.11": "@python_3_11_host//:python", 94 | "3.10": "@python_3_10_host//:python", 95 | "3.9": "@python_3_9_host//:python", 96 | "3.8": "@python_3_8_host//:python", 97 | }, 98 | requirements_lock = { 99 | "3.12": "//pybind11_abseil/requirements:requirements_lock_3_12.txt", 100 | "3.11": "//pybind11_abseil/requirements:requirements_lock_3_11.txt", 101 | "3.10": "//pybind11_abseil/requirements:requirements_lock_3_10.txt", 102 | "3.9": "//pybind11_abseil/requirements:requirements_lock_3_9.txt", 103 | "3.8": "//pybind11_abseil/requirements:requirements_lock_3_8.txt", 104 | }, 105 | ) 106 | 107 | load("@pypi//:requirements.bzl", "install_deps") 108 | install_deps() 109 | 110 | ## `pybind11_bazel` 111 | # https://github.com/pybind/pybind11_bazel 112 | git_repository( 113 | name = "pybind11_bazel", 114 | commit = "2b6082a4d9d163a52299718113fa41e4b7978db5", 115 | #tag = "v2.13.6", # 2024/10/21 116 | remote = "https://github.com/pybind/pybind11_bazel.git", 117 | ) 118 | 119 | ## `pybind11` 120 | # https://github.com/pybind/pybind11 121 | new_git_repository( 122 | name = "pybind11", 123 | build_file = "@pybind11_bazel//:pybind11-BUILD.bazel", 124 | commit = "a2e59f0e7065404b44dfe92a28aca47ba1378dc4", 125 | #tag = "v2.13.6", 126 | remote = "https://github.com/pybind/pybind11.git", 127 | ) 128 | -------------------------------------------------------------------------------- /WORKSPACE.bzlmod: -------------------------------------------------------------------------------- 1 | # Present for cross-compatibility between MODULE.bazel and WORKSPACE 2 | -------------------------------------------------------------------------------- /cmake/dependencies/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | set(BUILD_SHARED_LIBS ON) 3 | set(BUILD_TESTING OFF) 4 | 5 | message(CHECK_START "Checking for external dependencies") 6 | list(APPEND CMAKE_MESSAGE_INDENT " ") 7 | 8 | if(NOT TARGET absl::base) 9 | if(USE_SYSTEM_ABSEIL) 10 | # Version omitted, as absl only allows EXACT version matches 11 | find_package(absl REQUIRED) 12 | else() 13 | message(CHECK_START "Fetching Abseil-cpp") 14 | list(APPEND CMAKE_MESSAGE_INDENT " ") 15 | # ensure that abseil also installs itself, since we are using it in our 16 | # public API 17 | set(ABSL_ENABLE_INSTALL ON) 18 | set(ABSL_PROPAGATE_CXX_STD ON) 19 | set(ABSL_USE_SYSTEM_INCLUDES ON) 20 | set(ABSL_BUILD_TESTING OFF) 21 | FetchContent_Declare( 22 | absl 23 | GIT_REPOSITORY "https://github.com/abseil/abseil-cpp.git" 24 | GIT_TAG "20240722.0" 25 | GIT_SHALLOW TRUE) 26 | FetchContent_MakeAvailable(absl) 27 | list(POP_BACK CMAKE_MESSAGE_INDENT) 28 | message(CHECK_PASS "fetched") 29 | endif() 30 | endif() 31 | 32 | if(NOT TARGET pybind11::pybind11_headers) 33 | if(USE_SYSTEM_PYBIND) 34 | find_package(pybind11 2.13.6 REQUIRED) 35 | else() 36 | message(CHECK_START "Fetching pybind11") 37 | list(APPEND CMAKE_MESSAGE_INDENT " ") 38 | FetchContent_Declare( 39 | pybind11 40 | GIT_REPOSITORY "https://github.com/pybind/pybind11.git" 41 | GIT_TAG "v2.13.6" 42 | GIT_SHALLOW TRUE) 43 | FetchContent_MakeAvailable(pybind11) 44 | list(POP_BACK CMAKE_MESSAGE_INDENT) 45 | message(CHECK_PASS "fetched") 46 | endif() 47 | endif() 48 | 49 | list(POP_BACK CMAKE_MESSAGE_INDENT) 50 | message(CHECK_PASS "all dependencies found") 51 | -------------------------------------------------------------------------------- /pybind11_abseil/BUILD: -------------------------------------------------------------------------------- 1 | # Pybind11 bindings for the Abseil C++ Common Libraries 2 | 3 | load("@pybind11_bazel//:build_defs.bzl", "pybind_extension", "pybind_library") 4 | 5 | package( 6 | default_visibility = ["//visibility:public"], 7 | ) 8 | 9 | pybind_library( 10 | name = "absl_casters", 11 | hdrs = ["absl_casters.h"], 12 | deps = [ 13 | "@com_google_absl//absl/cleanup", 14 | "@com_google_absl//absl/container:btree", 15 | "@com_google_absl//absl/container:flat_hash_map", 16 | "@com_google_absl//absl/container:flat_hash_set", 17 | "@com_google_absl//absl/container:node_hash_map", 18 | "@com_google_absl//absl/container:node_hash_set", 19 | "@com_google_absl//absl/strings", 20 | "@com_google_absl//absl/strings:cord", 21 | "@com_google_absl//absl/time", 22 | "@com_google_absl//absl/types:optional", 23 | "@com_google_absl//absl/types:span", 24 | ], 25 | ) 26 | 27 | pybind_library( 28 | name = "ok_status_singleton_lib", 29 | srcs = ["ok_status_singleton_lib.cc"], 30 | hdrs = ["ok_status_singleton_lib.h"], 31 | visibility = ["//visibility:public"], 32 | deps = [ 33 | "@com_google_absl//absl/status", 34 | ], 35 | ) 36 | 37 | pybind_library( 38 | name = "ok_status_singleton_pyinit_google3", 39 | srcs = ["ok_status_singleton_pyinit_google3.cc"], 40 | visibility = ["//visibility:private"], 41 | deps = [ 42 | ":ok_status_singleton_lib", 43 | ], 44 | ) 45 | 46 | pybind_extension( 47 | name = "ok_status_singleton", 48 | srcs = ["ok_status_singleton_py_extension_stub.cc"], 49 | deps = [":ok_status_singleton_pyinit_google3"], 50 | ) 51 | 52 | pybind_library( 53 | name = "no_throw_status", 54 | hdrs = ["no_throw_status.h"], 55 | ) 56 | 57 | pybind_library( 58 | name = "status_not_ok_exception", 59 | hdrs = ["status_not_ok_exception.h"], 60 | deps = ["@com_google_absl//absl/status"], 61 | ) 62 | 63 | pybind_library( 64 | name = "check_status_module_imported", 65 | hdrs = ["check_status_module_imported.h"], 66 | visibility = ["//visibility:private"], 67 | deps = [ 68 | "@com_google_absl//absl/status", 69 | ], 70 | ) 71 | 72 | pybind_library( 73 | name = "status_caster", 74 | hdrs = ["status_caster.h"], 75 | deps = [ 76 | ":check_status_module_imported", 77 | ":no_throw_status", 78 | ":ok_status_singleton_lib", 79 | ":status_not_ok_exception", 80 | "//pybind11_abseil/compat:status_from_py_exc", 81 | "//pybind11_abseil/cpp_capsule_tools:raw_ptr_from_capsule", 82 | "@com_google_absl//absl/status", 83 | "@com_google_absl//absl/status:statusor", 84 | ], 85 | ) 86 | 87 | pybind_library( 88 | name = "statusor_caster", 89 | hdrs = ["statusor_caster.h"], 90 | deps = [ 91 | ":check_status_module_imported", 92 | ":no_throw_status", 93 | ":status_caster", 94 | "//pybind11_abseil/compat:status_from_py_exc", 95 | "@com_google_absl//absl/status", 96 | "@com_google_absl//absl/status:statusor", 97 | ], 98 | ) 99 | 100 | cc_library( 101 | name = "init_from_tag", 102 | hdrs = ["init_from_tag.h"], 103 | visibility = ["//visibility:private"], 104 | ) 105 | 106 | pybind_library( 107 | name = "utils_pybind11_absl", 108 | srcs = ["utils_pybind11_absl.cc"], 109 | hdrs = ["utils_pybind11_absl.h"], 110 | visibility = ["//visibility:private"], 111 | deps = [ 112 | "@com_google_absl//absl/strings", 113 | ], 114 | ) 115 | 116 | pybind_library( 117 | name = "register_status_bindings", 118 | srcs = ["register_status_bindings.cc"], 119 | hdrs = ["register_status_bindings.h"], 120 | visibility = ["//visibility:private"], 121 | deps = [ 122 | ":absl_casters", 123 | ":init_from_tag", 124 | ":no_throw_status", 125 | ":ok_status_singleton_lib", 126 | ":status_caster", 127 | ":status_not_ok_exception", 128 | ":utils_pybind11_absl", 129 | "//pybind11_abseil/cpp_capsule_tools:raw_ptr_from_capsule", 130 | "@com_google_absl//absl/status", 131 | "@com_google_absl//absl/status:statusor", 132 | "@com_google_absl//absl/strings", 133 | ], 134 | ) 135 | 136 | pybind_library( 137 | name = "status_pyinit_google3", 138 | srcs = ["status_pyinit_google3.cc"], 139 | visibility = ["//visibility:private"], 140 | deps = [ 141 | ":register_status_bindings", 142 | ], 143 | ) 144 | 145 | pybind_extension( 146 | name = "status", 147 | srcs = ["status_py_extension_stub.cc"], 148 | deps = [":status_pyinit_google3"], 149 | ) 150 | 151 | pybind_library( 152 | name = "import_status_module", 153 | srcs = ["import_status_module.cc"], 154 | hdrs = ["import_status_module.h"], 155 | data = ["status.so"], 156 | ) 157 | 158 | pybind_library( 159 | name = "status_casters", 160 | hdrs = ["status_casters.h"], 161 | deps = [ 162 | ":import_status_module", 163 | ":status_caster", 164 | ":statusor_caster", 165 | ], 166 | ) 167 | -------------------------------------------------------------------------------- /pybind11_abseil/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(compat) 2 | add_subdirectory(cpp_capsule_tools) 3 | 4 | # absl_casters ============================================================ 5 | add_library(absl_casters INTERFACE) 6 | add_library(pybind11_abseil::absl_casters ALIAS absl_casters) 7 | 8 | target_include_directories(absl_casters 9 | INTERFACE $) 10 | 11 | target_link_libraries( 12 | absl_casters 13 | INTERFACE absl::cleanup 14 | absl::btree 15 | absl::flat_hash_map 16 | absl::flat_hash_set 17 | absl::node_hash_map 18 | absl::node_hash_set 19 | absl::strings 20 | absl::time 21 | absl::optional 22 | absl::span) 23 | 24 | # ok_status_singleton_lib ====================================================== 25 | 26 | add_library(ok_status_singleton_lib STATIC ok_status_singleton_lib.cc) 27 | add_library(pybind11_abseil::ok_status_singleton_lib ALIAS 28 | ok_status_singleton_lib) 29 | 30 | target_include_directories(ok_status_singleton_lib 31 | INTERFACE $) 32 | 33 | target_link_libraries(ok_status_singleton_lib PUBLIC absl::status) 34 | 35 | # ok_status_singleton_pyinit_google3 =========================================== 36 | 37 | add_library(ok_status_singleton_pyinit_google3 STATIC 38 | ok_status_singleton_pyinit_google3.cc) 39 | 40 | target_link_libraries(ok_status_singleton_pyinit_google3 41 | PUBLIC ok_status_singleton_lib) 42 | 43 | # ok_status_singleton ======================================================= 44 | 45 | pybind11_add_module(ok_status_singleton MODULE 46 | ok_status_singleton_py_extension_stub.cc) 47 | add_library(pybind11_abseil::ok_status_singleton ALIAS ok_status_singleton) 48 | 49 | # note: macOS is APPLE and also UNIX ! 50 | if(APPLE) 51 | set_target_properties(ok_status_singleton PROPERTIES SUFFIX ".so") 52 | endif() 53 | 54 | target_include_directories(ok_status_singleton 55 | INTERFACE $) 56 | 57 | target_link_libraries(ok_status_singleton 58 | PUBLIC ok_status_singleton_pyinit_google3) 59 | 60 | # no_throw_status ============================================================== 61 | 62 | add_library(no_throw_status INTERFACE) 63 | add_library(pybind11_abseil::no_throw_status ALIAS no_throw_status) 64 | 65 | target_include_directories(no_throw_status 66 | INTERFACE $) 67 | 68 | # status_not_ok_exception ====================================================== 69 | 70 | add_library(status_not_ok_exception INTERFACE) 71 | add_library(pybind11_abseil::status_not_ok_exception ALIAS 72 | status_not_ok_exception) 73 | 74 | target_include_directories(status_not_ok_exception 75 | INTERFACE $) 76 | 77 | target_link_libraries(status_not_ok_exception INTERFACE absl::status) 78 | 79 | # check_status_module_imported ================================================= 80 | 81 | add_library(check_status_module_imported INTERFACE) 82 | 83 | target_link_libraries(check_status_module_imported INTERFACE absl::status) 84 | 85 | # status_caster ================================================================ 86 | 87 | add_library(status_caster INTERFACE) 88 | add_library(pybind11_abseil::status_caster ALIAS status_caster) 89 | 90 | target_include_directories(status_caster 91 | INTERFACE $) 92 | 93 | target_link_libraries( 94 | status_caster 95 | INTERFACE check_status_module_imported 96 | no_throw_status 97 | ok_status_singleton_lib 98 | status_from_py_exc 99 | status_not_ok_exception 100 | raw_ptr_from_capsule 101 | absl::status 102 | absl::statusor) 103 | 104 | # statusor_caster ============================================================== 105 | 106 | add_library(statusor_caster INTERFACE) 107 | add_library(pybind11_abseil::statusor_caster ALIAS statusor_caster) 108 | 109 | target_include_directories(statusor_caster 110 | INTERFACE $) 111 | 112 | target_link_libraries( 113 | statusor_caster 114 | INTERFACE check_status_module_imported no_throw_status status_caster 115 | status_from_py_exc absl::status absl::statusor) 116 | 117 | # init_from_tag ================================================================ 118 | 119 | add_library(init_from_tag INTERFACE) 120 | add_library(pybind11_abseil::init_from_tag ALIAS init_from_tag) 121 | 122 | target_include_directories(init_from_tag 123 | INTERFACE $) 124 | 125 | # utils_pybind11_absl ========================================================== 126 | 127 | add_library(utils_pybind11_absl STATIC utils_pybind11_absl.cc) 128 | 129 | target_link_libraries(utils_pybind11_absl PUBLIC absl::strings) 130 | 131 | # register_status_bindings ===================================================== 132 | 133 | add_library(register_status_bindings STATIC register_status_bindings.cc) 134 | 135 | target_link_libraries( 136 | register_status_bindings 137 | PUBLIC absl_casters 138 | init_from_tag 139 | no_throw_status 140 | ok_status_singleton_lib 141 | status_caster 142 | status_not_ok_exception 143 | utils_pybind11_absl 144 | raw_ptr_from_capsule 145 | absl::status 146 | absl::statusor 147 | absl::strings) 148 | 149 | # status_pyinit_google3 ======================================================== 150 | 151 | add_library(status_pyinit_google3 STATIC status_pyinit_google3.cc) 152 | 153 | target_link_libraries(status_pyinit_google3 PUBLIC register_status_bindings) 154 | 155 | # status ==================================================================== 156 | 157 | pybind11_add_module(status_py_extension_stub MODULE status_py_extension_stub.cc) 158 | set_target_properties(status_py_extension_stub PROPERTIES LIBRARY_OUTPUT_NAME 159 | "status") 160 | 161 | # note: macOS is APPLE and also UNIX ! 162 | if(APPLE) 163 | set_target_properties( 164 | status_py_extension_stub 165 | PROPERTIES SUFFIX ".so" INSTALL_RPATH "@loader_path;@loader_path/../.libs") 166 | elseif(UNIX) 167 | set_target_properties(status_py_extension_stub 168 | PROPERTIES INSTALL_RPATH "$ORIGIN:$ORIGIN/../.libs") 169 | endif() 170 | 171 | add_library(pybind11_abseil::status ALIAS status_py_extension_stub) 172 | 173 | target_include_directories(status_py_extension_stub 174 | INTERFACE $) 175 | 176 | set_target_properties(status_py_extension_stub PROPERTIES PREFIX "") 177 | 178 | target_link_libraries(status_py_extension_stub PUBLIC status_pyinit_google3 179 | absl::status) 180 | 181 | # import_status_module ========================================================= 182 | 183 | add_library(import_status_module STATIC import_status_module.cc) 184 | add_library(pybind11_abseil::import_status_module ALIAS import_status_module) 185 | 186 | target_include_directories(import_status_module 187 | INTERFACE $) 188 | 189 | add_dependencies(import_status_module status_py_extension_stub) 190 | 191 | # status_casters =============================================================== 192 | 193 | add_library(status_casters INTERFACE) 194 | add_library(pybind11_abseil::status_casters ALIAS status_casters) 195 | 196 | target_include_directories(status_casters 197 | INTERFACE $) 198 | 199 | target_link_libraries(status_casters INTERFACE import_status_module 200 | status_caster statusor_caster) 201 | 202 | if(BUILD_TESTING) 203 | add_subdirectory(tests) 204 | endif() 205 | 206 | if(CMAKE_INSTALL_PYDIR) 207 | # Copying to two target directories for simplicity. It is currently unknown 208 | # how to determine here which copy is actually being used. 209 | install( 210 | TARGETS status_py_extension_stub ok_status_singleton 211 | EXPORT pybind11_abseilTargets 212 | LIBRARY DESTINATION ${CMAKE_INSTALL_PYDIR}/pybind11_abseil 213 | ARCHIVE DESTINATION ${CMAKE_INSTALL_PYDIR}/pybind11_abseil 214 | RUNTIME DESTINATION ${CMAKE_INSTALL_PYDIR}/pybind11_abseil) 215 | 216 | install( 217 | TARGETS status_py_extension_stub ok_status_singleton 218 | EXPORT pybind11_abseil_cppTargets 219 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 220 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 221 | RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}) 222 | endif() 223 | -------------------------------------------------------------------------------- /pybind11_abseil/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pybind/pybind11_abseil/c55fdc9c53d26af70fa8c2314a683abef62fa3f0/pybind11_abseil/__init__.py -------------------------------------------------------------------------------- /pybind11_abseil/check_status_module_imported.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_CHECK_STATUS_MODULE_IMPORTED_H_ 2 | #define PYBIND11_ABSEIL_CHECK_STATUS_MODULE_IMPORTED_H_ 3 | 4 | #include 5 | 6 | #include "absl/status/status.h" 7 | 8 | namespace pybind11 { 9 | namespace google { 10 | namespace internal { 11 | 12 | // Returns true if the status module has been imported. 13 | inline bool IsStatusModuleImported() { 14 | return detail::get_type_info(typeid(absl::Status)); 15 | } 16 | 17 | // In debug mode, throws a type error if the proto module is not imported. 18 | // No-opt if NDEBUG is defined, and inlined so the compiler can optimize it out. 19 | inline void CheckStatusModuleImported() { 20 | #ifndef NDEBUG 21 | if (!IsStatusModuleImported()) 22 | throw type_error( 23 | "Status module has not been imported. Did you call ::pybind11::google" 24 | "::ImportStatusModule() in your PYBIND11_MODULE definition?"); 25 | #endif 26 | } 27 | 28 | } // namespace internal 29 | } // namespace google 30 | } // namespace pybind11 31 | 32 | #endif // PYBIND11_ABSEIL_CHECK_STATUS_MODULE_IMPORTED_H_ 33 | -------------------------------------------------------------------------------- /pybind11_abseil/compat/BUILD: -------------------------------------------------------------------------------- 1 | load("@pybind11_bazel//:build_defs.bzl", "pybind_library") 2 | 3 | licenses(["notice"]) 4 | 5 | package( 6 | default_visibility = ["//visibility:private"], 7 | ) 8 | 9 | pybind_library( 10 | name = "py_base_utilities", 11 | srcs = ["py_base_utilities.cc"], 12 | hdrs = ["py_base_utilities.h"], 13 | visibility = ["//visibility:public"], 14 | deps = [ 15 | "@com_google_absl//absl/log:absl_check", 16 | "@com_google_absl//absl/log:absl_log", 17 | "@com_google_absl//absl/strings", 18 | ], 19 | ) 20 | 21 | pybind_library( 22 | name = "status_from_core_py_exc", 23 | srcs = ["status_from_core_py_exc.cc"], 24 | hdrs = ["status_from_core_py_exc.h"], 25 | visibility = ["//visibility:public"], 26 | deps = [ 27 | ":py_base_utilities", 28 | "@com_google_absl//absl/container:flat_hash_map", 29 | "@com_google_absl//absl/status", 30 | ], 31 | ) 32 | 33 | pybind_library( 34 | name = "status_from_py_exc", 35 | srcs = ["status_from_py_exc.cc"], 36 | hdrs = ["status_from_py_exc.h"], 37 | visibility = ["//visibility:public"], 38 | deps = [ 39 | ":py_base_utilities", 40 | ":status_from_core_py_exc", 41 | "//pybind11_abseil/cpp_capsule_tools:raw_ptr_from_capsule", 42 | "@com_google_absl//absl/log:absl_check", 43 | "@com_google_absl//absl/log:absl_log", 44 | "@com_google_absl//absl/status", 45 | ], 46 | ) 47 | -------------------------------------------------------------------------------- /pybind11_abseil/compat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # py_base_utilities ============================================================ 2 | 3 | add_library(py_base_utilities STATIC py_base_utilities.cc) 4 | add_library(pybind11_abseil::compat::py_base_utilities ALIAS py_base_utilities) 5 | 6 | target_include_directories(py_base_utilities 7 | INTERFACE $) 8 | 9 | target_link_libraries(py_base_utilities PUBLIC absl::strings absl::string_view) 10 | 11 | # status_from_core_py_exc ====================================================== 12 | 13 | add_library(status_from_core_py_exc STATIC status_from_core_py_exc.cc) 14 | add_library(pybind11_abseil::compat::status_from_core_py_exc ALIAS 15 | status_from_core_py_exc) 16 | 17 | target_include_directories(status_from_core_py_exc 18 | INTERFACE $) 19 | 20 | target_link_libraries(status_from_core_py_exc PUBLIC py_base_utilities 21 | absl::status) 22 | 23 | # status_from_py_exc =========================================================== 24 | 25 | add_library(status_from_py_exc STATIC status_from_py_exc.cc) 26 | add_library(pybind11_abseil::compat::status_from_py_exc ALIAS 27 | status_from_py_exc) 28 | 29 | target_include_directories(status_from_py_exc 30 | INTERFACE $) 31 | 32 | target_link_libraries( 33 | status_from_py_exc PUBLIC py_base_utilities status_from_core_py_exc 34 | void_ptr_from_capsule absl::status) 35 | -------------------------------------------------------------------------------- /pybind11_abseil/compat/README.md: -------------------------------------------------------------------------------- 1 | Note 2 | ---- 3 | 4 | The code here 5 | 6 | * only depends on Python and abseil-cpp. 7 | 8 | * It does not depend on pybind11, mainly for compatibility with Google-internal 9 | policies: use of C++ exception handling is strongly discouraged / banned. 10 | 11 | See also: 12 | 13 | * https://google.github.io/styleguide/cppguide.html#Exceptions 14 | -------------------------------------------------------------------------------- /pybind11_abseil/compat/py_base_utilities.cc: -------------------------------------------------------------------------------- 1 | #include "pybind11_abseil/compat/py_base_utilities.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "absl/log/absl_check.h" 8 | #include "absl/log/absl_log.h" 9 | #include "absl/strings/str_cat.h" 10 | #include "absl/strings/string_view.h" 11 | 12 | namespace pybind11_abseil::compat::py_base_utilities { 13 | 14 | const char* ClassName(PyObject* obj) { 15 | if (PyType_Check(obj)) { 16 | return reinterpret_cast(obj)->tp_name; 17 | } 18 | return Py_TYPE(obj)->tp_name; 19 | } 20 | 21 | std::string PyStrAsStdString(PyObject* str_object) { 22 | Py_ssize_t value_size = 0; 23 | const char* value = PyUnicode_AsUTF8AndSize(str_object, &value_size); 24 | ABSL_CHECK(value != nullptr) << "FAILED: PyUnicode_AsUTF8AndSize()"; 25 | return std::string(value, value_size); 26 | } 27 | 28 | PyExcFetchMaybeErrOccurred::PyExcFetchMaybeErrOccurred() { 29 | if (PyErr_Occurred()) { 30 | PyErr_Fetch(&p_type_, &p_value_, &p_traceback_); 31 | } 32 | } 33 | 34 | PyExcFetchGivenErrOccurred::PyExcFetchGivenErrOccurred() { 35 | ABSL_CHECK(Type()) << "PyErr_Occurred() was false at entry."; 36 | } 37 | 38 | PyExcFetchMaybeErrOccurred::~PyExcFetchMaybeErrOccurred() { 39 | Py_XDECREF(p_type_); 40 | Py_XDECREF(p_value_); 41 | Py_XDECREF(p_traceback_); 42 | } 43 | 44 | void PyExcFetchGivenErrOccurred::NormalizeException() { 45 | PyErr_NormalizeException(&p_type_, &p_value_, &p_traceback_); 46 | } 47 | 48 | bool PyExcFetchGivenErrOccurred::Matches(PyObject* exc) const { 49 | ABSL_CHECK(p_type_ != nullptr); 50 | return PyErr_GivenExceptionMatches(p_type_, exc); 51 | } 52 | 53 | std::string PyExcFetchMaybeErrOccurred::FlatMessage() const { 54 | if (p_type_ == nullptr) { 55 | return "PyErr_Occurred() FALSE"; 56 | } 57 | ABSL_CHECK(p_value_ != nullptr) << ClassName(p_type_); 58 | PyObject* str = PyObject_Str(p_value_); 59 | if (str == nullptr) { 60 | ABSL_LOG(FATAL) << "FAILED (while processing " << ClassName(p_type_) 61 | << "): PyObject_Str(p_value_) [" 62 | << PyExcFetchMaybeErrOccurred().FlatMessage() << "]"; 63 | } 64 | Py_ssize_t utf8_str_size = 0; 65 | const char* utf8_str = PyUnicode_AsUTF8AndSize(str, &utf8_str_size); 66 | if (utf8_str == nullptr) { 67 | ABSL_LOG(FATAL) << "FAILED (while processing " << ClassName(p_type_) 68 | << "): PyUnicode_AsUTF8AndSize() [" 69 | << PyExcFetchMaybeErrOccurred().FlatMessage() << "]"; 70 | } 71 | auto msg = absl::StrCat(ClassName(p_type_), ": ", 72 | absl::string_view(utf8_str, utf8_str_size)); 73 | Py_DECREF(str); 74 | return msg; 75 | } 76 | 77 | PyObject* ImportModuleOrDie(const char* fq_mod) { 78 | PyObject* imported_mod = PyImport_ImportModule(fq_mod); 79 | if (imported_mod == nullptr || PyErr_Occurred()) { 80 | ABSL_LOG(FATAL) << "FAILED: PyImport_ImportModule(\"" << fq_mod << "\") [" 81 | << PyExcFetchMaybeErrOccurred().FlatMessage() << "]"; 82 | } 83 | return imported_mod; 84 | } 85 | 86 | PyObject* ImportObjectOrDie(const char* fq_mod, const char* mod_attr) { 87 | PyObject* imported_mod = ImportModuleOrDie(fq_mod); 88 | PyObject* imported_obj = PyObject_GetAttrString(imported_mod, mod_attr); 89 | Py_DECREF(imported_mod); 90 | if (imported_obj == nullptr || PyErr_Occurred()) { 91 | ABSL_LOG(FATAL) << "FAILED: PyObject_GetAttrString(\"" << mod_attr 92 | << "\") [" << PyExcFetchMaybeErrOccurred().FlatMessage() 93 | << "]"; 94 | } 95 | return imported_obj; 96 | } 97 | 98 | PyObject* ImportModuleOrReturnNone(const char* fq_mod) { 99 | ABSL_CHECK(!PyErr_Occurred()); 100 | PyObject* imported_mod = PyImport_ImportModule(fq_mod); 101 | if (PyErr_Occurred()) { 102 | ABSL_CHECK(imported_mod == nullptr); 103 | PyErr_Clear(); 104 | Py_RETURN_NONE; 105 | } 106 | ABSL_CHECK(imported_mod != nullptr); 107 | return imported_mod; 108 | } 109 | 110 | PyObject* ImportObjectOrReturnNone(const char* fq_mod, const char* mod_attr) { 111 | PyObject* imported_mod = ImportModuleOrReturnNone(fq_mod); 112 | if (imported_mod == Py_None) { 113 | return imported_mod; 114 | } 115 | PyObject* imported_obj = PyObject_GetAttrString(imported_mod, mod_attr); 116 | Py_DECREF(imported_mod); 117 | if (PyErr_Occurred()) { 118 | ABSL_CHECK(imported_obj == nullptr); 119 | PyErr_Clear(); 120 | Py_RETURN_NONE; 121 | } 122 | ABSL_CHECK(imported_obj != nullptr); 123 | return imported_obj; 124 | } 125 | 126 | } // namespace pybind11_abseil::compat::py_base_utilities 127 | -------------------------------------------------------------------------------- /pybind11_abseil/compat/py_base_utilities.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_COMPAT_PY_BASE_UTILITIES_H_ 2 | #define PYBIND11_ABSEIL_COMPAT_PY_BASE_UTILITIES_H_ 3 | 4 | #define PY_SSIZE_T_CLEAN 5 | #include 6 | 7 | #include 8 | 9 | namespace pybind11_abseil::compat::py_base_utilities { 10 | 11 | // Equivalent to obj.__class__.__name__ (or obj.__name__ if obj is a class). 12 | const char* ClassName(PyObject* obj); 13 | 14 | std::string PyStrAsStdString(PyObject* str_object); 15 | 16 | class PyExcFetchMaybeErrOccurred { 17 | public: 18 | PyExcFetchMaybeErrOccurred(); 19 | ~PyExcFetchMaybeErrOccurred(); 20 | 21 | // Rule of Five completeness: 22 | PyExcFetchMaybeErrOccurred(const PyExcFetchMaybeErrOccurred& other) = delete; 23 | PyExcFetchMaybeErrOccurred(PyExcFetchMaybeErrOccurred&& other) = delete; 24 | PyExcFetchMaybeErrOccurred& operator=( 25 | const PyExcFetchMaybeErrOccurred& other) = delete; 26 | PyExcFetchMaybeErrOccurred& operator=(PyExcFetchMaybeErrOccurred&& other) = 27 | delete; 28 | 29 | std::string FlatMessage() const; 30 | 31 | PyObject* Type() const { return p_type_; } 32 | PyObject* Value() const { return p_value_; } 33 | PyObject* TraceBack() const { return p_traceback_; } 34 | 35 | private: 36 | PyObject* p_type_ = nullptr; 37 | PyObject* p_value_ = nullptr; 38 | PyObject* p_traceback_ = nullptr; 39 | 40 | friend class PyExcFetchGivenErrOccurred; 41 | }; 42 | 43 | class PyExcFetchGivenErrOccurred : public PyExcFetchMaybeErrOccurred { 44 | public: 45 | PyExcFetchGivenErrOccurred(); 46 | 47 | // WARNING: Calling this method has the potential to mask bugs. 48 | // This problem will go away with Python 3.12: 49 | // https://github.com/python/cpython/issues/102594 50 | void NormalizeException(); 51 | 52 | bool Matches(PyObject* exc) const; 53 | }; 54 | 55 | PyObject* ImportModuleOrDie(const char* fq_mod); 56 | PyObject* ImportObjectOrDie(const char* fq_mod, const char* mod_attr); 57 | 58 | PyObject* ImportModuleOrReturnNone(const char* fq_mod); 59 | PyObject* ImportObjectOrReturnNone(const char* fq_mod, const char* mod_attr); 60 | 61 | } // namespace pybind11_abseil::compat::py_base_utilities 62 | 63 | #endif // PYBIND11_ABSEIL_COMPAT_PY_BASE_UTILITIES_H_ 64 | -------------------------------------------------------------------------------- /pybind11_abseil/compat/status_from_core_py_exc.cc: -------------------------------------------------------------------------------- 1 | #include "pybind11_abseil/compat/status_from_core_py_exc.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "absl/container/flat_hash_map.h" 8 | #include "absl/status/status.h" 9 | #include "pybind11_abseil/compat/py_base_utilities.h" 10 | 11 | namespace pybind11_abseil::compat { 12 | 13 | namespace { 14 | 15 | using PyExceptionStatusCodeMapType = 16 | absl::flat_hash_map; 17 | 18 | const PyExceptionStatusCodeMapType& GetPyExceptionStatusCodeMap() { 19 | // When making changes here, please review 20 | // tests/status_from_py_exc_testing_test.py:TAB_StatusFromFetchedExc 21 | static const auto* kPyExcStatusCodeMap = new PyExceptionStatusCodeMapType( 22 | {{PyExc_MemoryError, absl::StatusCode::kResourceExhausted}, 23 | {PyExc_NotImplementedError, absl::StatusCode::kUnimplemented}, 24 | {PyExc_KeyboardInterrupt, absl::StatusCode::kAborted}, 25 | {PyExc_SystemError, absl::StatusCode::kInternal}, 26 | {PyExc_SyntaxError, absl::StatusCode::kInternal}, 27 | {PyExc_TypeError, absl::StatusCode::kInvalidArgument}, 28 | {PyExc_ValueError, absl::StatusCode::kOutOfRange}, 29 | {PyExc_LookupError, absl::StatusCode::kNotFound}}); 30 | return *kPyExcStatusCodeMap; 31 | } 32 | 33 | } // namespace 34 | 35 | absl::Status StatusFromFetchedExc( 36 | const py_base_utilities::PyExcFetchGivenErrOccurred& fetched) { 37 | std::string message = fetched.FlatMessage(); 38 | const PyExceptionStatusCodeMapType& pyexc_status_code_map = 39 | GetPyExceptionStatusCodeMap(); 40 | for (const auto& it : pyexc_status_code_map) { 41 | if (fetched.Matches(it.first)) { 42 | return absl::Status(it.second, message); 43 | } 44 | } 45 | return absl::UnknownError(message); 46 | } 47 | 48 | } // namespace pybind11_abseil::compat 49 | -------------------------------------------------------------------------------- /pybind11_abseil/compat/status_from_core_py_exc.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_COMPAT_STATUS_FROM_CORE_PY_EXC_H_ 2 | #define PYBIND11_ABSEIL_COMPAT_STATUS_FROM_CORE_PY_EXC_H_ 3 | 4 | #include "absl/status/status.h" 5 | #include "pybind11_abseil/compat/py_base_utilities.h" 6 | 7 | namespace pybind11_abseil::compat { 8 | 9 | absl::Status StatusFromFetchedExc( 10 | const py_base_utilities::PyExcFetchGivenErrOccurred& fetched); 11 | 12 | } // namespace pybind11_abseil::compat 13 | 14 | #endif // PYBIND11_ABSEIL_COMPAT_STATUS_FROM_CORE_PY_EXC_H_ 15 | -------------------------------------------------------------------------------- /pybind11_abseil/compat/status_from_py_exc.cc: -------------------------------------------------------------------------------- 1 | #include "pybind11_abseil/compat/status_from_py_exc.h" 2 | 3 | #include 4 | 5 | #include "absl/log/absl_check.h" 6 | #include "absl/log/absl_log.h" 7 | #include "absl/status/status.h" 8 | #include "pybind11_abseil/compat/py_base_utilities.h" 9 | #include "pybind11_abseil/compat/status_from_core_py_exc.h" 10 | #include "pybind11_abseil/cpp_capsule_tools/raw_ptr_from_capsule.h" 11 | 12 | namespace pybind11_abseil::compat { 13 | 14 | absl::Status StatusFromFetchedStatusNotOk( 15 | const py_base_utilities::PyExcFetchGivenErrOccurred& fetched) { 16 | ABSL_CHECK(fetched.Value() != nullptr); 17 | PyObject* py_status = nullptr; 18 | bool py_status_owned = false; 19 | if (PyTuple_Check(fetched.Value())) { 20 | Py_ssize_t size = PyTuple_Size(fetched.Value()); 21 | ABSL_CHECK(size == 1) << "Unexpected tuple size from PyErr_Fetch(): " 22 | << size; 23 | py_status = PyTuple_GetItem(fetched.Value(), 0); 24 | } else { 25 | py_status = PyObject_GetAttrString(fetched.Value(), "status"); 26 | py_status_owned = true; 27 | } 28 | if (py_status == nullptr) { 29 | ABSL_LOG(FATAL) << "FAILED: Retrieving `StatusNotOk` `status` attribute " 30 | "from fetched Python exception [" 31 | << fetched.FlatMessage() << "]"; 32 | } 33 | if (py_status == Py_None) { 34 | ABSL_LOG(FATAL) << "FAILED: `StatusNotOk` `status` attribute from fetched " 35 | "Python exception is `None` [" 36 | << fetched.FlatMessage() << "]"; 37 | } 38 | auto statusor_raw_ptr = 39 | pybind11_abseil::cpp_capsule_tools::RawPtrFromCapsule( 40 | py_status, "::absl::Status", "as_absl_Status"); 41 | if (!statusor_raw_ptr.ok()) { 42 | ABSL_LOG(FATAL) 43 | << "FAILED: `StatusNotOk` `status` attribute from fetched Python " 44 | "exception cannot be converted to an `absl::Status` object [" 45 | << fetched.FlatMessage() << "]"; 46 | } 47 | if (py_status_owned) { 48 | Py_DECREF(py_status); 49 | } 50 | return *(statusor_raw_ptr.value()); 51 | } 52 | 53 | namespace { 54 | 55 | PyObject* PyStatusNotOkOrNone() { 56 | static PyObject* kImportedObj = nullptr; 57 | if (kImportedObj == nullptr) { 58 | kImportedObj = py_base_utilities::ImportObjectOrReturnNone( 59 | "pybind11_abseil.status", "StatusNotOk"); 60 | } 61 | return kImportedObj; 62 | } 63 | 64 | } // namespace 65 | 66 | absl::Status StatusFromPyExcGivenErrOccurred(bool normalize_exception) { 67 | // Fetching exc IMMEDIATELY to ensure it does not accidentally get clobbered 68 | // by Python C API calls while it is being processed (e.g. b/216844827). 69 | py_base_utilities::PyExcFetchGivenErrOccurred fetched; 70 | 71 | // Regarding "OrNone" in PyStatusNotOkOrNone(): 72 | // If StatusNotOk was not imported somewhere else already, it cannot possibly 73 | // have been used to raise the exception to be matched here. 74 | if (fetched.Matches(PyStatusNotOkOrNone())) { 75 | return StatusFromFetchedStatusNotOk(fetched); 76 | } 77 | 78 | if (normalize_exception) { 79 | fetched.NormalizeException(); 80 | } 81 | return StatusFromFetchedExc(fetched); 82 | } 83 | 84 | absl::Status StatusFromPyExcMaybeErrOccurred(bool normalize_exception) { 85 | if (!PyErr_Occurred()) { 86 | return absl::OkStatus(); 87 | } 88 | return StatusFromPyExcGivenErrOccurred(normalize_exception); 89 | } 90 | 91 | } // namespace pybind11_abseil::compat 92 | -------------------------------------------------------------------------------- /pybind11_abseil/compat/status_from_py_exc.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_COMPAT_STATUS_FROM_PY_EXC_H_ 2 | #define PYBIND11_ABSEIL_COMPAT_STATUS_FROM_PY_EXC_H_ 3 | 4 | #define PY_SSIZE_T_CLEAN 5 | #include 6 | 7 | #include 8 | 9 | #include "absl/status/status.h" 10 | #include "pybind11_abseil/compat/py_base_utilities.h" 11 | 12 | namespace pybind11_abseil::compat { 13 | 14 | // Caller must ensure that the fetched exc type is "error.StatusNotOk". 15 | absl::Status StatusFromFetchedStatusNotOk( 16 | const py_base_utilities::PyExcFetchGivenErrOccurred& fetched); 17 | 18 | // WARNING: `normalize_exception = true` has the potential to mask bugs. 19 | // This problem will go away with Python 3.12: 20 | // https://github.com/python/cpython/issues/102594 21 | absl::Status StatusFromPyExcGivenErrOccurred(bool normalize_exception = false); 22 | absl::Status StatusFromPyExcMaybeErrOccurred(bool normalize_exception = false); 23 | 24 | } // namespace pybind11_abseil::compat 25 | 26 | #endif // PYBIND11_ABSEIL_COMPAT_STATUS_FROM_PY_EXC_H_ 27 | -------------------------------------------------------------------------------- /pybind11_abseil/cpp_capsule_tools/BUILD: -------------------------------------------------------------------------------- 1 | load("@pybind11_bazel//:build_defs.bzl", "pybind_library") 2 | 3 | licenses(["notice"]) 4 | 5 | package( 6 | default_visibility = ["//visibility:private"], 7 | ) 8 | 9 | pybind_library( 10 | name = "void_ptr_from_capsule", 11 | srcs = ["void_ptr_from_capsule.cc"], 12 | hdrs = ["void_ptr_from_capsule.h"], 13 | visibility = ["//visibility:public"], 14 | deps = [ 15 | "@com_google_absl//absl/status", 16 | "@com_google_absl//absl/status:statusor", 17 | "@com_google_absl//absl/strings", 18 | ], 19 | ) 20 | 21 | pybind_library( 22 | name = "raw_ptr_from_capsule", 23 | hdrs = ["raw_ptr_from_capsule.h"], 24 | visibility = ["//visibility:public"], 25 | deps = [ 26 | ":void_ptr_from_capsule", 27 | "@com_google_absl//absl/status:statusor", 28 | ], 29 | ) 30 | 31 | pybind_library( 32 | name = "make_shared_ptr_capsule", 33 | hdrs = ["make_shared_ptr_capsule.h"], 34 | visibility = ["//visibility:public"], 35 | ) 36 | 37 | pybind_library( 38 | name = "shared_ptr_from_capsule", 39 | hdrs = ["shared_ptr_from_capsule.h"], 40 | visibility = ["//visibility:public"], 41 | deps = [ 42 | ":void_ptr_from_capsule", 43 | "@com_google_absl//absl/status:statusor", 44 | ], 45 | ) 46 | -------------------------------------------------------------------------------- /pybind11_abseil/cpp_capsule_tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # void_ptr_from_capsule ======================================================== 2 | 3 | add_library(void_ptr_from_capsule STATIC void_ptr_from_capsule.cc) 4 | add_library(pybind11_abseil::cpp_capsule_tools::void_ptr_from_capsule ALIAS 5 | void_ptr_from_capsule) 6 | 7 | target_include_directories(void_ptr_from_capsule 8 | INTERFACE $) 9 | 10 | target_link_libraries(void_ptr_from_capsule PUBLIC absl::status absl::statusor 11 | absl::strings) 12 | 13 | # raw_ptr_from_capsule ========================================================= 14 | 15 | add_library(raw_ptr_from_capsule INTERFACE) 16 | add_library(pybind11_abseil::cpp_capsule_tools::raw_ptr_from_capsule ALIAS 17 | raw_ptr_from_capsule) 18 | 19 | target_include_directories(raw_ptr_from_capsule 20 | INTERFACE $) 21 | 22 | target_link_libraries( 23 | raw_ptr_from_capsule INTERFACE void_ptr_from_capsule absl::statusor 24 | # python_headers does not need to be linked 25 | ) 26 | 27 | # make_shared_ptr_capsule ====================================================== 28 | 29 | add_library(make_shared_ptr_capsule INTERFACE) 30 | add_library(pybind11_abseil::cpp_capsule_tools::make_shared_ptr_capsule ALIAS 31 | make_shared_ptr_capsule) 32 | 33 | target_include_directories(make_shared_ptr_capsule 34 | INTERFACE $) 35 | 36 | # shared_ptr_from_capsule ====================================================== 37 | 38 | add_library(shared_ptr_from_capsule INTERFACE) 39 | add_library(pybind11_abseil::cpp_capsule_tools::shared_ptr_from_capsule ALIAS 40 | shared_ptr_from_capsule) 41 | 42 | target_include_directories(shared_ptr_from_capsule 43 | INTERFACE $) 44 | 45 | target_link_libraries( 46 | shared_ptr_from_capsule INTERFACE void_ptr_from_capsule absl::statusor 47 | # python_headers does not need to be linked 48 | ) 49 | -------------------------------------------------------------------------------- /pybind11_abseil/cpp_capsule_tools/make_shared_ptr_capsule.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_MAKE_SHARED_PTR_CAPSULE_H_ 2 | #define PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_MAKE_SHARED_PTR_CAPSULE_H_ 3 | 4 | // Must be first include (https://docs.python.org/3/c-api/intro.html). 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace pybind11_abseil { 11 | namespace cpp_capsule_tools { 12 | 13 | // Returns a capsule owning a dynamically allocated copy of the passed 14 | // shared_ptr, or nullptr if an error occurred. 15 | // If the return value is nullptr, the Python error indicator is set. 16 | template 17 | PyObject* MakeSharedPtrCapsule(const std::shared_ptr& sp, const char* name) { 18 | using sp_t = std::shared_ptr; 19 | std::unique_ptr sp_heap(new sp_t(sp)); // C++11 compatibility. 20 | PyObject* cap = PyCapsule_New( 21 | // Portability note. The function type underlying the pointer-to-function 22 | // type that results from implicit conversion of this lambda has not got 23 | // C-language linkage, but seems to work (and this patterns is widely 24 | // used in the pybind11 sources). 25 | sp_heap.get(), name, /* PyCapsule_Destructor */ [](PyObject* self) { 26 | // Fetch (and restore below) existing Python error, if any. 27 | // This is to not mask errors during teardown. 28 | PyObject *prev_err_type, *prev_err_value, *prev_err_traceback; 29 | PyErr_Fetch(&prev_err_type, &prev_err_value, &prev_err_traceback); 30 | const char* self_name = PyCapsule_GetName(self); 31 | if (PyErr_Occurred()) { 32 | // Something is critically wrong with the process if this happens. 33 | // Skipping deallocation of the owned shared_ptr is most likely 34 | // completely insignificant in comparison. Intentionally not 35 | // terminating the process, to not disrupt potentially in-flight 36 | // error reporting. 37 | PyErr_Print(); 38 | // Intentionally after PyErr_Print(), to rescue as much information 39 | // as possible. 40 | assert(self_name == nullptr); 41 | } else { 42 | void* void_ptr = PyCapsule_GetPointer(self, self_name); 43 | if (PyErr_Occurred()) { 44 | PyErr_Print(); // See comments above. 45 | assert(void_ptr == nullptr); 46 | } else { 47 | delete static_cast(void_ptr); 48 | } 49 | } 50 | PyErr_Restore(prev_err_type, prev_err_value, prev_err_traceback); 51 | }); 52 | if (cap != nullptr) { 53 | sp_heap.release(); 54 | } 55 | return cap; 56 | } 57 | 58 | } // namespace cpp_capsule_tools 59 | } // namespace pybind11_abseil 60 | 61 | #endif // PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_MAKE_SHARED_PTR_CAPSULE_H_ 62 | -------------------------------------------------------------------------------- /pybind11_abseil/cpp_capsule_tools/raw_ptr_from_capsule.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_RAW_PTR_FROM_CAPSULE_H_ 2 | #define PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_RAW_PTR_FROM_CAPSULE_H_ 3 | 4 | // Must be first include (https://docs.python.org/3/c-api/intro.html). 5 | #include 6 | 7 | #include "absl/status/statusor.h" 8 | #include "pybind11_abseil/cpp_capsule_tools/void_ptr_from_capsule.h" 9 | 10 | namespace pybind11_abseil { 11 | namespace cpp_capsule_tools { 12 | 13 | // Extract a raw pointer from a PyCapsule or return absl::InvalidArgumentError, 14 | // with a detailed message. 15 | // The function arguments are documented under VoidPtrFromCapsule(). 16 | // CAUTION: The returned raw pointer does (of course) not manage the lifetime 17 | // of the pointee! It is best to use the raw pointer only for the 18 | // duration of a function call, similar to e.g. std::string::c_str(), 19 | // but not to store it in any way (e.g. as a data member of a 20 | // long-lived object). 21 | template 22 | absl::StatusOr RawPtrFromCapsule(PyObject* py_obj, const char* name, 23 | const char* as_capsule_method_name) { 24 | absl::StatusOr> statusor_void_ptr = 25 | VoidPtrFromCapsule(py_obj, name, as_capsule_method_name); 26 | if (!statusor_void_ptr.ok()) { 27 | return statusor_void_ptr.status(); 28 | } 29 | Py_XDECREF(statusor_void_ptr.value().first); 30 | return static_cast(statusor_void_ptr.value().second); 31 | } 32 | 33 | } // namespace cpp_capsule_tools 34 | } // namespace pybind11_abseil 35 | 36 | #endif // PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_RAW_PTR_FROM_CAPSULE_H_ 37 | -------------------------------------------------------------------------------- /pybind11_abseil/cpp_capsule_tools/shared_ptr_from_capsule.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_SHARED_PTR_FROM_CAPSULE_H_ 2 | #define PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_SHARED_PTR_FROM_CAPSULE_H_ 3 | 4 | // Must be first include (https://docs.python.org/3/c-api/intro.html). 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "absl/status/statusor.h" 11 | #include "pybind11_abseil/cpp_capsule_tools/void_ptr_from_capsule.h" 12 | 13 | namespace pybind11_abseil { 14 | namespace cpp_capsule_tools { 15 | 16 | // Extract a shared_ptr from a PyCapsule or return absl::InvalidArgumentError, 17 | // with a detailed message. 18 | template 19 | absl::StatusOr> SharedPtrFromCapsule( 20 | PyObject* py_obj, const char* name, const char* as_capsule_method_name) { 21 | absl::StatusOr> statusor_void_ptr = 22 | VoidPtrFromCapsule(py_obj, name, as_capsule_method_name); 23 | if (!statusor_void_ptr.ok()) { 24 | return statusor_void_ptr.status(); 25 | } 26 | auto sp = *static_cast*>(statusor_void_ptr.value().second); 27 | Py_XDECREF(statusor_void_ptr.value().first); 28 | return sp; 29 | } 30 | 31 | } // namespace cpp_capsule_tools 32 | } // namespace pybind11_abseil 33 | 34 | #endif // PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_SHARED_PTR_FROM_CAPSULE_H_ 35 | -------------------------------------------------------------------------------- /pybind11_abseil/cpp_capsule_tools/void_ptr_from_capsule.cc: -------------------------------------------------------------------------------- 1 | #include "pybind11_abseil/cpp_capsule_tools/void_ptr_from_capsule.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "absl/status/status.h" 9 | #include "absl/status/statusor.h" 10 | #include "absl/strings/str_cat.h" 11 | 12 | namespace pybind11_abseil { 13 | namespace cpp_capsule_tools { 14 | 15 | namespace { 16 | 17 | // Copied from pybind11/pytypes.h, to decouple from exception handling 18 | // requirement. 19 | // Equivalent to obj.__class__.__name__ (or obj.__name__ if obj is a class). 20 | const char* obj_class_name(PyObject* obj) { 21 | if (PyType_Check(obj)) { 22 | return reinterpret_cast(obj)->tp_name; 23 | } 24 | return Py_TYPE(obj)->tp_name; 25 | } 26 | 27 | std::string quoted_name_or_null_indicator( 28 | const char* name, const char* quote = "\"", 29 | const char* null_indicator = "NULL") { 30 | return (name == nullptr ? null_indicator : absl::StrCat(quote, name, quote)); 31 | } 32 | 33 | } // namespace 34 | 35 | absl::StatusOr> VoidPtrFromCapsule( 36 | PyObject* py_obj, const char* name, const char* as_capsule_method_name) { 37 | // Note: https://docs.python.org/3/c-api/capsule.html: 38 | // The pointer argument may not be NULL. 39 | if (PyCapsule_CheckExact(py_obj)) { 40 | void* void_ptr = PyCapsule_GetPointer(py_obj, name); 41 | if (PyErr_Occurred()) { 42 | PyErr_Clear(); 43 | return absl::InvalidArgumentError(absl::StrCat( 44 | "obj is a capsule with name ", 45 | quoted_name_or_null_indicator(PyCapsule_GetName(py_obj)), " but ", 46 | quoted_name_or_null_indicator(name), " is expected.")); 47 | } 48 | return std::pair(nullptr, void_ptr); 49 | } 50 | if (as_capsule_method_name == nullptr) { 51 | return absl::InvalidArgumentError( 52 | absl::StrCat(obj_class_name(py_obj), " object is not a capsule.")); 53 | } 54 | PyObject* from_method = 55 | PyObject_CallMethod(py_obj, as_capsule_method_name, nullptr); 56 | if (from_method == nullptr) { 57 | PyObject *ptype = nullptr, *pvalue = nullptr, *ptraceback = nullptr; 58 | PyErr_Fetch(&ptype, &pvalue, &ptraceback); 59 | PyErr_NormalizeException(&ptype, &pvalue, &ptraceback); 60 | PyObject* err_msg_str = PyObject_Str(pvalue); 61 | std::string err_msg; 62 | if (err_msg_str == nullptr) { 63 | PyErr_Clear(); 64 | err_msg = ""; 65 | } else { 66 | PyObject* err_msg_bytes = 67 | PyUnicode_AsEncodedString(err_msg_str, "UTF-8", "replace"); 68 | Py_DECREF(err_msg_str); 69 | if (err_msg_bytes == nullptr) { 70 | PyErr_Clear(); 71 | err_msg = ""; 72 | } else { 73 | const char* err_msg_char_ptr = PyBytes_AsString(err_msg_bytes); 74 | if (err_msg_char_ptr == nullptr) { 75 | PyErr_Clear(); 76 | err_msg = ""; 77 | } else { 78 | err_msg = err_msg_char_ptr; 79 | } 80 | Py_DECREF(err_msg_bytes); 81 | } 82 | } 83 | return absl::InvalidArgumentError( 84 | absl::StrCat(obj_class_name(py_obj), ".", as_capsule_method_name, 85 | "() call failed: ", obj_class_name(ptype), ": ", err_msg)); 86 | } 87 | if (!PyCapsule_CheckExact(from_method)) { 88 | std::string returned_obj_type = obj_class_name(from_method); 89 | Py_DECREF(from_method); 90 | return absl::InvalidArgumentError( 91 | absl::StrCat(obj_class_name(py_obj), ".", as_capsule_method_name, 92 | "() returned an object (", returned_obj_type, 93 | ") that is not a capsule.")); 94 | } 95 | void* void_ptr = PyCapsule_GetPointer(from_method, name); 96 | if (!PyErr_Occurred()) { 97 | return std::pair(from_method, void_ptr); 98 | } 99 | PyErr_Clear(); 100 | std::string capsule_name = 101 | quoted_name_or_null_indicator(PyCapsule_GetName(from_method)); 102 | Py_DECREF(from_method); 103 | return absl::InvalidArgumentError( 104 | absl::StrCat(obj_class_name(py_obj), ".", as_capsule_method_name, 105 | "() returned a capsule with name ", capsule_name, " but ", 106 | quoted_name_or_null_indicator(name), " is expected.")); 107 | } 108 | 109 | } // namespace cpp_capsule_tools 110 | } // namespace pybind11_abseil 111 | -------------------------------------------------------------------------------- /pybind11_abseil/cpp_capsule_tools/void_ptr_from_capsule.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_VOID_PTR_FROM_CAPSULE_H_ 2 | #define PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_VOID_PTR_FROM_CAPSULE_H_ 3 | 4 | // Must be first include (https://docs.python.org/3/c-api/intro.html). 5 | #include 6 | 7 | #include 8 | 9 | #include "absl/status/statusor.h" 10 | 11 | namespace pybind11_abseil { 12 | namespace cpp_capsule_tools { 13 | 14 | // Helper for higher-level functions (e.g. RawPtrFromCapsule(), 15 | // SharedPtrFromCapsule()). 16 | // 17 | // Arguments: 18 | // If py_obj is a capsule, the capsule name is inspected. If it matches the 19 | // name argument, the raw pointer is returned. Otherwise 20 | // absl::InvalidArgumentError is returned. - Note that name can be nullptr, 21 | // and can match a nullptr capsule name. 22 | // If py_obj is not a capsule, and as_capsule_method_name is given (i.e. it 23 | // is not nullptr), the py_obj method with that name will be called without 24 | // arguments, with the expectation to receive a capsule object in return, 25 | // from which the raw pointer is then extracted exactly as described above. 26 | // A specific error message is generated for every possible error condition 27 | // (most of the code in this function is for error handling). 28 | // Return value: 29 | // The PyObject* is nullptr if the input py_obj is a capsule. 30 | // Otherwise PyObject* is the capsule obtained in the function call. 31 | // IMPORTANT: It is the responsibility of the caller to call Py_XDECREF(). 32 | absl::StatusOr> VoidPtrFromCapsule( 33 | PyObject* py_obj, const char* name, const char* as_capsule_method_name); 34 | 35 | } // namespace cpp_capsule_tools 36 | } // namespace pybind11_abseil 37 | 38 | #endif // PYBIND11_ABSEIL_CPP_CAPSULE_TOOLS_VOID_PTR_FROM_CAPSULE_H_ 39 | -------------------------------------------------------------------------------- /pybind11_abseil/display_source_location_in_python.cc: -------------------------------------------------------------------------------- 1 | #include "absl/status/status.h" 2 | #include "absl/strings/string_view.h" 3 | #include "util/task/status_builder.h" 4 | 5 | namespace pybind11 { 6 | namespace google { 7 | namespace { 8 | 9 | constexpr absl::string_view kDisplay = "1"; 10 | constexpr absl::string_view kDoNotDisplay = "0"; 11 | constexpr absl::string_view kDisplaySourceLocationInPython = 12 | "pybind11_abseil_display_source_location"; 13 | 14 | } // namespace 15 | 16 | bool HasDisplaySourceLocationInPython(absl::Status s) { 17 | auto optional_payload = s.GetPayload(kDisplaySourceLocationInPython); 18 | return optional_payload.has_value() && 19 | optional_payload.value() == kDisplay; 20 | } 21 | 22 | bool HasDoNotDisplaySourceLocationInPython(absl::Status s) { 23 | auto optional_payload = s.GetPayload(kDisplaySourceLocationInPython); 24 | return optional_payload.has_value() && 25 | optional_payload.value() == kDoNotDisplay; 26 | } 27 | 28 | absl::Status DisplaySourceLocationInPython(absl::Status s) { 29 | s.SetPayload(kDisplaySourceLocationInPython, absl::Cord(kDisplay)); 30 | return s; 31 | } 32 | 33 | absl::Status DoNotDisplaySourceLocationInPython(absl::Status s) { 34 | s.SetPayload(kDisplaySourceLocationInPython, absl::Cord(kDoNotDisplay)); 35 | return s; 36 | } 37 | 38 | util::StatusBuilder DisplaySourceLocationInPython(util::StatusBuilder sb) { 39 | return sb.SetPayload(kDisplaySourceLocationInPython, absl::Cord(kDisplay)); 40 | } 41 | 42 | util::StatusBuilder DoNotDisplaySourceLocationInPython(util::StatusBuilder sb) { 43 | return sb.SetPayload(kDisplaySourceLocationInPython, 44 | absl::Cord(kDoNotDisplay)); 45 | } 46 | 47 | } // namespace google 48 | } // namespace pybind11 49 | -------------------------------------------------------------------------------- /pybind11_abseil/display_source_location_in_python.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_DISPLAY_SOURCE_LOCATION_IN_PYTHON_H_ 2 | #define PYBIND11_ABSEIL_DISPLAY_SOURCE_LOCATION_IN_PYTHON_H_ 3 | 4 | // This file exists to simplify adding C++ source location to python StatusNotOk 5 | // traces. See: b/266066084 for details. 6 | 7 | #include "absl/status/status.h" 8 | #include "util/task/status_builder.h" 9 | 10 | namespace pybind11 { 11 | namespace google { 12 | 13 | // Return true if the status was set with DisplaySourceLocationInPython. 14 | bool HasDisplaySourceLocationInPython(absl::Status s); 15 | bool HasDoNotDisplaySourceLocationInPython(absl::Status s); 16 | 17 | // Annotate the Status to display the c++ SourceLocation in python. 18 | absl::Status DisplaySourceLocationInPython(absl::Status s); 19 | absl::Status DoNotDisplaySourceLocationInPython(absl::Status s); 20 | 21 | // Annotate the StatusBuilder to display the c++ SourceLocation in python. 22 | util::StatusBuilder DisplaySourceLocationInPython(util::StatusBuilder sb); 23 | util::StatusBuilder DoNotDisplaySourceLocationInPython(util::StatusBuilder sb); 24 | 25 | // Annotate the StatusOr to display the c++ SourceLocation in python. 26 | template 27 | StatusOrT DisplaySourceLocationInPython(StatusOrT&& s_or_t) { 28 | if (s_or_t.ok()) { 29 | return s_or_t; 30 | } 31 | absl::Status status_with_payload = DisplaySourceLocationInPython( 32 | s_or_t.status()); 33 | return StatusOrT{status_with_payload}; 34 | } 35 | 36 | template 37 | StatusOrT DoNotDisplaySourceLocationInPython(StatusOrT&& s_or_t) { 38 | if (s_or_t.ok()) { 39 | return s_or_t; 40 | } 41 | absl::Status status_with_payload = DoNotDisplaySourceLocationInPython( 42 | s_or_t.status()); 43 | return StatusOrT{status_with_payload}; 44 | } 45 | 46 | } // namespace google 47 | } // namespace pybind11 48 | 49 | #endif // PYBIND11_ABSEIL_DISPLAY_SOURCE_LOCATION_IN_PYTHON_H_ 50 | -------------------------------------------------------------------------------- /pybind11_abseil/import_status_module.cc: -------------------------------------------------------------------------------- 1 | #include "pybind11_abseil/import_status_module.h" 2 | 3 | #include 4 | 5 | namespace pybind11 { 6 | namespace google { 7 | 8 | module_ ImportStatusModule(bool bypass_regular_import) { 9 | if (!PyGILState_Check()) { 10 | pybind11_fail("ImportStatusModule() PyGILState_Check() failure."); 11 | } 12 | if (bypass_regular_import) { 13 | throw std::runtime_error( 14 | "ImportStatusModule(bypass_regular_import=true) is no longer supported." 15 | " Please change the calling code to" 16 | " call this function without arguments."); 17 | } 18 | return module_::import(PYBIND11_TOSTRING(PYBIND11_ABSEIL_STATUS_MODULE_PATH)); 19 | } 20 | 21 | } // namespace google 22 | } // namespace pybind11 23 | -------------------------------------------------------------------------------- /pybind11_abseil/import_status_module.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_IMPORT_STATUS_MODULE_H_ 2 | #define PYBIND11_ABSEIL_IMPORT_STATUS_MODULE_H_ 3 | 4 | #include 5 | 6 | // The value of PYBIND11_ABSEIL_STATUS_MODULE_PATH will be different depending 7 | // on whether this is being used inside or outside of google3. The value used 8 | // inside of google3 is defined here. Outside of google3, change this value by 9 | // passing "-DPYBIND11_ABSEIL_STATUS_MODULE_PATH=..." on the commandline. 10 | #ifndef PYBIND11_ABSEIL_STATUS_MODULE_PATH 11 | #define PYBIND11_ABSEIL_STATUS_MODULE_PATH \ 12 | pybind11_abseil.status 13 | #endif 14 | 15 | namespace pybind11 { 16 | namespace google { 17 | 18 | // Imports the bindings for the status types. This is meant to only be called 19 | // from a PYBIND11_MODULE definition. The Python GIL must be held when calling 20 | // this function (enforced). 21 | // TODO(b/225205409): Remove bypass_regular_import. 22 | // bypass_regular_import is deprecated and can only be false (enforced). 23 | module_ ImportStatusModule(bool bypass_regular_import = false); 24 | 25 | } // namespace google 26 | } // namespace pybind11 27 | 28 | #endif // PYBIND11_ABSEIL_IMPORT_STATUS_MODULE_H_ 29 | -------------------------------------------------------------------------------- /pybind11_abseil/init_from_tag.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_INIT_FROM_TAG_H_ 2 | #define PYBIND11_ABSEIL_INIT_FROM_TAG_H_ 3 | 4 | namespace pybind11 { 5 | namespace google { 6 | 7 | enum struct InitFromTag { capsule, capsule_direct_only, serialized }; 8 | 9 | } // namespace google 10 | } // namespace pybind11 11 | 12 | #endif // PYBIND11_ABSEIL_INIT_FROM_TAG_H_ 13 | -------------------------------------------------------------------------------- /pybind11_abseil/no_throw_status.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_NO_THROW_STATUS_H_ 2 | #define PYBIND11_ABSEIL_NO_THROW_STATUS_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace pybind11 { 8 | namespace google { 9 | 10 | // Wrapper type to signal to the type_caster that a non-ok status should not 11 | // be converted into an object rather than a thrown exception. StatusType can 12 | // encapsulate references, e.g. `NoThrowStatus`. 13 | template 14 | struct NoThrowStatus { 15 | NoThrowStatus() = default; 16 | NoThrowStatus(StatusType status_in) 17 | : status(std::forward(status_in)) {} 18 | StatusType status; 19 | }; 20 | 21 | // Convert a absl::Status(Or) into a NoThrowStatus. To use this with references, 22 | // explicitly specify the template parameter rather deducing it, e.g.: 23 | // `return DoNotThrowStatus(my_status);` 24 | // When returning a status by value (by far the most common case), deducing the 25 | // template parameter is fine, e.g.: `return DoNotThrowStatus(my_status);` 26 | template 27 | NoThrowStatus DoNotThrowStatus(StatusType status) { 28 | return NoThrowStatus(std::forward(status)); 29 | } 30 | // Convert a function returning a absl::Status(Or) into a function 31 | // returning a NoThrowStatus. 32 | template 33 | std::function(Args...)> DoNotThrowStatus( 34 | std::function f) { 35 | return [f = std::move(f)](Args&&... args) { 36 | return NoThrowStatus( 37 | std::forward(f(std::forward(args)...))); 38 | }; 39 | } 40 | template 41 | std::function(Args...)> DoNotThrowStatus( 42 | StatusType (*f)(Args...)) { 43 | return [f](Args&&... args) { 44 | return NoThrowStatus( 45 | std::forward(f(std::forward(args)...))); 46 | }; 47 | } 48 | template 49 | std::function(Class*, Args...)> DoNotThrowStatus( 50 | StatusType (Class::*f)(Args...)) { 51 | return [f](Class* c, Args&&... args) { 52 | return NoThrowStatus( 53 | std::forward((c->*f)(std::forward(args)...))); 54 | }; 55 | } 56 | template 57 | std::function(const Class*, Args...)> 58 | DoNotThrowStatus(StatusType (Class::*f)(Args...) const) { 59 | return [f](const Class* c, Args&&... args) { 60 | return NoThrowStatus( 61 | std::forward((c->*f)(std::forward(args)...))); 62 | }; 63 | } 64 | 65 | } // namespace google 66 | } // namespace pybind11 67 | 68 | #endif // PYBIND11_ABSEIL_NO_THROW_STATUS_H_ 69 | -------------------------------------------------------------------------------- /pybind11_abseil/ok_status_singleton_lib.cc: -------------------------------------------------------------------------------- 1 | #include "pybind11_abseil/ok_status_singleton_lib.h" 2 | 3 | #include 4 | 5 | #include "absl/status/status.h" 6 | 7 | namespace pybind11_abseil { 8 | 9 | const absl::Status* OkStatusSingleton() { 10 | static const absl::Status* singleton = new absl::Status(); 11 | return singleton; 12 | } 13 | 14 | PyObject* PyOkStatusSingleton() { 15 | static bool first_call = true; 16 | static PyObject* py_singleton = nullptr; 17 | if (first_call) { 18 | PyObject* imported_mod = 19 | PyImport_ImportModule("pybind11_abseil.status"); 20 | if (imported_mod == nullptr) { 21 | PyErr_Clear(); 22 | py_singleton = 23 | PyCapsule_New(const_cast(OkStatusSingleton()), 24 | "::absl::Status", nullptr); 25 | first_call = false; 26 | if (py_singleton == nullptr) { 27 | return nullptr; 28 | } 29 | } else { 30 | PyObject* make_fn = 31 | PyObject_GetAttrString(imported_mod, "_make_py_ok_status_singleton"); 32 | Py_DECREF(imported_mod); 33 | if (make_fn == nullptr) { 34 | first_call = false; 35 | return nullptr; 36 | } 37 | PyObject* call_result = PyObject_CallObject(make_fn, nullptr); 38 | Py_DECREF(make_fn); 39 | if (call_result == nullptr) { 40 | first_call = false; 41 | return nullptr; 42 | } 43 | assert(call_result != Py_None); 44 | py_singleton = call_result; 45 | } 46 | first_call = false; 47 | } 48 | if (py_singleton == nullptr) { 49 | PyErr_SetString(PyExc_SystemError, 50 | "FAILED: pybind11_abseil::PyOkStatusSingleton()"); 51 | return nullptr; 52 | } 53 | Py_INCREF(py_singleton); 54 | return py_singleton; 55 | } 56 | 57 | } // namespace pybind11_abseil 58 | -------------------------------------------------------------------------------- /pybind11_abseil/ok_status_singleton_lib.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_OK_STATUS_SINGLETON_LIB_H_ 2 | #define PYBIND11_ABSEIL_OK_STATUS_SINGLETON_LIB_H_ 3 | 4 | #include 5 | 6 | #include "absl/status/status.h" 7 | 8 | namespace pybind11_abseil { 9 | 10 | const absl::Status* OkStatusSingleton(); 11 | PyObject* PyOkStatusSingleton(); 12 | 13 | } // namespace pybind11_abseil 14 | 15 | #endif // PYBIND11_ABSEIL_OK_STATUS_SINGLETON_LIB_H_ 16 | -------------------------------------------------------------------------------- /pybind11_abseil/ok_status_singleton_py_extension_stub.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" PyObject* 4 | GooglePyInit_google3_third__party_pybind11__abseil_ok__status__singleton(); 5 | 6 | // Required only for OSS, but also compatible with the Google toolchain. 7 | #if defined(WIN32) || defined(_WIN32) 8 | #define LOCALDEFINE_DLLEXPORT __declspec(dllexport) 9 | #else 10 | #define LOCALDEFINE_DLLEXPORT __attribute__((visibility("default"))) 11 | #endif 12 | 13 | extern "C" LOCALDEFINE_DLLEXPORT PyObject* PyInit_ok_status_singleton() { 14 | // NOLINTNEXTLINE(whitespace/line_length) 15 | return GooglePyInit_google3_third__party_pybind11__abseil_ok__status__singleton(); 16 | } 17 | -------------------------------------------------------------------------------- /pybind11_abseil/ok_status_singleton_pyinit_google3.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "pybind11_abseil/ok_status_singleton_lib.h" 4 | 5 | namespace { 6 | 7 | static PyObject* wrapOkStatusSingleton(PyObject*, PyObject*) { 8 | return pybind11_abseil::PyOkStatusSingleton(); 9 | } 10 | 11 | static PyMethodDef ThisMethodDef[] = { 12 | {"OkStatusSingleton", wrapOkStatusSingleton, METH_NOARGS, 13 | "OkStatusSingleton() -> capsule"}, 14 | {}}; 15 | 16 | static struct PyModuleDef ThisModuleDef = { 17 | PyModuleDef_HEAD_INIT, // m_base 18 | "ok_status_singleton", // m_name 19 | nullptr, // m_doc 20 | -1, // m_size 21 | ThisMethodDef, // m_methods 22 | nullptr, // m_slots 23 | nullptr, // m_traverse 24 | nullptr, // m_clear 25 | nullptr // m_free 26 | }; 27 | 28 | } // namespace 29 | 30 | extern "C" PyObject* 31 | GooglePyInit_google3_third__party_pybind11__abseil_ok__status__singleton() { 32 | return PyModule_Create(&ThisModuleDef); 33 | } 34 | -------------------------------------------------------------------------------- /pybind11_abseil/register_status_bindings.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_REGISTER_STATUS_BINDINGS_H_ 2 | #define PYBIND11_ABSEIL_REGISTER_STATUS_BINDINGS_H_ 3 | 4 | #include 5 | 6 | namespace pybind11 { 7 | namespace google { 8 | namespace internal { 9 | 10 | // Registers the bindings for the status types in the given module. Can only 11 | // be called once; subsequent calls will fail due to duplicate registrations. 12 | void RegisterStatusBindings(module m); 13 | 14 | } // namespace internal 15 | } // namespace google 16 | } // namespace pybind11 17 | 18 | #endif // PYBIND11_ABSEIL_REGISTER_STATUS_BINDINGS_H_ 19 | -------------------------------------------------------------------------------- /pybind11_abseil/requirements/BUILD: -------------------------------------------------------------------------------- 1 | load("@python//3.10:defs.bzl", compile_pip_requirements_3_10 = "compile_pip_requirements") 2 | load("@python//3.11:defs.bzl", compile_pip_requirements_3_11 = "compile_pip_requirements") 3 | load("@python//3.12:defs.bzl", compile_pip_requirements_3_12 = "compile_pip_requirements") 4 | load("@python//3.8:defs.bzl", compile_pip_requirements_3_8 = "compile_pip_requirements") 5 | load("@python//3.9:defs.bzl", compile_pip_requirements_3_9 = "compile_pip_requirements") 6 | 7 | package( 8 | default_visibility = ["//visibility:private"], 9 | ) 10 | 11 | compile_pip_requirements_3_12( 12 | name = "requirements_3_12", 13 | src = "requirements.in", 14 | requirements_txt = "requirements_lock_3_12.txt", 15 | ) 16 | 17 | compile_pip_requirements_3_11( 18 | name = "requirements_3_11", 19 | src = "requirements.in", 20 | requirements_txt = "requirements_lock_3_11.txt", 21 | ) 22 | 23 | compile_pip_requirements_3_10( 24 | name = "requirements_3_10", 25 | src = "requirements.in", 26 | requirements_txt = "requirements_lock_3_10.txt", 27 | ) 28 | 29 | compile_pip_requirements_3_9( 30 | name = "requirements_3_9", 31 | src = "requirements.in", 32 | requirements_txt = "requirements_lock_3_9.txt", 33 | ) 34 | 35 | compile_pip_requirements_3_8( 36 | name = "requirements_3_8", 37 | src = "requirements.in", 38 | requirements_txt = "requirements_lock_3_8.txt", 39 | ) 40 | -------------------------------------------------------------------------------- /pybind11_abseil/requirements/requirements.in: -------------------------------------------------------------------------------- 1 | absl-py 2 | numpy 3 | -------------------------------------------------------------------------------- /pybind11_abseil/requirements/requirements_lock_3_10.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.10 3 | # by the following command: 4 | # 5 | # bazel run //pybind11_abseil/requirements:requirements_3_10.update 6 | # 7 | absl-py==2.1.0 \ 8 | --hash=sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308 \ 9 | --hash=sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff 10 | # via -r pybind11_abseil/requirements/requirements.in 11 | numpy==1.26.4 \ 12 | --hash=sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b \ 13 | --hash=sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818 \ 14 | --hash=sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20 \ 15 | --hash=sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0 \ 16 | --hash=sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010 \ 17 | --hash=sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a \ 18 | --hash=sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea \ 19 | --hash=sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c \ 20 | --hash=sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71 \ 21 | --hash=sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110 \ 22 | --hash=sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be \ 23 | --hash=sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a \ 24 | --hash=sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a \ 25 | --hash=sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5 \ 26 | --hash=sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed \ 27 | --hash=sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd \ 28 | --hash=sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c \ 29 | --hash=sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e \ 30 | --hash=sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0 \ 31 | --hash=sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c \ 32 | --hash=sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a \ 33 | --hash=sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b \ 34 | --hash=sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0 \ 35 | --hash=sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6 \ 36 | --hash=sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2 \ 37 | --hash=sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a \ 38 | --hash=sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30 \ 39 | --hash=sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218 \ 40 | --hash=sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5 \ 41 | --hash=sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07 \ 42 | --hash=sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2 \ 43 | --hash=sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4 \ 44 | --hash=sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764 \ 45 | --hash=sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef \ 46 | --hash=sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3 \ 47 | --hash=sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f 48 | # via -r pybind11_abseil/requirements/requirements.in 49 | -------------------------------------------------------------------------------- /pybind11_abseil/requirements/requirements_lock_3_11.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.11 3 | # by the following command: 4 | # 5 | # bazel run //pybind11_abseil/requirements:requirements_3_11.update 6 | # 7 | absl-py==2.1.0 \ 8 | --hash=sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308 \ 9 | --hash=sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff 10 | # via -r pybind11_abseil/requirements/requirements.in 11 | numpy==1.26.4 \ 12 | --hash=sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b \ 13 | --hash=sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818 \ 14 | --hash=sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20 \ 15 | --hash=sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0 \ 16 | --hash=sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010 \ 17 | --hash=sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a \ 18 | --hash=sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea \ 19 | --hash=sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c \ 20 | --hash=sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71 \ 21 | --hash=sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110 \ 22 | --hash=sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be \ 23 | --hash=sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a \ 24 | --hash=sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a \ 25 | --hash=sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5 \ 26 | --hash=sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed \ 27 | --hash=sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd \ 28 | --hash=sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c \ 29 | --hash=sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e \ 30 | --hash=sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0 \ 31 | --hash=sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c \ 32 | --hash=sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a \ 33 | --hash=sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b \ 34 | --hash=sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0 \ 35 | --hash=sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6 \ 36 | --hash=sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2 \ 37 | --hash=sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a \ 38 | --hash=sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30 \ 39 | --hash=sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218 \ 40 | --hash=sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5 \ 41 | --hash=sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07 \ 42 | --hash=sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2 \ 43 | --hash=sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4 \ 44 | --hash=sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764 \ 45 | --hash=sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef \ 46 | --hash=sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3 \ 47 | --hash=sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f 48 | # via -r pybind11_abseil/requirements/requirements.in 49 | -------------------------------------------------------------------------------- /pybind11_abseil/requirements/requirements_lock_3_12.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.12 3 | # by the following command: 4 | # 5 | # bazel run //pybind11_abseil/requirements:requirements_3_12.update 6 | # 7 | absl-py==2.1.0 \ 8 | --hash=sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308 \ 9 | --hash=sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff 10 | # via -r pybind11_abseil/requirements/requirements.in 11 | numpy==1.26.4 \ 12 | --hash=sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b \ 13 | --hash=sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818 \ 14 | --hash=sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20 \ 15 | --hash=sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0 \ 16 | --hash=sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010 \ 17 | --hash=sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a \ 18 | --hash=sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea \ 19 | --hash=sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c \ 20 | --hash=sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71 \ 21 | --hash=sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110 \ 22 | --hash=sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be \ 23 | --hash=sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a \ 24 | --hash=sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a \ 25 | --hash=sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5 \ 26 | --hash=sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed \ 27 | --hash=sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd \ 28 | --hash=sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c \ 29 | --hash=sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e \ 30 | --hash=sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0 \ 31 | --hash=sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c \ 32 | --hash=sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a \ 33 | --hash=sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b \ 34 | --hash=sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0 \ 35 | --hash=sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6 \ 36 | --hash=sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2 \ 37 | --hash=sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a \ 38 | --hash=sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30 \ 39 | --hash=sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218 \ 40 | --hash=sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5 \ 41 | --hash=sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07 \ 42 | --hash=sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2 \ 43 | --hash=sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4 \ 44 | --hash=sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764 \ 45 | --hash=sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef \ 46 | --hash=sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3 \ 47 | --hash=sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f 48 | # via -r pybind11_abseil/requirements/requirements.in 49 | -------------------------------------------------------------------------------- /pybind11_abseil/requirements/requirements_lock_3_8.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.8 3 | # by the following command: 4 | # 5 | # bazel run //pybind11_abseil/requirements:requirements_3_8.update 6 | # 7 | absl-py==2.1.0 \ 8 | --hash=sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308 \ 9 | --hash=sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff 10 | # via -r pybind11_abseil/requirements/requirements.in 11 | numpy==1.24.4 \ 12 | --hash=sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f \ 13 | --hash=sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61 \ 14 | --hash=sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7 \ 15 | --hash=sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400 \ 16 | --hash=sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef \ 17 | --hash=sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2 \ 18 | --hash=sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d \ 19 | --hash=sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc \ 20 | --hash=sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835 \ 21 | --hash=sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706 \ 22 | --hash=sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5 \ 23 | --hash=sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4 \ 24 | --hash=sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6 \ 25 | --hash=sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463 \ 26 | --hash=sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a \ 27 | --hash=sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f \ 28 | --hash=sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e \ 29 | --hash=sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e \ 30 | --hash=sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694 \ 31 | --hash=sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8 \ 32 | --hash=sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64 \ 33 | --hash=sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d \ 34 | --hash=sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc \ 35 | --hash=sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254 \ 36 | --hash=sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2 \ 37 | --hash=sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1 \ 38 | --hash=sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810 \ 39 | --hash=sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9 40 | # via -r pybind11_abseil/requirements/requirements.in 41 | -------------------------------------------------------------------------------- /pybind11_abseil/requirements/requirements_lock_3_9.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.9 3 | # by the following command: 4 | # 5 | # bazel run //pybind11_abseil/requirements:requirements_3_9.update 6 | # 7 | absl-py==2.1.0 \ 8 | --hash=sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308 \ 9 | --hash=sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff 10 | # via -r pybind11_abseil/requirements/requirements.in 11 | numpy==1.26.4 \ 12 | --hash=sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b \ 13 | --hash=sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818 \ 14 | --hash=sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20 \ 15 | --hash=sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0 \ 16 | --hash=sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010 \ 17 | --hash=sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a \ 18 | --hash=sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea \ 19 | --hash=sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c \ 20 | --hash=sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71 \ 21 | --hash=sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110 \ 22 | --hash=sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be \ 23 | --hash=sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a \ 24 | --hash=sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a \ 25 | --hash=sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5 \ 26 | --hash=sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed \ 27 | --hash=sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd \ 28 | --hash=sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c \ 29 | --hash=sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e \ 30 | --hash=sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0 \ 31 | --hash=sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c \ 32 | --hash=sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a \ 33 | --hash=sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b \ 34 | --hash=sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0 \ 35 | --hash=sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6 \ 36 | --hash=sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2 \ 37 | --hash=sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a \ 38 | --hash=sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30 \ 39 | --hash=sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218 \ 40 | --hash=sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5 \ 41 | --hash=sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07 \ 42 | --hash=sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2 \ 43 | --hash=sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4 \ 44 | --hash=sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764 \ 45 | --hash=sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef \ 46 | --hash=sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3 \ 47 | --hash=sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f 48 | # via -r pybind11_abseil/requirements/requirements.in 49 | -------------------------------------------------------------------------------- /pybind11_abseil/status_caster.h: -------------------------------------------------------------------------------- 1 | // Author: Ken Oslund (kenoslund@) 2 | 3 | // IWYU pragma: always_keep // See pybind11/docs/type_caster_iwyu.rst 4 | 5 | #ifndef PYBIND11_ABSEIL_STATUS_CASTER_H_ 6 | #define PYBIND11_ABSEIL_STATUS_CASTER_H_ 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "absl/status/status.h" 16 | #include "pybind11_abseil/check_status_module_imported.h" 17 | #include "pybind11_abseil/compat/status_from_py_exc.h" 18 | #include "pybind11_abseil/cpp_capsule_tools/raw_ptr_from_capsule.h" 19 | #include "pybind11_abseil/no_throw_status.h" 20 | #include "pybind11_abseil/ok_status_singleton_lib.h" 21 | #include "pybind11_abseil/status_not_ok_exception.h" 22 | 23 | namespace pybind11 { 24 | namespace detail { 25 | 26 | template 27 | struct NoThrowStatusType { 28 | // NoThrowStatus should only wrap absl::Status or absl::StatusOr. 29 | using NoThrowAbslStatus = type_caster_base; 30 | static constexpr auto name = NoThrowAbslStatus::name; 31 | }; 32 | 33 | // Convert NoThrowStatus by dispatching to a caster for StatusType with the 34 | // argument throw_exception = false. StatusType should be an absl::Status 35 | // (rvalue, lvalue, reference, or pointer), or an absl::StatusOr value. 36 | // Only return values trigger exceptions, so NoThrowStatus has no meaning for 37 | // input values. Therefore only C++->Python casting is supported. 38 | template 39 | struct type_caster> { 40 | using InputType = google::NoThrowStatus; 41 | using StatusCaster = make_caster; 42 | static constexpr auto name = NoThrowStatusType::name; 43 | 44 | // Convert C++->Python. 45 | static handle cast(const InputType& src, return_value_policy policy, 46 | handle parent) { 47 | // pybind11::cast applies a const qualifier, so this takes a const reference 48 | // argument. The qualifiers we care about are in StatusType, and we will 49 | // forward those, but to do so, we must strip the const off the InputType. 50 | return StatusCaster::cast( 51 | std::forward(const_cast(src).status), policy, 52 | parent, false); 53 | } 54 | }; 55 | 56 | // Convert absl::Status. 57 | template <> 58 | struct type_caster : public type_caster_base { 59 | public: 60 | static constexpr auto name = const_name("None"); 61 | // Convert C++ -> Python. 62 | static handle cast(const absl::Status* src, return_value_policy policy, 63 | handle parent, bool throw_exception = true) { 64 | if (!src) return none().release(); 65 | return cast_impl(*src, policy, parent, throw_exception); 66 | } 67 | 68 | static handle cast(const absl::Status& src, return_value_policy policy, 69 | handle parent, bool throw_exception = true) { 70 | return cast_impl(src, policy, parent, throw_exception); 71 | } 72 | 73 | static handle cast(absl::Status&& src, return_value_policy policy, 74 | handle parent, bool throw_exception = true) { 75 | return cast_impl(std::move(src), policy, parent, throw_exception); 76 | } 77 | 78 | bool load(handle src, bool convert) { 79 | if (type_caster_base::load(src, convert)) { 80 | // Behavior change 2023-02-09: previously `value` was simply left as 81 | // `nullptr`. 82 | if (!value) { 83 | value = const_cast(pybind11_abseil::OkStatusSingleton()); 84 | } 85 | return true; 86 | } 87 | if (convert) { 88 | absl::StatusOr raw_ptr = 89 | pybind11_abseil::cpp_capsule_tools::RawPtrFromCapsule( 90 | src.ptr(), "::absl::Status", "as_absl_Status"); 91 | if (raw_ptr.ok()) { 92 | value = raw_ptr.value(); 93 | return true; 94 | } 95 | } 96 | return false; 97 | } 98 | 99 | private: 100 | template 101 | static handle cast_impl(CType&& src, return_value_policy policy, 102 | handle parent, bool throw_exception) { 103 | google::internal::CheckStatusModuleImported(); 104 | #if defined(PYBIND11_HAS_RETURN_VALUE_POLICY_CLIF_AUTOMATIC) 105 | if (src.ok() && policy == return_value_policy::_clif_automatic) { 106 | return pybind11_abseil::PyOkStatusSingleton(); 107 | } 108 | #endif 109 | if (!throw_exception) { 110 | // Use the built-in/standard pybind11 caster. 111 | return type_caster_base::cast(std::forward(src), 112 | policy, parent); 113 | } else if (!src.ok()) { 114 | // Convert a non-ok status into an exception. 115 | throw google::StatusNotOk(std::forward(src)); 116 | } else { 117 | // Return none for an ok status. 118 | return none().release(); 119 | } 120 | } 121 | }; 122 | 123 | #if defined(PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS) 124 | 125 | // IMPORTANT: 126 | // KEEP 127 | // type_caster 128 | // func_wrapper 129 | // IN THE SAME HEADER FILE 130 | // to avoid surprising behavior differences and ODR violations. 131 | 132 | namespace type_caster_std_function_specializations { 133 | 134 | template 135 | struct func_wrapper : func_wrapper_base { 136 | using func_wrapper_base::func_wrapper_base; 137 | // NOTE: `noexcept` to guarantee that no C++ exception will ever escape. 138 | absl::Status operator()(Args... args) const noexcept { 139 | gil_scoped_acquire acq; 140 | try { 141 | object py_result = 142 | #if defined(PYBIND11_HAS_RETURN_VALUE_POLICY_PACK) 143 | hfunc.f.call_with_policies(rvpp, std::forward(args)...); 144 | #else 145 | hfunc.f(std::forward(args)...); 146 | #endif 147 | try { 148 | return py_result.template cast(); 149 | } catch (cast_error& e) { 150 | return absl::Status(absl::StatusCode::kInvalidArgument, e.what()); 151 | } 152 | } 153 | // All exceptions derived from std::exception are handled here: 154 | // https://github.com/pybind/pybind11/blob/aec6cc5406edb076f5a489c2d7f84bb07052c4a3/include/pybind11/detail/internals.h#L363-L420 155 | // Design choice for safety: Intentionally no `catch (...)`: 156 | // Occurrence of such exceptions in this context is considered a bug in 157 | // user code. The `noexcept` above will lead to process termination. 158 | catch (error_already_set& e) { 159 | e.restore(); 160 | return pybind11_abseil::compat::StatusFromPyExcGivenErrOccurred(); 161 | } 162 | } 163 | }; 164 | 165 | } // namespace type_caster_std_function_specializations 166 | 167 | #endif 168 | 169 | } // namespace detail 170 | } // namespace pybind11 171 | 172 | #endif // PYBIND11_ABSEIL_STATUS_CASTER_H_ 173 | -------------------------------------------------------------------------------- /pybind11_abseil/status_casters.h: -------------------------------------------------------------------------------- 1 | // DEPRECATED: Please prefer including the headers below directly. 2 | 3 | #ifndef PYBIND11_ABSEIL_STATUS_CASTERS_H_ 4 | #define PYBIND11_ABSEIL_STATUS_CASTERS_H_ 5 | 6 | #include "pybind11_abseil/status_caster.h" 7 | #include "pybind11_abseil/statusor_caster.h" 8 | #include "pybind11_abseil/import_status_module.h" 9 | 10 | #endif // PYBIND11_ABSEIL_STATUS_CASTERS_H_ 11 | -------------------------------------------------------------------------------- /pybind11_abseil/status_not_ok_exception.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_STATUS_NOT_OK_EXCEPTION_H_ 2 | #define PYBIND11_ABSEIL_STATUS_NOT_OK_EXCEPTION_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "absl/status/status.h" 9 | 10 | namespace pybind11 { 11 | namespace google { 12 | 13 | // Exception class which represents a non-ok status. 14 | // 15 | // This is in the pybind::google namespace because it was originally created to 16 | // use with pybind11, but it does NOT depend on the pybind11 library. 17 | class StatusNotOk : public std::exception { 18 | public: 19 | StatusNotOk(absl::Status&& status) 20 | : status_(std::move(status)), 21 | what_(status_.ToString(absl::StatusToStringMode::kWithEverything)) {} 22 | StatusNotOk(const absl::Status& status) 23 | : status_(status), 24 | what_(status_.ToString(absl::StatusToStringMode::kWithEverything)) {} 25 | const absl::Status& status() const& { return status_; } 26 | absl::Status&& status() && { return std::move(status_); } 27 | const char* what() const noexcept override { return what_.c_str(); } 28 | 29 | private: 30 | absl::Status status_; 31 | std::string what_; 32 | }; 33 | 34 | } // namespace google 35 | } // namespace pybind11 36 | 37 | #endif // PYBIND11_ABSEIL_STATUS_NOT_OK_EXCEPTION_H_ 38 | -------------------------------------------------------------------------------- /pybind11_abseil/status_py_extension_stub.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" PyObject* 4 | GooglePyInit_google3_third__party_pybind11__abseil_status(); 5 | 6 | // Required only for OSS, but also compatible with the Google toolchain. 7 | #if defined(WIN32) || defined(_WIN32) 8 | #define LOCALDEFINE_DLLEXPORT __declspec(dllexport) 9 | #else 10 | #define LOCALDEFINE_DLLEXPORT __attribute__((visibility("default"))) 11 | #endif 12 | 13 | extern "C" LOCALDEFINE_DLLEXPORT PyObject* PyInit_status() { 14 | return GooglePyInit_google3_third__party_pybind11__abseil_status(); 15 | } 16 | -------------------------------------------------------------------------------- /pybind11_abseil/status_pyinit_google3.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "pybind11_abseil/register_status_bindings.h" 5 | 6 | namespace { 7 | 8 | PyObject* this_module_init() noexcept { 9 | PYBIND11_CHECK_PYTHON_VERSION 10 | PYBIND11_ENSURE_INTERNALS_READY 11 | static pybind11::module_::module_def module_def_status; 12 | auto m = pybind11::module_::create_extension_module("status", nullptr, 13 | &module_def_status); 14 | try { 15 | pybind11::google::internal::RegisterStatusBindings(m); 16 | return m.ptr(); 17 | } 18 | PYBIND11_CATCH_INIT_EXCEPTIONS 19 | } 20 | 21 | } // namespace 22 | 23 | extern "C" PyObject* 24 | GooglePyInit_google3_third__party_pybind11__abseil_status() { 25 | return this_module_init(); 26 | } 27 | -------------------------------------------------------------------------------- /pybind11_abseil/statusor_caster.h: -------------------------------------------------------------------------------- 1 | // Author: Ken Oslund (kenoslund@) 2 | 3 | // IWYU pragma: always_keep // See pybind11/docs/type_caster_iwyu.rst 4 | 5 | #ifndef PYBIND11_ABSEIL_STATUSOR_CASTER_H_ 6 | #define PYBIND11_ABSEIL_STATUSOR_CASTER_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "absl/status/status.h" 17 | #include "absl/status/statusor.h" 18 | #include "pybind11_abseil/check_status_module_imported.h" 19 | #include "pybind11_abseil/compat/status_from_py_exc.h" 20 | #include "pybind11_abseil/no_throw_status.h" 21 | #include "pybind11_abseil/status_caster.h" 22 | 23 | namespace pybind11 { 24 | namespace detail { 25 | 26 | template 27 | struct NoThrowStatusType> { 28 | using NoThrowAbslStatus = type_caster_base; 29 | static constexpr auto name = const_name("Union[") + NoThrowAbslStatus::name + 30 | const_name(", ") + 31 | make_caster::name + const_name("]"); 32 | }; 33 | 34 | // Convert absl::StatusOr. 35 | // It isn't possible to specify separate return value policies for the container 36 | // (StatusOr) and the payload. Since StatusOr is processed and not ever actually 37 | // represented in python, the return value policy applies to the payload. Eg, if 38 | // you return a StatusOr (note the * is inside the StatusOr) with a 39 | // take_ownership return val policy and the status is ok (ie, it has a payload), 40 | // python will take ownership of that payload and free it when it is garbage 41 | // collected. 42 | // However, if you return a StatusOr* (note the * is outside the 43 | // StatusOr rather than inside it now) with a take_ownership return val policy, 44 | // python does not take ownership of the StatusOr and will not free it (because 45 | // again, that policy applies to MyObject, not StatusOr). 46 | template 47 | struct type_caster> { 48 | public: 49 | using PayloadCaster = make_caster; 50 | using StatusCaster = make_caster; 51 | 52 | #if defined(PYBIND11_HAS_RETURN_VALUE_POLICY_PACK) 53 | using return_value_policy_t = const return_value_policy_pack&; 54 | PYBIND11_TYPE_CASTER_RVPP(absl::StatusOr, PayloadCaster::name); 55 | #else 56 | using return_value_policy_t = return_value_policy; 57 | PYBIND11_TYPE_CASTER(absl::StatusOr, PayloadCaster::name); 58 | #endif 59 | 60 | bool load(handle src, bool convert) { 61 | PayloadCaster payload_caster; 62 | if (payload_caster.load(src, convert)) { 63 | value = cast_op(std::move(payload_caster)); 64 | return true; 65 | } 66 | if (src.is_none()) { 67 | throw cast_error( 68 | "None is not a valid value for a StatusOr argument."); 69 | } 70 | StatusCaster status_caster; 71 | if (status_caster.load(src, convert)) { 72 | absl::Status status = cast_op(std::move(status_caster)); 73 | if (status.ok()) { 74 | throw cast_error( 75 | "An OK status is not a valid constructor argument to StatusOr."); 76 | } else { 77 | value = status; 78 | } 79 | return true; 80 | } 81 | return false; 82 | } 83 | 84 | // Convert C++ -> Python. 85 | static handle cast(const absl::StatusOr* src, 86 | return_value_policy_t policy, handle parent, 87 | bool throw_exception = true) { 88 | if (!src) return none().release(); 89 | return cast_impl(*src, policy, parent, throw_exception); 90 | } 91 | 92 | static handle cast(const absl::StatusOr& src, 93 | return_value_policy_t policy, handle parent, 94 | bool throw_exception = true) { 95 | return cast_impl(src, policy, parent, throw_exception); 96 | } 97 | 98 | static handle cast(absl::StatusOr&& src, 99 | return_value_policy_t policy, handle parent, 100 | bool throw_exception = true) { 101 | return cast_impl(std::move(src), policy, parent, throw_exception); 102 | } 103 | 104 | private: 105 | template 106 | static handle cast_impl(CType&& src, return_value_policy_t policy, 107 | handle parent, bool throw_exception) { 108 | google::internal::CheckStatusModuleImported(); 109 | if (src.ok()) { 110 | // Convert and return the payload. 111 | #if defined(PYBIND11_HAS_RETURN_VALUE_POLICY_PACK) 112 | auto policy_for_payload = policy.get(0); 113 | #else 114 | auto policy_for_payload = policy; 115 | #endif 116 | return PayloadCaster::cast(std::forward(src).value(), 117 | policy_for_payload, parent); 118 | } else { 119 | // Convert and return the error. 120 | return StatusCaster::cast(std::forward(src).status(), 121 | return_value_policy::move, parent, 122 | throw_exception); 123 | } 124 | } 125 | }; 126 | 127 | #if defined(PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS) 128 | 129 | // IMPORTANT: 130 | // KEEP 131 | // type_caster> 132 | // func_wrapper, Args...> 133 | // IN THE SAME HEADER FILE 134 | // to avoid surprising behavior differences and ODR violations. 135 | 136 | namespace type_caster_std_function_specializations { 137 | 138 | template 139 | struct func_wrapper, Args...> : func_wrapper_base { 140 | using func_wrapper_base::func_wrapper_base; 141 | // NOTE: `noexcept` to guarantee that no C++ exception will ever escape. 142 | absl::StatusOr operator()(Args... args) const noexcept { 143 | gil_scoped_acquire acq; 144 | try { 145 | object py_result = 146 | #if defined(PYBIND11_HAS_RETURN_VALUE_POLICY_PACK) 147 | hfunc.f.call_with_policies(rvpp, std::forward(args)...); 148 | #else 149 | hfunc.f(std::forward(args)...); 150 | #endif 151 | try { 152 | auto cpp_result = 153 | py_result.template cast>(); 154 | // Intentionally not `if constexpr`: runtime overhead is insignificant. 155 | if (is_same_ignoring_cvref::value) { 156 | // Ownership of the Python reference was transferred to cpp_result. 157 | py_result.release(); 158 | } 159 | return cpp_result; 160 | } catch (cast_error& e) { 161 | return absl::Status(absl::StatusCode::kInvalidArgument, e.what()); 162 | } 163 | } 164 | // See comment for the corresponding `catch` in status_caster.h. 165 | catch (error_already_set& e) { 166 | e.restore(); 167 | return pybind11_abseil::compat::StatusFromPyExcGivenErrOccurred(); 168 | } 169 | } 170 | }; 171 | 172 | } // namespace type_caster_std_function_specializations 173 | 174 | #endif 175 | 176 | } // namespace detail 177 | } // namespace pybind11 178 | 179 | #endif // PYBIND11_ABSEIL_STATUSOR_CASTER_H_ 180 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/BUILD: -------------------------------------------------------------------------------- 1 | # Tests and examples for pybind11_abseil. 2 | 3 | load("@pybind11_bazel//:build_defs.bzl", "pybind_extension", "pybind_library") 4 | load("@pypi//:requirements.bzl", "requirement") 5 | 6 | licenses(["notice"]) 7 | 8 | pybind_extension( 9 | name = "cpp_capsule_tools_testing", 10 | srcs = ["cpp_capsule_tools_testing.cc"], 11 | deps = [ 12 | "//pybind11_abseil/cpp_capsule_tools:make_shared_ptr_capsule", 13 | "//pybind11_abseil/cpp_capsule_tools:raw_ptr_from_capsule", 14 | "//pybind11_abseil/cpp_capsule_tools:shared_ptr_from_capsule", 15 | "@com_google_absl//absl/status:statusor", 16 | ], 17 | ) 18 | 19 | py_test( 20 | name = "cpp_capsule_tools_testing_test", 21 | srcs = ["cpp_capsule_tools_testing_test.py"], 22 | data = [":cpp_capsule_tools_testing.so"], 23 | deps = [requirement("absl_py")], 24 | ) 25 | 26 | pybind_library( 27 | name = "status_testing_no_cpp_eh_lib", 28 | hdrs = ["status_testing_no_cpp_eh_lib.h"], 29 | deps = [ 30 | "@com_google_absl//absl/log:absl_check", 31 | "@com_google_absl//absl/status", 32 | "@com_google_absl//absl/status:statusor", 33 | ], 34 | ) 35 | 36 | pybind_extension( 37 | name = "status_testing_no_cpp_eh_pybind", 38 | srcs = ["status_testing_no_cpp_eh_pybind.cc"], 39 | deps = [ 40 | ":status_testing_no_cpp_eh_lib", 41 | "//pybind11_abseil:import_status_module", 42 | "//pybind11_abseil:status_caster", 43 | "//pybind11_abseil:statusor_caster", 44 | ], 45 | ) 46 | 47 | py_library( 48 | name = "status_testing_no_cpp_eh_test_lib", 49 | srcs = ["status_testing_no_cpp_eh_test_lib.py"], 50 | data = ["//pybind11_abseil:status.so"], 51 | deps = [requirement("absl_py")], 52 | ) 53 | 54 | py_test( 55 | name = "status_testing_no_cpp_eh_test", 56 | srcs = ["status_testing_no_cpp_eh_test.py"], 57 | data = [":status_testing_no_cpp_eh_pybind.so"], 58 | deps = [":status_testing_no_cpp_eh_test_lib"], 59 | ) 60 | 61 | pybind_extension( 62 | name = "absl_example", 63 | srcs = ["absl_example.cc"], 64 | deps = [ 65 | "//pybind11_abseil:absl_casters", 66 | "@com_google_absl//absl/container:btree", 67 | "@com_google_absl//absl/container:flat_hash_set", 68 | "@com_google_absl//absl/strings", 69 | "@com_google_absl//absl/time", 70 | "@com_google_absl//absl/types:optional", 71 | "@com_google_absl//absl/types:span", 72 | ], 73 | ) 74 | 75 | py_test( 76 | name = "absl_test", 77 | srcs = ["absl_test.py"], 78 | data = [":absl_example.so"], 79 | deps = [ 80 | requirement("absl_py"), 81 | requirement("numpy"), 82 | ], 83 | ) 84 | 85 | py_test( 86 | name = "ok_status_singleton_test", 87 | srcs = ["ok_status_singleton_test.py"], 88 | data = ["//pybind11_abseil:ok_status_singleton.so"], 89 | deps = [requirement("absl_py")], 90 | ) 91 | 92 | pybind_extension( 93 | name = "missing_import", 94 | srcs = ["missing_import.cc"], 95 | copts = ["-UNDEBUG"], 96 | deps = [ 97 | "//pybind11_abseil:status_casters", 98 | "@com_google_absl//absl/status", 99 | "@com_google_absl//absl/status:statusor", 100 | ], 101 | ) 102 | 103 | py_test( 104 | name = "missing_import_test", 105 | srcs = ["missing_import_test.py"], 106 | data = [":missing_import.so"], 107 | ) 108 | 109 | py_test( 110 | name = "status_test", 111 | srcs = ["status_test.py"], 112 | data = ["//pybind11_abseil:status.so"], 113 | deps = [requirement("absl_py")], 114 | ) 115 | 116 | pybind_extension( 117 | name = "status_example", 118 | srcs = ["status_example.cc"], 119 | deps = [ 120 | "//pybind11_abseil:status_casters", 121 | "@com_google_absl//absl/memory", 122 | "@com_google_absl//absl/status", 123 | "@com_google_absl//absl/status:statusor", 124 | ], 125 | ) 126 | 127 | py_test( 128 | name = "status_example_test", 129 | srcs = ["status_example_test.py"], 130 | data = [ 131 | ":status_example.so", 132 | "//pybind11_abseil:status.so", 133 | ], 134 | deps = [requirement("absl_py")], 135 | ) 136 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # cpp_capsule_tools_testing ==================================================== 2 | 3 | pybind11_add_module(cpp_capsule_tools_testing MODULE 4 | cpp_capsule_tools_testing.cc) 5 | 6 | target_link_libraries( 7 | cpp_capsule_tools_testing PUBLIC make_shared_ptr_capsule raw_ptr_from_capsule 8 | shared_ptr_from_capsule absl::statusor) 9 | # cpp_capsule_tools_testing_test =============================================== 10 | 11 | if(NOT DEFINED Python_EXECUTABLE) 12 | if(NOT DEFINED PYBIND11_PYTHON_EXECUTABLE_LAST) 13 | set(Python_EXECUTABLE ${PYTHON_EXECUTABLE}) 14 | else() 15 | set(Python_EXECUTABLE ${PYBIND11_PYTHON_EXECUTABLE_LAST}) 16 | endif() 17 | endif() 18 | 19 | add_test( 20 | NAME cpp_capsule_tools_testing_test 21 | COMMAND 22 | ${CMAKE_COMMAND} -E env PYTHONPATH=$PYTHONPATH:${CMAKE_BINARY_DIR} 23 | ${Python_EXECUTABLE} 24 | ${CMAKE_CURRENT_SOURCE_DIR}/cpp_capsule_tools_testing_test.py 25 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 26 | 27 | # absl_example ================================================================= 28 | 29 | pybind11_add_module(absl_example MODULE absl_example.cc) 30 | 31 | target_link_libraries( 32 | absl_example 33 | PRIVATE absl_casters 34 | absl::btree 35 | absl::flat_hash_set 36 | absl::strings 37 | absl::time 38 | absl::optional 39 | absl::span) 40 | 41 | # absl_test ==================================================================== 42 | 43 | add_test( 44 | NAME absl_test 45 | COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=$PYTHONPATH:${CMAKE_BINARY_DIR} 46 | ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/absl_test.py 47 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 48 | 49 | # ok_status_singleton_test ===================================================== 50 | 51 | add_test( 52 | NAME ok_status_singleton_test 53 | COMMAND 54 | ${CMAKE_COMMAND} -E env PYTHONPATH=$PYTHONPATH:${CMAKE_BINARY_DIR} 55 | ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/ok_status_singleton_test.py 56 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 57 | 58 | # missing_import =============================================================== 59 | 60 | pybind11_add_module(missing_import MODULE missing_import.cc) 61 | 62 | target_compile_options(missing_import PUBLIC -UNDEBUG) 63 | 64 | target_link_libraries(missing_import PRIVATE status_casters absl::status 65 | absl::statusor) 66 | 67 | # missing_import_test ========================================================== 68 | 69 | add_test( 70 | NAME missing_import_test 71 | COMMAND 72 | ${CMAKE_COMMAND} -E env PYTHONPATH=$PYTHONPATH:${CMAKE_BINARY_DIR} 73 | ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/missing_import_test.py 74 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 75 | 76 | # status_test ================================================================== 77 | 78 | add_test( 79 | NAME status_test 80 | COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=$PYTHONPATH:${CMAKE_BINARY_DIR} 81 | ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/status_test.py 82 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 83 | 84 | # status_example =============================================================== 85 | 86 | pybind11_add_module(status_example MODULE status_example.cc) 87 | 88 | target_link_libraries(status_example PRIVATE status_casters absl::status 89 | absl::statusor) 90 | # status_example_test ========================================================== 91 | 92 | add_test( 93 | NAME status_example_test 94 | COMMAND 95 | ${CMAKE_COMMAND} -E env PYTHONPATH=$PYTHONPATH:${CMAKE_BINARY_DIR} 96 | ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/status_example_test.py 97 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 98 | 99 | # OMITTED (help appreciated): status_testing_no_cpp_eh_test 100 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/cpp_capsule_tools_testing.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 The Pybind Development Team. All rights reserved. 2 | // 3 | // All rights reserved. Use of this source code is governed by a 4 | // BSD-style license that can be found in the LICENSE file. 5 | 6 | #include 7 | #if true // go/pybind11_include_order 8 | #include 9 | #endif 10 | 11 | #include 12 | 13 | #include "absl/status/statusor.h" 14 | #include "pybind11_abseil/cpp_capsule_tools/make_shared_ptr_capsule.h" 15 | #include "pybind11_abseil/cpp_capsule_tools/raw_ptr_from_capsule.h" 16 | #include "pybind11_abseil/cpp_capsule_tools/shared_ptr_from_capsule.h" 17 | 18 | PYBIND11_MODULE(cpp_capsule_tools_testing, m) { 19 | namespace py = pybind11; 20 | namespace cpp_capsule_tools = pybind11_abseil::cpp_capsule_tools; 21 | 22 | m.def("make_bad_capsule", [](bool pass_name) { 23 | // https://docs.python.org/3/c-api/capsule.html: 24 | // The pointer argument may not be NULL. 25 | #if (defined(_WIN64) || defined(_WIN32)) 26 | // see C2466 cannot allocate an array of constant size 0 27 | int* dummy_pointee = nullptr; 28 | #else 29 | int dummy_pointee[] = {}; // This will become a dangling pointer when this 30 | // function returns: We don't want the pointer to be used. Hopefully if it 31 | // is used unintentionally, one of the sanitizers will flag it. 32 | #endif 33 | return py::capsule(static_cast(dummy_pointee), 34 | pass_name ? "NotGood" : nullptr); 35 | }); 36 | 37 | m.def("make_raw_ptr_capsule", []() { 38 | static int any_int = 890352; 39 | return py::capsule(&any_int, "type:int"); 40 | }); 41 | 42 | m.def("get_int_from_raw_ptr_capsule", 43 | [](py::handle py_obj, bool enable_method) { 44 | absl::StatusOr status_or_raw_ptr = 45 | cpp_capsule_tools::RawPtrFromCapsule( 46 | py_obj.ptr(), "type:int", 47 | (enable_method ? "get_capsule" : nullptr)); 48 | if (!status_or_raw_ptr.ok()) { 49 | return status_or_raw_ptr.status().ToString(); 50 | } 51 | return std::to_string(*status_or_raw_ptr.value()); 52 | }); 53 | 54 | m.def("make_shared_ptr_capsule", []() { 55 | return py::reinterpret_steal( 56 | cpp_capsule_tools::MakeSharedPtrCapsule(std::make_shared(906069), 57 | "type:shared_ptr")); 58 | }); 59 | 60 | m.def("get_int_from_shared_ptr_capsule", 61 | [](py::handle py_obj, bool enable_method) { 62 | using sp_t = std::shared_ptr; 63 | absl::StatusOr status_or_shared_ptr = 64 | cpp_capsule_tools::SharedPtrFromCapsule( 65 | py_obj.ptr(), "type:shared_ptr", 66 | (enable_method ? "get_capsule" : nullptr)); 67 | if (!status_or_shared_ptr.ok()) { 68 | return status_or_shared_ptr.status().ToString(); 69 | } 70 | return std::to_string(*status_or_shared_ptr.value()); 71 | }); 72 | } 73 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/cpp_capsule_tools_testing_test.py: -------------------------------------------------------------------------------- 1 | from absl.testing import absltest 2 | from absl.testing import parameterized 3 | 4 | from pybind11_abseil.tests import cpp_capsule_tools_testing as tstng 5 | 6 | 7 | class UsingMakeCapsule: 8 | 9 | def __init__(self, make_capsule): 10 | self.make_capsule = make_capsule 11 | 12 | def get_capsule(self): 13 | return self.make_capsule() 14 | 15 | 16 | class BadCapsule: 17 | 18 | def __init__(self, pass_name): 19 | self.pass_name = pass_name 20 | 21 | def get_capsule(self): 22 | return tstng.make_bad_capsule(self.pass_name) 23 | 24 | 25 | class NotACapsule: 26 | 27 | def __init__(self, not_a_capsule): 28 | self.not_a_capsule = not_a_capsule 29 | 30 | def get_capsule(self): 31 | return self.not_a_capsule 32 | 33 | 34 | class RaisingGetCapsule: 35 | 36 | def get_capsule(self): 37 | raise RuntimeError('from get_capsule') 38 | 39 | 40 | class CppCapsuleToolsTest(parameterized.TestCase): 41 | 42 | def test_raw_ptr_capsule_direct(self): 43 | cap = tstng.make_raw_ptr_capsule() 44 | res = tstng.get_int_from_raw_ptr_capsule(cap, False) 45 | self.assertEqual(res, '890352') 46 | 47 | def test_raw_ptr_capsule_method(self): 48 | using_cap = UsingMakeCapsule(tstng.make_raw_ptr_capsule) 49 | res = tstng.get_int_from_raw_ptr_capsule(using_cap, True) 50 | self.assertEqual(res, '890352') 51 | 52 | def test_shared_ptr_capsule_direct(self): 53 | cap = tstng.make_shared_ptr_capsule() 54 | res = tstng.get_int_from_shared_ptr_capsule(cap, False) 55 | self.assertEqual(res, '906069') 56 | 57 | def test_shared_ptr_capsule_method(self): 58 | using_cap = UsingMakeCapsule(tstng.make_shared_ptr_capsule) 59 | res = tstng.get_int_from_shared_ptr_capsule(using_cap, True) 60 | self.assertEqual(res, '906069') 61 | 62 | @parameterized.parameters((False, 'NULL'), (True, '"NotGood"')) 63 | def test_raw_ptr_capsule_direct_bad_capsule(self, pass_name, quoted_name): 64 | cap = tstng.make_bad_capsule(pass_name) 65 | res = tstng.get_int_from_raw_ptr_capsule(cap, False) 66 | self.assertEqual( 67 | res, 68 | f'INVALID_ARGUMENT: obj is a capsule with name {quoted_name} but' 69 | ' "type:int" is expected.', 70 | ) 71 | 72 | @parameterized.parameters((False, 'NULL'), (True, '"NotGood"')) 73 | def test_raw_ptr_capsule_method_bad_capsule(self, pass_name, quoted_name): 74 | cap = BadCapsule(pass_name) 75 | res = tstng.get_int_from_raw_ptr_capsule(cap, True) 76 | self.assertEqual( 77 | res, 78 | 'INVALID_ARGUMENT: BadCapsule.get_capsule() returned a capsule with' 79 | f' name {quoted_name} but "type:int" is expected.', 80 | ) 81 | 82 | @parameterized.parameters(None, '', 0) 83 | def test_raw_ptr_capsule_direct_not_a_capsule(self, not_a_capsule): 84 | res = tstng.get_int_from_raw_ptr_capsule(not_a_capsule, False) 85 | self.assertEqual( 86 | res, 87 | f'INVALID_ARGUMENT: {not_a_capsule.__class__.__name__} object is not a' 88 | ' capsule.', 89 | ) 90 | 91 | @parameterized.parameters(None, '', 0) 92 | def test_raw_ptr_capsule_method_not_a_capsule(self, not_a_capsule): 93 | cap = NotACapsule(not_a_capsule) 94 | res = tstng.get_int_from_raw_ptr_capsule(cap, True) 95 | self.assertEqual( 96 | res, 97 | 'INVALID_ARGUMENT: NotACapsule.get_capsule() returned an object' 98 | f' ({not_a_capsule.__class__.__name__}) that is not a capsule.', 99 | ) 100 | 101 | @parameterized.parameters( 102 | tstng.get_int_from_raw_ptr_capsule, tstng.get_int_from_shared_ptr_capsule 103 | ) 104 | def test_raising_get_capsule(self, get_int_from_capsule): 105 | cap = RaisingGetCapsule() 106 | res = get_int_from_capsule(cap, True) 107 | self.assertEqual( 108 | res, 109 | 'INVALID_ARGUMENT: RaisingGetCapsule.get_capsule() call failed:' 110 | ' RuntimeError: from get_capsule', 111 | ) 112 | 113 | 114 | if __name__ == '__main__': 115 | absltest.main() 116 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/missing_import.cc: -------------------------------------------------------------------------------- 1 | // A pybind11 module which uses the status caster but does not call 2 | // ImportStatusModule (as it should), to test the behavior in that case. 3 | #include 4 | 5 | #include "absl/status/status.h" 6 | #include "absl/status/statusor.h" 7 | #include "pybind11_abseil/status_casters.h" 8 | 9 | namespace pybind11 { 10 | namespace test { 11 | 12 | absl::Status ReturnStatus() { return absl::InternalError("test"); } 13 | absl::StatusOr ReturnStatusOr() { return absl::InternalError("test"); } 14 | 15 | PYBIND11_MODULE(missing_import, m) { 16 | m.def("returns_status", &ReturnStatus); 17 | m.def("returns_status_or", &ReturnStatusOr); 18 | } 19 | 20 | } // namespace test 21 | } // namespace pybind11 22 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/missing_import_test.py: -------------------------------------------------------------------------------- 1 | """Tests that the casters raise a TypeError if the status module is missing.""" 2 | 3 | # In google3, `from absl.testing import absltest` imports the status module, 4 | # which breaks the requirement for this test that the status module is missing. 5 | import unittest 6 | 7 | from pybind11_abseil.tests import missing_import 8 | 9 | 10 | class MissingStatusImportTest(unittest.TestCase): 11 | 12 | message_regex = 'Status module has not been imported.*' 13 | 14 | def test_returns_status(self): 15 | with self.assertRaisesRegex(TypeError, self.message_regex): 16 | missing_import.returns_status() 17 | 18 | def test_returns_status_or(self): 19 | with self.assertRaisesRegex(TypeError, self.message_regex): 20 | missing_import.returns_status_or() 21 | 22 | 23 | if __name__ == '__main__': 24 | unittest.main() 25 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/ok_status_singleton_test.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2022 The Pybind Development Team. All rights reserved. 2 | # 3 | # All rights reserved. Use of this source code is governed by a 4 | # BSD-style license that can be found in the LICENSE file. 5 | 6 | import sys 7 | 8 | from absl.testing import absltest 9 | 10 | from pybind11_abseil import ok_status_singleton 11 | 12 | 13 | class OkStatusSingletonTest(absltest.TestCase): 14 | 15 | def test_singleton(self): 16 | cap = ok_status_singleton.OkStatusSingleton() 17 | if 'pybind11_abseil.status' in sys.modules: # OSS 18 | expected_repr_cap = ' 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "absl/memory/memory.h" 8 | #include "absl/status/status.h" 9 | #include "absl/status/statusor.h" 10 | #include "pybind11_abseil/status_casters.h" 11 | 12 | namespace pybind11 { 13 | namespace test { 14 | 15 | struct IntValue { 16 | IntValue() = default; 17 | IntValue(int value_in) : value(value_in) {} 18 | int value; 19 | }; 20 | 21 | class TestClass { 22 | public: 23 | absl::Status MakeStatus(absl::StatusCode code, const std::string& text = "") { 24 | return absl::Status(code, text); 25 | } 26 | 27 | absl::Status MakeStatusConst(absl::StatusCode code, 28 | const std::string& text = "") const { 29 | return absl::Status(code, text); 30 | } 31 | 32 | absl::StatusOr MakeFailureStatusOr(absl::StatusCode code, 33 | const std::string& text = "") { 34 | return absl::Status(code, text); 35 | } 36 | }; 37 | 38 | bool CheckStatus(const absl::Status& status, absl::StatusCode code) { 39 | return status.code() == code; 40 | } 41 | 42 | bool CheckStatusOr(const absl::StatusOr& statusor, absl::StatusCode code) { 43 | if (statusor.ok()) { 44 | return true; 45 | } 46 | return statusor.status().code() == code; 47 | } 48 | 49 | absl::Status ReturnStatus(absl::StatusCode code, const std::string& text = "") { 50 | return absl::Status(code, text); 51 | } 52 | 53 | pybind11::object ReturnStatusManualCast(absl::StatusCode code, 54 | const std::string& text = "") { 55 | return pybind11::cast(google::DoNotThrowStatus(absl::Status(code, text))); 56 | } 57 | 58 | const absl::Status& ReturnStatusRef(absl::StatusCode code, 59 | const std::string& text = "") { 60 | static absl::Status static_status; 61 | static_status = absl::Status(code, text); 62 | return static_status; 63 | } 64 | 65 | const absl::Status* ReturnStatusPtr(absl::StatusCode code, 66 | const std::string& text = "") { 67 | static absl::Status static_status; 68 | static_status = absl::Status(code, text); 69 | return &static_status; 70 | } 71 | 72 | absl::StatusOr ReturnFailureStatusOr(absl::StatusCode code, 73 | const std::string& text = "") { 74 | return absl::Status(code, text); 75 | } 76 | 77 | pybind11::object ReturnFailureStatusOrManualCast(absl::StatusCode code, 78 | const std::string& text = "") { 79 | return pybind11::cast(google::DoNotThrowStatus(absl::Status(code, text))); 80 | } 81 | 82 | absl::StatusOr ReturnValueStatusOr(int value) { return value; } 83 | 84 | absl::StatusOr ReturnPtrStatusOr(int value) { 85 | static IntValue static_object; 86 | static_object.value = value; 87 | return &static_object; 88 | } 89 | 90 | absl::StatusOr> ReturnUniquePtrStatusOr(int value) { 91 | return absl::make_unique(value); 92 | } 93 | 94 | class IntGetter { 95 | public: 96 | virtual ~IntGetter() {} 97 | virtual absl::StatusOr Get(int i) const = 0; 98 | }; 99 | 100 | class PyIntGetter : public IntGetter { 101 | public: 102 | using IntGetter::IntGetter; 103 | absl::StatusOr Get(int i) const override { 104 | PYBIND11_OVERRIDE_PURE(absl::StatusOr, IntGetter, Get, i); 105 | } 106 | }; 107 | 108 | absl::StatusOr CallGetRedirectToPython(IntGetter* ptr, int i) { 109 | if (ptr) { 110 | return ptr->Get(i); 111 | } 112 | return absl::InvalidArgumentError( 113 | "Function parameter should not be nullptr."); 114 | } 115 | 116 | PYBIND11_MODULE(status_example, m) { 117 | m.attr("PYBIND11_HAS_RETURN_VALUE_POLICY_CLIF_AUTOMATIC") = 118 | #if defined(PYBIND11_HAS_RETURN_VALUE_POLICY_CLIF_AUTOMATIC) 119 | true; 120 | #else 121 | false; 122 | #endif 123 | 124 | auto status_module = pybind11::google::ImportStatusModule(); 125 | m.attr("StatusNotOk") = status_module.attr("StatusNotOk"); 126 | 127 | m.def("make_absl_status_capsule", [](bool return_ok_status) { 128 | static absl::Status ok_status; 129 | static absl::Status not_ok_status(absl::StatusCode::kAlreadyExists, 130 | "Made by make_absl_status_capsule."); 131 | if (return_ok_status) { 132 | return capsule(static_cast(&ok_status), "::absl::Status"); 133 | } 134 | return capsule(static_cast(¬_ok_status), "::absl::Status"); 135 | }); 136 | 137 | m.def("extract_code_message", [](const absl::Status& status) { 138 | return pybind11::make_tuple(status.code(), std::string(status.message())); 139 | }); 140 | 141 | m.def("make_bad_capsule", [](bool pass_name) { 142 | // https://docs.python.org/3/c-api/capsule.html: 143 | // The pointer argument may not be NULL. 144 | #if (defined(_WIN64) || defined(_WIN32)) 145 | // see C2466 cannot allocate an array of constant size 0 146 | int* dummy_pointee = nullptr; 147 | #else 148 | int dummy_pointee[] = {}; // This will become a dangling pointer when this 149 | // function returns: We don't want the pointer to be used. Hopefully if it 150 | // is used unintentionally, one of the sanitizers will flag it. 151 | #endif 152 | return capsule(static_cast(dummy_pointee), 153 | pass_name ? "NotGood" : nullptr); 154 | }); 155 | 156 | class_(m, "IntValue").def_readonly("value", &IntValue::value); 157 | 158 | class_(m, "TestClass") 159 | .def(init()) 160 | .def("make_status", google::DoNotThrowStatus(&TestClass::MakeStatus), 161 | arg("code"), arg("text") = "") 162 | .def("make_status_const", 163 | google::DoNotThrowStatus(&TestClass::MakeStatusConst), arg("code"), 164 | arg("text") = "") 165 | .def("make_failure_status_or", 166 | google::DoNotThrowStatus(&TestClass::MakeFailureStatusOr), 167 | arg("code"), arg("text") = ""); 168 | 169 | // absl::Status bindings 170 | m.def("check_status", &CheckStatus, arg("status"), arg("code")); 171 | m.def("check_statusor", &CheckStatusOr, arg("statusor"), arg("code")); 172 | m.def("return_status", &ReturnStatus, "Raise an error if code is not OK.", 173 | arg("code"), arg("text") = ""); 174 | m.def("make_status", google::DoNotThrowStatus(&ReturnStatus), 175 | "Return a status without raising an error, regardless of what it is.", 176 | arg("code"), arg("text") = ""); 177 | m.def("make_status_manual_cast", ReturnStatusManualCast, 178 | "Return a status without raising an error, regardless of what it is.", 179 | arg("code"), arg("text") = ""); 180 | m.def("make_status_ref", google::DoNotThrowStatus(&ReturnStatusRef), 181 | "Return a reference to a static status value without raising an error.", 182 | arg("code"), arg("text") = "", return_value_policy::reference); 183 | m.def("make_status_ptr", google::DoNotThrowStatus(&ReturnStatusPtr), 184 | "Return a reference to a static status value without raising an error.", 185 | arg("code"), arg("text") = "", return_value_policy::reference); 186 | 187 | // absl::StatusOr bindings 188 | m.def("return_value_status_or", &ReturnValueStatusOr, arg("value")); 189 | m.def("return_failure_status_or", &ReturnFailureStatusOr, 190 | "Raise an error with the given code.", arg("code"), arg("text") = ""); 191 | m.def("make_failure_status_or", 192 | google::DoNotThrowStatus(&ReturnFailureStatusOr), arg("code"), 193 | arg("text") = "", "Return a status without raising an error."); 194 | m.def("make_failure_status_or_manual_cast", &ReturnFailureStatusOrManualCast, 195 | arg("code"), arg("text") = "", "Return a status."); 196 | m.def("return_ptr_status_or", &ReturnPtrStatusOr, arg("value"), 197 | "Return a reference in a status or to a static value.", 198 | return_value_policy::reference); 199 | m.def("return_unique_ptr_status_or", &ReturnUniquePtrStatusOr, arg("value")); 200 | m.def("return_status_or_pointer", []() { 201 | static absl::StatusOr* ptr = new absl::StatusOr(42); 202 | return ptr; 203 | }); 204 | m.def("return_failure_status_or_pointer", []() { 205 | static absl::StatusOr* ptr = 206 | new absl::StatusOr(absl::InvalidArgumentError("Uh oh!")); 207 | return ptr; 208 | }); 209 | 210 | class_(m, "IntGetter") 211 | .def(init()) 212 | .def("Get", &IntGetter::Get); 213 | m.def("call_get_redirect_to_python", &CallGetRedirectToPython, arg("ptr"), 214 | arg("i")); 215 | 216 | // Needed to exercise raw_code() != code(). 217 | m.def("status_from_int_code", [](int code, const std::string& msg) { 218 | return google::DoNotThrowStatus( 219 | absl::Status(static_cast(code), msg)); 220 | }); 221 | 222 | m.def("return_ok_status", [](bool use_return_value_policy_clif_automatic) { 223 | if (use_return_value_policy_clif_automatic) { 224 | #if defined(PYBIND11_HAS_RETURN_VALUE_POLICY_CLIF_AUTOMATIC) 225 | return cast(absl::OkStatus(), return_value_policy::_clif_automatic); 226 | #endif 227 | } 228 | return cast(absl::OkStatus()); 229 | }); 230 | 231 | #if defined(PYBIND11_HAS_RETURN_VALUE_POLICY_CLIF_AUTOMATIC) 232 | m.def( 233 | "return_ok_status_direct", []() { return absl::OkStatus(); }, 234 | return_value_policy::_clif_automatic); 235 | #endif 236 | } 237 | 238 | } // namespace test 239 | } // namespace pybind11 240 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/status_example_test.py: -------------------------------------------------------------------------------- 1 | from absl.testing import absltest 2 | from absl.testing import parameterized 3 | from pybind11_abseil import status 4 | from pybind11_abseil.tests import status_example 5 | 6 | 7 | def docstring_signature(f): 8 | """Returns the first line from a docstring - the signature for a function.""" 9 | return f.__doc__.split('\n')[0] 10 | 11 | 12 | class AbslStatusCapsule: 13 | 14 | def __init__(self, return_ok_status): 15 | self.return_ok_status = return_ok_status 16 | 17 | def as_absl_Status(self): # pylint: disable=invalid-name 18 | return status_example.make_absl_status_capsule(self.return_ok_status) 19 | 20 | 21 | class BadCapsule: 22 | 23 | def __init__(self, pass_name): 24 | self.pass_name = pass_name 25 | 26 | def as_absl_Status(self): # pylint: disable=invalid-name 27 | return status_example.make_bad_capsule(self.pass_name) 28 | 29 | 30 | class NotACapsule: 31 | 32 | def __init__(self, not_a_capsule): 33 | self.not_a_capsule = not_a_capsule 34 | 35 | def as_absl_Status(self): # pylint: disable=invalid-name 36 | return self.not_a_capsule 37 | 38 | 39 | class StatusTest(parameterized.TestCase): 40 | 41 | def test_pass_status(self): 42 | test_status = status.Status(status.StatusCode.CANCELLED, 'test') 43 | self.assertTrue( 44 | status_example.check_status(test_status, status.StatusCode.CANCELLED)) 45 | 46 | def test_pass_statusor(self): 47 | test_status = status.Status(status.StatusCode.CANCELLED, 'test') 48 | self.assertTrue( 49 | status_example.check_statusor(test_status, status.StatusCode.CANCELLED)) 50 | test_status = status.Status(status.StatusCode.OK, 'test') 51 | with self.assertRaises(RuntimeError) as ctx: 52 | status_example.check_statusor(test_status, status.StatusCode.CANCELLED) 53 | self.assertEqual( 54 | str(ctx.exception), 55 | 'An OK status is not a valid constructor argument to StatusOr.') 56 | with self.assertRaises(RuntimeError) as ctx: 57 | status_example.check_statusor(None, status.StatusCode.CANCELLED) 58 | self.assertEqual( 59 | str(ctx.exception), 60 | 'None is not a valid value for a StatusOr argument.') 61 | 62 | def test_return_status_return_type_from_doc(self): 63 | self.assertEndsWith( 64 | docstring_signature(status_example.return_status), ' -> None') 65 | 66 | def test_return_ok(self): 67 | # The return_status function should convert an ok status to None. 68 | self.assertIsNone(status_example.return_status(status.StatusCode.OK)) 69 | 70 | def test_return_not_ok(self): 71 | # The return_status function should convert a non-ok status to an exception. 72 | with self.assertRaises(status.StatusNotOk) as cm: 73 | status_example.return_status(status.StatusCode.CANCELLED, 'test') 74 | self.assertEqual(cm.exception.status.code(), status.StatusCode.CANCELLED) 75 | self.assertEqual(cm.exception.status.message(), 'test') 76 | self.assertEqual(cm.exception.code, int(status.StatusCode.CANCELLED)) 77 | self.assertEqual(cm.exception.message, 'test') 78 | 79 | def test_return_not_ok_twice(self): 80 | # Each exception is a different instance with different messages. 81 | with self.assertRaises(status.StatusNotOk) as cm1: 82 | status_example.return_status(status.StatusCode.CANCELLED, 'test1') 83 | with self.assertRaises(status.StatusNotOk) as cm2: 84 | status_example.return_status(status.StatusCode.CANCELLED, 'test2') 85 | self.assertEqual(cm1.exception.status.message(), 'test1') 86 | self.assertEqual(cm2.exception.status.message(), 'test2') 87 | 88 | def test_return_not_ok_catch_with_alias(self): 89 | # Catch as status_example.StatusNotOk, an alias of status.StatusNotOk. 90 | with self.assertRaises(status_example.StatusNotOk) as cm: 91 | status_example.return_status(status.StatusCode.CANCELLED, 'test') 92 | self.assertEqual(cm.exception.status.code(), status.StatusCode.CANCELLED) 93 | self.assertEqual(cm.exception.status.message(), 'test') 94 | 95 | def test_return_not_ok_catch_as_generic_exception(self): 96 | # Catch as a generic Exception, the base type of StatusNotOk. 97 | with self.assertRaises(Exception): 98 | status_example.return_status(status.StatusCode.CANCELLED, 'test') 99 | 100 | def test_make_status_return_type_from_doc(self): 101 | self.assertRegex( 102 | docstring_signature(status_example.make_status), r' -> .*\.Status') 103 | 104 | def test_make_ok(self): 105 | # The make_status function has been set up to return a status object 106 | # instead of raising an exception (this is done in status_example.cc). 107 | test_status = status_example.make_status(status.StatusCode.OK) 108 | self.assertTrue(test_status.ok()) 109 | self.assertEqual(test_status.code(), status.StatusCode.OK) 110 | self.assertEqual(test_status.code_int(), 0) 111 | 112 | def test_make_not_ok(self): 113 | # The make_status function should always return a status object, even if 114 | # it is not ok (ie, it should *not* convert it to an exception). 115 | test_status = status_example.make_status(status.StatusCode.CANCELLED) 116 | self.assertFalse(test_status.ok()) 117 | self.assertEqual(test_status.code(), status.StatusCode.CANCELLED) 118 | self.assertEqual(test_status.code_int(), 1) 119 | 120 | def test_make_not_ok_manual_cast(self): 121 | test_status = status_example.make_status_manual_cast( 122 | status.StatusCode.CANCELLED) 123 | self.assertEqual(test_status.code(), status.StatusCode.CANCELLED) 124 | 125 | def test_make_status_ref(self): 126 | result_1 = status_example.make_status_ref(status.StatusCode.OK) 127 | self.assertEqual(result_1.code(), status.StatusCode.OK) 128 | result_2 = status_example.make_status_ref(status.StatusCode.CANCELLED) 129 | self.assertEqual(result_2.code(), status.StatusCode.CANCELLED) 130 | # result_1 and 2 reference the same value, so they should always be equal. 131 | self.assertEqual(result_1.code(), result_2.code()) 132 | 133 | def test_make_status_ptr(self): 134 | result_1 = status_example.make_status_ptr(status.StatusCode.OK) 135 | self.assertEqual(result_1.code(), status.StatusCode.OK) 136 | result_2 = status_example.make_status_ptr(status.StatusCode.CANCELLED) 137 | self.assertEqual(result_2.code(), status.StatusCode.CANCELLED) 138 | # result_1 and 2 reference the same value, so they should always be equal. 139 | self.assertEqual(result_1.code(), result_2.code()) 140 | 141 | def test_member_method(self): 142 | test_status = status_example.TestClass().make_status(status.StatusCode.OK) 143 | self.assertEqual(test_status.code(), status.StatusCode.OK) 144 | test_status = status_example.TestClass().make_status_const( 145 | status.StatusCode.OK) 146 | self.assertEqual(test_status.code(), status.StatusCode.OK) 147 | 148 | def test_is_ok(self): 149 | ok_status = status_example.make_status(status.StatusCode.OK) 150 | self.assertTrue(status.is_ok(ok_status)) 151 | failure_status = status_example.make_status(status.StatusCode.CANCELLED) 152 | self.assertFalse(status.is_ok(failure_status)) 153 | 154 | def test_repr(self): 155 | any_status = status_example.make_status(status.StatusCode.DATA_LOSS) 156 | self.assertRegex(repr(any_status), r'<.*\.status.Status object at .*>') 157 | 158 | def test_ok_to_string(self): 159 | ok_status = status_example.make_status(status.StatusCode.OK) 160 | self.assertEqual(ok_status.to_string(), 'OK') 161 | self.assertEqual(str(ok_status), 'OK') 162 | 163 | def test_raw_code_ne_code(self): 164 | st500 = status_example.status_from_int_code(500, 'Not a canonical code.') 165 | self.assertEqual(st500.raw_code(), 500) 166 | self.assertEqual(st500.code(), status.StatusCode.UNKNOWN) 167 | 168 | @parameterized.parameters((False, 'NULL'), (True, '"NotGood"')) 169 | def test_init_from_capsule_direct_bad_capsule(self, pass_name, quoted_name): 170 | with self.assertRaises(ValueError) as ctx: 171 | status.Status(status.InitFromTag.capsule, 172 | status_example.make_bad_capsule(pass_name)) 173 | self.assertEqual( 174 | str(ctx.exception), 175 | f'obj is a capsule with name {quoted_name} but "::absl::Status"' 176 | f' is expected.') 177 | 178 | @parameterized.parameters((False, 'NULL'), (True, '"NotGood"')) 179 | def test_init_from_capsule_correct_method_bad_capsule(self, pass_name, 180 | quoted_name): 181 | with self.assertRaises(ValueError) as ctx: 182 | status.Status(status.InitFromTag.capsule, BadCapsule(pass_name)) 183 | self.assertEqual( 184 | str(ctx.exception), 185 | f'BadCapsule.as_absl_Status() returned a capsule with name' 186 | f' {quoted_name} but "::absl::Status" is expected.') 187 | 188 | @parameterized.parameters(False, True) 189 | def test_status_caster_load_as_absl_status_success(self, return_ok_status): 190 | code, msg = status_example.extract_code_message( 191 | AbslStatusCapsule(return_ok_status)) 192 | if return_ok_status: 193 | self.assertEqual(code, status.StatusCode.OK) 194 | self.assertEqual(msg, '') 195 | else: 196 | self.assertEqual(code, status.StatusCode.ALREADY_EXISTS) 197 | self.assertEqual(msg, 'Made by make_absl_status_capsule.') 198 | 199 | @parameterized.parameters(False, True) 200 | def test_status_caster_load_as_absl_status_bad_capsule(self, pass_name): 201 | cap = BadCapsule(pass_name) 202 | with self.assertRaises(TypeError): 203 | status_example.extract_code_message(cap) 204 | 205 | @parameterized.parameters(None, '', 0) 206 | def test_status_caster_load_as_absl_status_not_a_capsule(self, not_a_capsule): 207 | cap = NotACapsule(not_a_capsule) 208 | with self.assertRaises(TypeError): 209 | status_example.extract_code_message(cap) 210 | 211 | @parameterized.parameters('', 0) 212 | def test_status_caster_load_no_as_absl_status(self, something_random): 213 | with self.assertRaises(TypeError): 214 | status_example.extract_code_message(something_random) 215 | 216 | def test_status_caster_load_none(self): 217 | code, msg = status_example.extract_code_message(None) 218 | self.assertEqual(code, status.StatusCode.OK) 219 | self.assertEqual(msg, '') 220 | 221 | def test_return_ok_status_return_value_policy_clif_automatic(self): 222 | self.assertIsNone(status_example.return_ok_status(False)) 223 | if not status_example.PYBIND11_HAS_RETURN_VALUE_POLICY_CLIF_AUTOMATIC: 224 | self.skipTest('return_value_policy::_clif_automatic not available') 225 | obj = status_example.return_ok_status(True) 226 | self.assertIs(obj, status.Status.OkStatus()) 227 | 228 | def test_return_ok_status_direct_return_value_policy_clif_automatic(self): 229 | if not status_example.PYBIND11_HAS_RETURN_VALUE_POLICY_CLIF_AUTOMATIC: 230 | self.skipTest('return_value_policy::_clif_automatic not available') 231 | obj = status_example.return_ok_status_direct() 232 | self.assertIs(obj, status.Status.OkStatus()) 233 | 234 | 235 | class IntGetter(status_example.IntGetter): 236 | 237 | def Get(self, i): 238 | if i > 10: 239 | raise ValueError('Value out of range') 240 | return i 241 | 242 | 243 | class StatusOrTest(absltest.TestCase): 244 | 245 | def test_return_value_status_or_return_type_from_doc(self): 246 | self.assertEndsWith( 247 | docstring_signature(status_example.return_value_status_or), 248 | ' -> int') 249 | 250 | def test_return_value(self): 251 | self.assertEqual(status_example.return_value_status_or(5), 5) 252 | 253 | def test_return_not_ok(self): 254 | with self.assertRaises(status.StatusNotOk) as cm: 255 | status_example.return_failure_status_or(status.StatusCode.NOT_FOUND) 256 | self.assertEqual(cm.exception.status.code(), status.StatusCode.NOT_FOUND) 257 | 258 | def test_make_failure_status_or_return_type_from_doc(self): 259 | self.assertRegex( 260 | docstring_signature(status_example.make_failure_status_or), 261 | r' -> Union\[.*\.Status, int\]') 262 | 263 | def test_make_not_ok(self): 264 | self.assertEqual( 265 | status_example.make_failure_status_or( 266 | status.StatusCode.CANCELLED).code(), status.StatusCode.CANCELLED) 267 | 268 | def test_make_not_ok_manual_cast(self): 269 | self.assertEqual( 270 | status_example.make_failure_status_or_manual_cast( 271 | status.StatusCode.CANCELLED).code(), status.StatusCode.CANCELLED) 272 | 273 | def test_return_ptr_status_or(self): 274 | result_1 = status_example.return_ptr_status_or(5) 275 | self.assertEqual(result_1.value, 5) 276 | result_2 = status_example.return_ptr_status_or(6) 277 | self.assertEqual(result_2.value, 6) 278 | # result_1 and 2 reference the same value, so they should always be equal. 279 | self.assertEqual(result_1.value, result_2.value) 280 | 281 | def test_return_unique_ptr(self): 282 | result = status_example.return_unique_ptr_status_or(5) 283 | self.assertEqual(result.value, 5) 284 | 285 | def test_member_method(self): 286 | test_status = status_example.TestClass().make_failure_status_or( 287 | status.StatusCode.ABORTED) 288 | self.assertEqual(test_status.code(), status.StatusCode.ABORTED) 289 | 290 | def test_is_ok(self): 291 | ok_result = status_example.return_value_status_or(5) 292 | self.assertEqual(ok_result, 5) 293 | self.assertTrue(status.is_ok(ok_result)) 294 | failure_result = status_example.make_failure_status_or( 295 | status.StatusCode.CANCELLED) 296 | self.assertFalse(status.is_ok(failure_result)) 297 | 298 | def test_return_status_or_pointer(self): 299 | expected_result = 42 300 | for _ in range(3): 301 | result = status_example.return_status_or_pointer() 302 | self.assertEqual(result, expected_result) 303 | 304 | def test_return_failed_status_or_pointer(self): 305 | for _ in range(3): 306 | with self.assertRaises(status.StatusNotOk): 307 | status_example.return_failure_status_or_pointer() 308 | 309 | def test_canonical_error_to_string(self): 310 | failure_result = status_example.make_failure_status_or( 311 | status.StatusCode.CANCELLED) 312 | self.assertEqual(failure_result.to_string(), 'CANCELLED: ') 313 | self.assertEqual(str(failure_result), 'CANCELLED: ') 314 | 315 | def test_overriding_in_python(self): 316 | int_getter = IntGetter() 317 | self.assertEqual(int_getter.Get(5), 5) 318 | with self.assertRaises(ValueError): 319 | int_getter.Get(100) 320 | self.assertEqual( 321 | status_example.call_get_redirect_to_python(int_getter, 5), 5 322 | ) 323 | with self.assertRaises(ValueError): 324 | status_example.call_get_redirect_to_python(int_getter, 100) 325 | 326 | 327 | if __name__ == '__main__': 328 | absltest.main() 329 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/status_test.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | 3 | from absl.testing import absltest 4 | from absl.testing import parameterized 5 | from pybind11_abseil import status 6 | 7 | 8 | class NotACapsule: 9 | 10 | def __init__(self, not_a_capsule): 11 | self.not_a_capsule = not_a_capsule 12 | 13 | def as_absl_Status(self): # pylint: disable=invalid-name 14 | return self.not_a_capsule 15 | 16 | 17 | class StatusCodeTest(absltest.TestCase): 18 | 19 | def test_status_code_from_int_valid(self): 20 | self.assertEqual(status.StatusCodeFromInt(13), status.StatusCode.INTERNAL) 21 | 22 | def test_status_code_from_int_invalid(self): 23 | with self.assertRaises(ValueError) as ctx: 24 | status.StatusCodeFromInt(9876) 25 | self.assertEqual( 26 | str(ctx.exception), 'code_int=9876 is not a valid absl::StatusCode') 27 | 28 | def test_status_code_as_int(self): 29 | self.assertEqual(status.StatusCodeAsInt(status.StatusCode.UNAVAILABLE), 14) 30 | 31 | def test_repr(self): 32 | self.assertEqual( 33 | repr(status.StatusCode.NOT_FOUND), '') 34 | 35 | 36 | class StatusTest(parameterized.TestCase): 37 | 38 | def test_status_not_ok_status(self): 39 | e = status.StatusNotOk(status.Status(status.StatusCode.CANCELLED, 'Cnclld')) 40 | self.assertEqual(e.code, int(status.StatusCode.CANCELLED)) 41 | self.assertEqual(e.message, 'Cnclld') 42 | 43 | def test_status_nok_ok_str(self): 44 | with self.assertRaises(AttributeError) as cm: 45 | status.StatusNotOk('') # pytype: disable=wrong-arg-types 46 | self.assertEqual(str(cm.exception), "'str' object has no attribute 'ok'") 47 | 48 | def test_status_nok_ok_none(self): 49 | with self.assertRaises(AssertionError) as cm: 50 | status.StatusNotOk(None) # pytype: disable=wrong-arg-types 51 | self.assertEqual(str(cm.exception), '') 52 | 53 | def test_canonical_error(self): 54 | test_status = status.aborted_error('test') 55 | self.assertEqual(test_status.code(), status.StatusCode.ABORTED) 56 | self.assertEqual(test_status.message(), 'test') 57 | 58 | def test_canonical_error_to_string(self): 59 | test_status = status.aborted_error('test') 60 | self.assertEqual(test_status.to_string(), 'ABORTED: test') 61 | self.assertEqual(str(test_status), 'ABORTED: test') 62 | 63 | def test_create_ok_status(self): 64 | ok_status = status.Status.OkStatus() 65 | self.assertEqual(ok_status.to_string(), 'OK') 66 | self.assertEqual(ok_status.raw_code(), 0) 67 | self.assertIsNone(ok_status.IgnoreError()) 68 | 69 | def test_error_message_malformed_utf8(self): 70 | malformed_utf8 = b'\x80' 71 | stx80 = status.invalid_argument_error(malformed_utf8) 72 | self.assertEqual(stx80.message(), '�') 73 | self.assertEqual(stx80.message_bytes(), malformed_utf8) 74 | self.assertEqual(stx80.to_string(), 'INVALID_ARGUMENT: �') 75 | self.assertEqual(str(stx80), 'INVALID_ARGUMENT: �') 76 | e = status.StatusNotOk(stx80) 77 | self.assertEqual(str(e), '� [INVALID_ARGUMENT]') 78 | 79 | def test_payload_management_apis(self): 80 | st = status.Status(status.StatusCode.CANCELLED, '') 81 | self.assertEqual(st.AllPayloads(), ()) 82 | st.SetPayload('Url1', 'Payload1') 83 | self.assertEqual(st.AllPayloads(), ((b'Url1', b'Payload1'),)) 84 | st.SetPayload('Url0', 'Payload0') 85 | self.assertEqual(st.AllPayloads(), 86 | ((b'Url0', b'Payload0'), (b'Url1', b'Payload1'))) 87 | st.SetPayload('Url2', 'Payload2') 88 | self.assertEqual(st.AllPayloads(), 89 | ((b'Url0', b'Payload0'), (b'Url1', b'Payload1'), 90 | (b'Url2', b'Payload2'))) 91 | st.SetPayload('Url2', 'Payload2B') 92 | self.assertEqual(st.AllPayloads(), 93 | ((b'Url0', b'Payload0'), (b'Url1', b'Payload1'), 94 | (b'Url2', b'Payload2B'))) 95 | self.assertTrue(st.ErasePayload('Url1')) 96 | self.assertEqual(st.AllPayloads(), 97 | ((b'Url0', b'Payload0'), (b'Url2', b'Payload2B'))) 98 | self.assertFalse(st.ErasePayload('Url1')) 99 | self.assertEqual(st.AllPayloads(), 100 | ((b'Url0', b'Payload0'), (b'Url2', b'Payload2B'))) 101 | self.assertFalse(st.ErasePayload('UrlNeverExisted')) 102 | self.assertEqual(st.AllPayloads(), 103 | ((b'Url0', b'Payload0'), (b'Url2', b'Payload2B'))) 104 | self.assertTrue(st.ErasePayload('Url0')) 105 | self.assertEqual(st.AllPayloads(), ((b'Url2', b'Payload2B'),)) 106 | self.assertTrue(st.ErasePayload('Url2')) 107 | self.assertEqual(st.AllPayloads(), ()) 108 | self.assertFalse(st.ErasePayload('UrlNeverExisted')) 109 | self.assertEqual(st.AllPayloads(), ()) 110 | 111 | def test_eq_and_hash(self): 112 | s0 = status.Status(status.StatusCode.CANCELLED, 'A') 113 | sb = status.Status(status.StatusCode.CANCELLED, 'A') 114 | sp = status.Status(status.StatusCode.CANCELLED, 'A') 115 | sp.SetPayload('Url1p', 'Payload1p') 116 | sc = status.Status(status.StatusCode.UNKNOWN, 'A') 117 | sm = status.Status(status.StatusCode.CANCELLED, 'B') 118 | sx = status.Status(status.StatusCode.UNKNOWN, 'B') 119 | 120 | self.assertTrue(bool(s0 == s0)) # pylint: disable=comparison-with-itself 121 | self.assertTrue(bool(s0 == sb)) 122 | self.assertFalse(bool(s0 == sp)) 123 | self.assertFalse(bool(s0 == sc)) 124 | self.assertFalse(bool(s0 == sm)) 125 | self.assertFalse(bool(s0 == sx)) 126 | self.assertFalse(bool(s0 == 'AnyOtherType')) 127 | 128 | self.assertEqual(hash(sb), hash(s0)) 129 | self.assertEqual(hash(sp), hash(s0)) # Payload ignored intentionally. 130 | self.assertNotEqual(hash(sc), hash(s0)) 131 | self.assertNotEqual(hash(sm), hash(s0)) 132 | self.assertNotEqual(hash(sx), hash(s0)) 133 | 134 | st_set = {s0} 135 | self.assertLen(st_set, 1) 136 | st_set.add(sb) 137 | self.assertLen(st_set, 1) 138 | st_set.add(sp) 139 | self.assertLen(st_set, 2) 140 | st_set.add(sc) 141 | self.assertLen(st_set, 3) 142 | st_set.add(sm) 143 | self.assertLen(st_set, 4) 144 | st_set.add(sx) 145 | self.assertLen(st_set, 5) 146 | 147 | @parameterized.parameters(0, 1, 2) 148 | def test_pickle(self, payload_size): 149 | orig = status.Status(status.StatusCode.CANCELLED, 'Cucumber.') 150 | expected_all_payloads = [] 151 | for i in range(payload_size): 152 | type_url = f'Url{i}' 153 | payload = f'Payload{i}' 154 | orig.SetPayload(type_url, payload) 155 | expected_all_payloads.append((type_url.encode(), payload.encode())) 156 | expected_all_payloads = tuple(expected_all_payloads) 157 | 158 | # Redundant with other tests, but here to reassure that the preconditions 159 | # for the tests below to be meaningful are met. 160 | self.assertEqual(orig.code(), status.StatusCode.CANCELLED) 161 | self.assertEqual(orig.message_bytes(), b'Cucumber.') 162 | self.assertEqual(orig.AllPayloads(), expected_all_payloads) 163 | 164 | # Exercises implementation details, but is simple and might be useful to 165 | # narrow down root causes for regressions. 166 | redx = orig.__reduce_ex__() 167 | self.assertLen(redx, 2) 168 | self.assertIs(redx[0], status.Status) 169 | self.assertEqual( 170 | redx[1], 171 | (status.InitFromTag.serialized, 172 | (status.StatusCode.CANCELLED, b'Cucumber.', expected_all_payloads))) 173 | 174 | ser = pickle.dumps(orig) 175 | deser = pickle.loads(ser) 176 | self.assertEqual(deser, orig) 177 | self.assertIs(deser.__class__, orig.__class__) 178 | 179 | def test_init_from_serialized_exception_unexpected_len_state(self): 180 | with self.assertRaisesRegex( 181 | ValueError, r'Unexpected len\(state\) == 4' 182 | r' \[.*register_status_bindings\.cc:[0-9]+\]'): 183 | status.Status(status.InitFromTag.serialized, (0, 0, 0, 0)) 184 | 185 | def test_init_from_serialized_exception_unexpected_len_ap_item_tup(self): 186 | with self.assertRaisesRegex( 187 | ValueError, 188 | r'Unexpected len\(tuple\) == 3 where \(type_url, payload\) is expected' 189 | r' \[.*register_status_bindings\.cc:[0-9]+\]'): 190 | status.Status(status.InitFromTag.serialized, 191 | (status.StatusCode.CANCELLED, '', ((0, 0, 0),))) 192 | 193 | def test_init_from_capsule_direct_ok(self): 194 | orig = status.Status(status.StatusCode.CANCELLED, 'Direct.') 195 | from_cap = status.Status(status.InitFromTag.capsule, orig.as_absl_Status()) 196 | self.assertEqual(from_cap, orig) 197 | 198 | def test_init_from_capsule_as_capsule_method_ok(self): 199 | orig = status.Status(status.StatusCode.CANCELLED, 'AsCapsuleMethod.') 200 | from_cap = status.Status(status.InitFromTag.capsule, orig) 201 | self.assertEqual(from_cap, orig) 202 | 203 | @parameterized.parameters(None, '', 0) 204 | def test_init_from_capsule_direct_only_not_a_capsule(self, not_a_capsule): 205 | with self.assertRaises(ValueError) as ctx: 206 | status.Status(status.InitFromTag.capsule_direct_only, not_a_capsule) 207 | nm = not_a_capsule.__class__.__name__ 208 | self.assertEqual(str(ctx.exception), f'{nm} object is not a capsule.') 209 | 210 | @parameterized.parameters(None, '', 0) 211 | def test_init_from_capsule_direct_not_a_capsule(self, not_a_capsule): 212 | with self.assertRaises(ValueError) as ctx: 213 | status.Status(status.InitFromTag.capsule, not_a_capsule) 214 | nm = not_a_capsule.__class__.__name__ 215 | self.assertEqual( 216 | str(ctx.exception), 217 | f"{nm}.as_absl_Status() call failed: AttributeError: '{nm}' object" 218 | f" has no attribute 'as_absl_Status'") 219 | 220 | @parameterized.parameters(None, '', 0) 221 | def test_init_from_capsule_correct_method_not_a_capsule(self, not_a_capsule): 222 | with self.assertRaises(ValueError) as ctx: 223 | status.Status(status.InitFromTag.capsule, NotACapsule(not_a_capsule)) 224 | nm = not_a_capsule.__class__.__name__ 225 | self.assertEqual( 226 | str(ctx.exception), 227 | f'NotACapsule.as_absl_Status() returned an object ({nm})' 228 | f' that is not a capsule.') 229 | 230 | 231 | class StatusNotOkTest(absltest.TestCase): 232 | 233 | def test_build_status_not_ok_enum(self): 234 | e = status.BuildStatusNotOk(status.StatusCode.INVALID_ARGUMENT, 'Msg enum.') 235 | self.assertEqual(e.status.code(), status.StatusCode.INVALID_ARGUMENT) 236 | self.assertEqual(e.code, int(status.StatusCode.INVALID_ARGUMENT)) 237 | self.assertEqual(e.message, 'Msg enum.') 238 | 239 | def test_build_status_not_ok_int(self): 240 | with self.assertRaises(TypeError) as cm: 241 | status.BuildStatusNotOk(1, 'Msg int.') # pytype: disable=wrong-arg-types 242 | self.assertIn('incompatible function arguments', str(cm.exception)) 243 | 244 | def test_eq(self): 245 | sa1 = status.BuildStatusNotOk(status.StatusCode.UNKNOWN, 'sa') 246 | sa2 = status.BuildStatusNotOk(status.StatusCode.UNKNOWN, 'sa') 247 | sb = status.BuildStatusNotOk(status.StatusCode.UNKNOWN, 'sb') 248 | self.assertTrue(bool(sa1 == sa1)) # pylint: disable=comparison-with-itself 249 | self.assertTrue(bool(sa1 == sa2)) 250 | self.assertFalse(bool(sa1 == sb)) 251 | self.assertFalse(bool(sa1 == 'x')) 252 | self.assertFalse(bool('x' == sa1)) 253 | 254 | def test_pickle(self): 255 | orig = status.BuildStatusNotOk(status.StatusCode.UNKNOWN, 'Cabbage') 256 | ser = pickle.dumps(orig) 257 | deser = pickle.loads(ser) 258 | self.assertEqual(deser.message, 'Cabbage') 259 | self.assertEqual(deser, orig) 260 | self.assertIs(deser.__class__, orig.__class__) 261 | 262 | 263 | if __name__ == '__main__': 264 | absltest.main() 265 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/status_testing_no_cpp_eh_lib.h: -------------------------------------------------------------------------------- 1 | // This code is meant to be built with C++ exception handling disabled: 2 | // the whole point of absl::Status, absl::StatusOr is to provide an alternative 3 | // to C++ exception handling. 4 | 5 | #ifndef PYBIND11_ABSEIL_TESTS_STATUS_TESTING_NO_CPP_EH_LIB_H_ 6 | #define PYBIND11_ABSEIL_TESTS_STATUS_TESTING_NO_CPP_EH_LIB_H_ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "absl/log/absl_check.h" 14 | #include "absl/status/status.h" 15 | #include "absl/status/statusor.h" 16 | 17 | namespace pybind11_abseil_tests { 18 | namespace status_testing_no_cpp_eh { 19 | 20 | inline std::string CallCallbackWithStatusReturn( 21 | const std::function &cb) { 22 | absl::Status cb_return_value = cb(); 23 | return cb_return_value.ToString(); 24 | } 25 | 26 | inline std::string CallCallbackWithStatusOrIntReturn( 27 | const std::function()> &cb) { 28 | absl::StatusOr cb_return_value = cb(); 29 | if (cb_return_value.ok()) { 30 | return std::to_string(cb_return_value.value()); 31 | } 32 | return cb_return_value.status().ToString(); 33 | } 34 | 35 | inline PyObject *CallCallbackWithStatusOrObjectReturn( 36 | const std::function()> &cb) { 37 | absl::StatusOr cb_return_value = cb(); 38 | if (cb_return_value.ok()) { 39 | return cb_return_value.value(); 40 | } 41 | return PyUnicode_FromString(cb_return_value.status().ToString().c_str()); 42 | } 43 | 44 | inline absl::Status GenerateErrorStatusNotOk() { 45 | return absl::AlreadyExistsError("Something went wrong, again."); 46 | } 47 | 48 | inline absl::StatusOr ReturnStatusOrPyObjectPtr(bool is_ok) { 49 | if (is_ok) { 50 | return PyLong_FromLongLong(2314L); 51 | } 52 | return absl::InvalidArgumentError("!is_ok"); 53 | } 54 | 55 | inline std::string PassStatusOrPyObjectPtr( 56 | const absl::StatusOr &obj) { 57 | if (!obj.ok()) { 58 | return "!obj.ok()@" + std::string(obj.status().message()); 59 | } 60 | if (PyTuple_CheckExact(obj.value())) { 61 | return "is_tuple"; 62 | } 63 | return "!is_tuple"; 64 | } 65 | 66 | inline std::string CallCallbackWithStatusOrPyObjectPtrReturn( 67 | const std::function(std::string)> &cb, 68 | std::string cb_arg) { 69 | // Implicitly take ownership of Python reference: 70 | absl::StatusOr cb_result = cb(cb_arg); 71 | std::string result = PassStatusOrPyObjectPtr(cb_result); 72 | if (cb_result.ok()) { 73 | ABSL_CHECK_NE(Py_REFCNT(cb_result.value()), 0); 74 | Py_DECREF(cb_result.value()); // Release owned reference. 75 | } 76 | return result; 77 | } 78 | 79 | } // namespace status_testing_no_cpp_eh 80 | } // namespace pybind11_abseil_tests 81 | 82 | #endif // PYBIND11_ABSEIL_TESTS_STATUS_TESTING_NO_CPP_EH_LIB_H_ 83 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/status_testing_no_cpp_eh_pybind.cc: -------------------------------------------------------------------------------- 1 | #if true // go/pybind11_include_order 2 | #include 3 | #endif 4 | 5 | #include 6 | #include 7 | 8 | #include "pybind11_abseil/import_status_module.h" 9 | #include "pybind11_abseil/status_caster.h" 10 | #include "pybind11_abseil/statusor_caster.h" 11 | #include "pybind11_abseil/tests/status_testing_no_cpp_eh_lib.h" 12 | 13 | namespace pybind11_abseil_tests { 14 | namespace status_testing_no_cpp_eh { 15 | 16 | PYBIND11_MODULE(status_testing_no_cpp_eh_pybind, m) { 17 | pybind11::google::ImportStatusModule(); 18 | 19 | m.def("CallCallbackWithStatusReturn", &CallCallbackWithStatusReturn); 20 | m.def("CallCallbackWithStatusOrIntReturn", 21 | &CallCallbackWithStatusOrIntReturn); 22 | m.def("CallCallbackWithStatusOrObjectReturn", 23 | &CallCallbackWithStatusOrObjectReturn, 24 | pybind11::return_value_policy::take_ownership); 25 | m.def("GenerateErrorStatusNotOk", &GenerateErrorStatusNotOk); 26 | 27 | m.attr("defined_PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS") = 28 | #if defined(PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS) 29 | true; 30 | #else 31 | false; 32 | #endif 33 | 34 | m.def("ReturnStatusOrPyObjectPtr", &ReturnStatusOrPyObjectPtr, 35 | pybind11::return_value_policy::take_ownership); 36 | m.def("PassStatusOrPyObjectPtr", &PassStatusOrPyObjectPtr); 37 | m.def("CallCallbackWithStatusOrPyObjectPtrReturn", 38 | &CallCallbackWithStatusOrPyObjectPtrReturn); 39 | } 40 | 41 | } // namespace status_testing_no_cpp_eh 42 | } // namespace pybind11_abseil_tests 43 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/status_testing_no_cpp_eh_test.py: -------------------------------------------------------------------------------- 1 | from absl.testing import absltest 2 | 3 | from pybind11_abseil.tests import status_testing_no_cpp_eh_pybind 4 | from pybind11_abseil.tests import status_testing_no_cpp_eh_test_lib as test_lib 5 | 6 | _HAS_FUN_SPEC = ( 7 | status_testing_no_cpp_eh_pybind.defined_PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS 8 | ) 9 | _FUN_SPEC_NDEF = ( 10 | 'PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS is not defined.' 11 | ) 12 | 13 | 14 | class _TestModuleMixin: 15 | 16 | def getTestModule(self): # pylint: disable=invalid-name 17 | return status_testing_no_cpp_eh_pybind 18 | 19 | 20 | @absltest.skipIf(not _HAS_FUN_SPEC, _FUN_SPEC_NDEF) 21 | class StatusReturnTest(test_lib.StatusReturnTest, _TestModuleMixin): 22 | pass 23 | 24 | 25 | @absltest.skipIf(not _HAS_FUN_SPEC, _FUN_SPEC_NDEF) 26 | class StatusOrReturnTest(test_lib.StatusOrReturnTest, _TestModuleMixin): 27 | pass 28 | 29 | 30 | @absltest.skipIf(not _HAS_FUN_SPEC, _FUN_SPEC_NDEF) 31 | class StatusOrPyObjectPtrTest( 32 | test_lib.StatusOrPyObjectPtrTest, _TestModuleMixin 33 | ): 34 | pass 35 | 36 | 37 | if __name__ == '__main__': 38 | absltest.main() 39 | -------------------------------------------------------------------------------- /pybind11_abseil/tests/status_testing_no_cpp_eh_test_lib.py: -------------------------------------------------------------------------------- 1 | """This is a py_library to enable testing with pybind11 & PyCLIF.""" 2 | 3 | # This is the default for py_test code: 4 | # pylint: disable=missing-class-docstring 5 | # pylint: disable=missing-function-docstring 6 | 7 | from absl.testing import absltest 8 | from absl.testing import parameterized 9 | 10 | from pybind11_abseil import status 11 | 12 | # Exercises status_from_core_py_exc.cc:StatusFromFetchedExc() 13 | TAB_StatusFromFetchedExc = ( 14 | (MemoryError, 'RESOURCE_EXHAUSTED: MemoryError'), 15 | (NotImplementedError, 'UNIMPLEMENTED: NotImplementedError'), 16 | (KeyboardInterrupt, 'ABORTED: KeyboardInterrupt'), 17 | (SystemError, 'INTERNAL: SystemError'), 18 | (SyntaxError, 'INTERNAL: SyntaxError'), 19 | (TypeError, 'INVALID_ARGUMENT: TypeError'), 20 | (ValueError, 'OUT_OF_RANGE: ValueError'), 21 | (LookupError, 'NOT_FOUND: LookupError'), 22 | (RuntimeError, 'UNKNOWN: RuntimeError'), 23 | ) 24 | 25 | 26 | class StatusReturnTest(parameterized.TestCase): 27 | 28 | def setUp(self): 29 | super().setUp() 30 | self.tm = self.getTestModule() # pytype: disable=attribute-error 31 | 32 | def testStatusOk(self): # pylint: disable=invalid-name 33 | def cb(): 34 | pass 35 | 36 | self.assertEqual(self.tm.CallCallbackWithStatusReturn(cb), 'OK') 37 | 38 | @parameterized.parameters(*TAB_StatusFromFetchedExc) 39 | def testStatusFromFetchedExc(self, etype, expected): # pylint: disable=invalid-name 40 | 41 | def cb(): 42 | raise etype('Msg.') 43 | 44 | self.assertEqual( 45 | self.tm.CallCallbackWithStatusReturn(cb), expected + ': Msg.' 46 | ) 47 | 48 | def testStatusWrongReturnType(self): # pylint: disable=invalid-name 49 | def cb(): 50 | return ['something'] 51 | 52 | if getattr(self.tm, '__pyclif_codegen_mode__', None) == 'c_api': 53 | expected = 'OK' 54 | else: 55 | expected = ( 56 | r"INVALID_ARGUMENT: Unable to cast Python instance of type to C\+\+ type ('absl::(\w*::)?Status'|'\?')" 58 | ) 59 | self.assertRegex(self.tm.CallCallbackWithStatusReturn(cb), expected) 60 | 61 | def testAssertionErrorBare(self): # pylint: disable=invalid-name 62 | 63 | def cb(): 64 | assert False 65 | 66 | self.assertEqual( 67 | self.tm.CallCallbackWithStatusReturn(cb), 'UNKNOWN: AssertionError: ' 68 | ) 69 | 70 | def testAssertionErrorWithValue(self): # pylint: disable=invalid-name 71 | 72 | def cb(): 73 | assert False, 'Unexpected' 74 | 75 | self.assertEqual( 76 | self.tm.CallCallbackWithStatusReturn(cb), 77 | 'UNKNOWN: AssertionError: Unexpected', 78 | ) 79 | 80 | def testErrorStatusNotOkRoundTrip(self): # pylint: disable=invalid-name 81 | 82 | def cb(): 83 | self.tm.GenerateErrorStatusNotOk() 84 | 85 | self.assertEqual( 86 | self.tm.CallCallbackWithStatusReturn(cb), 87 | 'ALREADY_EXISTS: Something went wrong, again.', 88 | ) 89 | 90 | 91 | class StatusOrReturnTest(parameterized.TestCase): 92 | 93 | def setUp(self): 94 | super().setUp() 95 | self.tm = self.getTestModule() # pytype: disable=attribute-error 96 | 97 | def testStatusOrIntOk(self): # pylint: disable=invalid-name 98 | def cb(): 99 | return 5 100 | 101 | self.assertEqual(self.tm.CallCallbackWithStatusOrIntReturn(cb), '5') 102 | 103 | @parameterized.parameters(*TAB_StatusFromFetchedExc) 104 | def testStatusOrIntFromFetchedExc(self, etype, expected): # pylint: disable=invalid-name 105 | def cb(): 106 | raise etype('Msg.') 107 | 108 | self.assertEqual( 109 | self.tm.CallCallbackWithStatusOrIntReturn(cb), expected + ': Msg.' 110 | ) 111 | 112 | def testStatusOrIntWrongReturnType(self): # pylint: disable=invalid-name 113 | def cb(): 114 | return '5' 115 | 116 | if getattr(self.tm, '__pyclif_codegen_mode__', None) == 'c_api': 117 | expected = 'INVALID_ARGUMENT: TypeError: expecting int' 118 | else: 119 | expected = ( 120 | r"INVALID_ARGUMENT: Unable to cast Python instance of type to C\+\+ type ('absl::(\w*::)?StatusOr'|'\?')" 122 | ) 123 | self.assertRegex(self.tm.CallCallbackWithStatusOrIntReturn(cb), expected) 124 | 125 | 126 | class StatusOrPyObjectPtrTest(absltest.TestCase): 127 | 128 | def setUp(self): 129 | super().setUp() 130 | self.tm = self.getTestModule() # pytype: disable=attribute-error 131 | 132 | def testStatusOrObject(self): # pylint: disable=invalid-name 133 | while True: 134 | lst = [1, 2, 3, 4] 135 | 136 | def cb(): 137 | return lst 138 | 139 | # call many times to be sure that object reference is not being removed 140 | for _ in range(10): 141 | res = self.tm.CallCallbackWithStatusOrObjectReturn(cb) 142 | self.assertListEqual(res, lst) 143 | self.assertIs(res, lst) 144 | break # Comment out for manual leak checking (use `top` command). 145 | # Manual verification: cl/485274434, cl/578064081 146 | 147 | def testReturnStatusOrPyObjectPtr(self): # pylint: disable=invalid-name 148 | obj = self.tm.ReturnStatusOrPyObjectPtr(True) 149 | self.assertEqual(obj, 2314) 150 | with self.assertRaises(status.StatusNotOk) as ctx: 151 | self.tm.ReturnStatusOrPyObjectPtr(False) 152 | self.assertEqual(str(ctx.exception), '!is_ok [INVALID_ARGUMENT]') 153 | while True: 154 | self.tm.ReturnStatusOrPyObjectPtr(True) 155 | break # Comment out for manual leak checking (use `top` command). 156 | # Manual verification: cl/578064081 157 | while True: 158 | with self.assertRaises(status.StatusNotOk) as ctx: 159 | self.tm.ReturnStatusOrPyObjectPtr(False) 160 | break # Comment out for manual leak checking (use `top` command). 161 | # Manual verification: cl/578064081 162 | 163 | def testPassStatusOrPyObjectPtr(self): # pylint: disable=invalid-name 164 | pass_fn = self.tm.PassStatusOrPyObjectPtr 165 | self.assertEqual(pass_fn(()), 'is_tuple') 166 | self.assertEqual(pass_fn([]), '!is_tuple') 167 | while True: 168 | pass_fn([]) 169 | break # Comment out for manual leak checking (use `top` command). 170 | # Manual verification: cl/578064081 171 | 172 | def testCallCallbackWithStatusOrPyObjectPtrReturn(self): # pylint: disable=invalid-name 173 | def cb(arg): 174 | if arg == 'tup': 175 | return () 176 | if arg == 'lst': 177 | return [] 178 | raise ValueError(f'Unknown arg: {repr(arg)}') 179 | 180 | cc_fn = self.tm.CallCallbackWithStatusOrPyObjectPtrReturn 181 | res = cc_fn(cb, 'tup') 182 | self.assertEqual(res, 'is_tuple') 183 | res = cc_fn(cb, 'lst') 184 | self.assertEqual(res, '!is_tuple') 185 | 186 | if ( 187 | hasattr(self.tm, '__pyclif_codegen_mode__') 188 | or self.tm.defined_PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS 189 | ): 190 | res = cc_fn(cb, 'exc') 191 | self.assertEqual(res, "!obj.ok()@ValueError: Unknown arg: 'exc'") 192 | while True: 193 | cc_fn(cb, 'exc') 194 | break # Comment out for manual leak checking (use `top` command). 195 | # Manual verification: cl/578064081 196 | else: 197 | with self.assertRaises(ValueError) as ctx: 198 | cc_fn(cb, 'exc') 199 | self.assertEqual(str(ctx.exception), "Unknown arg: 'exc'") 200 | -------------------------------------------------------------------------------- /pybind11_abseil/utils_pybind11_absl.cc: -------------------------------------------------------------------------------- 1 | #include "pybind11_abseil/utils_pybind11_absl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "absl/strings/string_view.h" 7 | 8 | namespace pybind11 { 9 | namespace google { 10 | 11 | str decode_utf8_replace(absl::string_view s) { 12 | PyObject* u = PyUnicode_DecodeUTF8(s.data(), s.size(), "replace"); 13 | if (u == nullptr) { 14 | throw error_already_set(); 15 | } 16 | return reinterpret_steal(u); 17 | } 18 | 19 | } // namespace google 20 | } // namespace pybind11 21 | -------------------------------------------------------------------------------- /pybind11_abseil/utils_pybind11_absl.h: -------------------------------------------------------------------------------- 1 | #ifndef PYBIND11_ABSEIL_UTILS_PYBIND11_ABSL_H_ 2 | #define PYBIND11_ABSEIL_UTILS_PYBIND11_ABSL_H_ 3 | 4 | // Note: This is meant to only depend on pybind11 and absl headers. 5 | // DO NOT add other dependencies. 6 | 7 | #include 8 | 9 | #include "absl/strings/string_view.h" 10 | 11 | namespace pybind11 { 12 | namespace google { 13 | 14 | // To avoid clobbering potentially critical error messages with 15 | // `UnicodeDecodeError`. 16 | str decode_utf8_replace(absl::string_view s); 17 | 18 | } // namespace google 19 | } // namespace pybind11 20 | 21 | #endif // PYBIND11_ABSEIL_UTILS_PYBIND11_ABSL_H_ 22 | -------------------------------------------------------------------------------- /scripts/build_and_run_tests_bazel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The following script builds and runs tests 4 | 5 | set -e # exit when any command fails 6 | set -x # Prints all executed commands 7 | 8 | MYDIR="$(dirname "$(realpath "$0")")" 9 | 10 | BAZEL=$(which bazel || true) 11 | if [[ -z $BAZEL || ! -x $BAZEL ]] 12 | then 13 | echo -e -n '\e[1m\e[93m' 14 | echo -n 'Bazel not found (bazel (https://bazel.build/) is needed to ' 15 | echo -n 'compile & test). ' 16 | echo -e 'Exiting...\e[0m' 17 | exit 1 18 | fi 19 | 20 | echo "Building and testing in $PWD using 'python' (version $PYVERSION)." 21 | 22 | bazel clean --expunge # Force a deep update 23 | 24 | # Can't use BAZEL_CXXOPTS since it will be override by the bazelrc cxxopt need 25 | # to use --cxxopt on the command line instead which will override the bazelrc 26 | # cxxopt config. 27 | bazel test --cxxopt=-std=c++14 ... --test_output=errors "$@" --enable_bzlmod 28 | bazel test --cxxopt=-std=c++17 ... --test_output=errors "$@" --enable_bzlmod 29 | bazel test --cxxopt=-std=c++20 ... --test_output=errors "$@" --enable_bzlmod 30 | 31 | #bazel test --cxxopt=-std=c++14 ... --test_output=errors "$@" --noenable_bzlmod --enable_workspace 32 | bazel test --cxxopt=-std=c++17 ... --test_output=errors "$@" --noenable_bzlmod --enable_workspace 33 | bazel test --cxxopt=-std=c++20 ... --test_output=errors "$@" --noenable_bzlmod --enable_workspace 34 | -------------------------------------------------------------------------------- /scripts/build_and_run_tests_cmake.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The following scripts: 4 | # - creates a virtualenv 5 | # - installs the pip package dependencies 6 | # - builds and runs tests 7 | 8 | set -e # exit when any command fails 9 | set -x # Prints all executed commands 10 | 11 | MYDIR="$(dirname "$(realpath "$0")")" 12 | 13 | CMAKE=$(which cmake || true) 14 | if [[ -z $CMAKE || ! -x $CMAKE ]] 15 | then 16 | echo -e -n '\e[1m\e[93m' 17 | echo -n 'CMake not found (cmake is needed to ' 18 | echo -n 'compile & test). ' 19 | echo -e 'Exiting...\e[0m' 20 | exit 1 21 | fi 22 | 23 | VIRTUAL_ENV_BINARY=$(which virtualenv || true) 24 | if [[ -z $VIRTUAL_ENV_BINARY || ! -x $VIRTUAL_ENV_BINARY ]] 25 | then 26 | echo -e -n '\e[1m\e[93m' 27 | echo -n 'virtualenv command not found ' 28 | echo -n '(try `python3 -m pip install virtualenv`, possibly as root). ' 29 | echo -e 'Exiting...\e[0m' 30 | exit 1 31 | fi 32 | 33 | is_in_virtual_env="false" 34 | # if we are in a virtual_env, we will not create a new one inside. 35 | if [[ "$VIRTUAL_ENV" != "" ]] 36 | then 37 | echo -e "\e[1m\e[93mVirtualenv already detected. We do not create a new one.\e[0m" 38 | is_in_virtual_env="true" 39 | fi 40 | 41 | echo -e "\e[33mRunning ${0} from $PWD\e[0m" 42 | PYBIN=$(which python3 || true) 43 | if [[ -z $PYBIN || ! -x $PYBIN ]] 44 | then 45 | echo -e '\e[1m\e[93mpython3 not found! Skip build and test.\e[0m' 46 | exit 1 47 | fi 48 | 49 | PYVERSION=$($PYBIN -c 'import sys; print(".".join(map(str, sys.version_info[:3])))') 50 | 51 | VENV_DIR="./venv" 52 | 53 | if [[ $is_in_virtual_env == "false" ]]; then 54 | if ! [ -d "$VENV_DIR" ]; then 55 | echo "Installing..." 56 | echo -e "\e[33mInstalling a virtualenv to $VENV_DIR. The setup is long the first time, please wait.\e[0m" 57 | virtualenv -p "$PYBIN" "$VENV_DIR" 58 | else 59 | echo -e "\e[33mReusing virtualenv from $VENV_DIR.\e[0m" 60 | fi 61 | source "${VENV_DIR}/bin/activate" 62 | fi 63 | 64 | # We only exit the virtualenv if we created one. 65 | function cleanup { 66 | if [[ $is_in_virtual_env == "true" ]]; then 67 | echo "Exiting virtualenv" 68 | deactivate 69 | fi 70 | } 71 | trap cleanup EXIT 72 | 73 | echo -e "\e[33mInstalling the requirements (use --noinstall to skip).\e[0m" 74 | pip3 install --upgrade -r $(python3 -c 'import sys; print("./pybind11_abseil/requirements/requirements_lock_%d_%d.txt" % (sys.version_info[:2]))') 75 | 76 | echo "Building and testing in $PWD using 'python' (version $PYVERSION)." 77 | 78 | PYTHON_BIN_PATH="$(which python3)" 79 | export PYTHON_BIN_PATH 80 | PYTHON_LIB_PATH=$(python3 -c "import sysconfig; print(sysconfig.get_path('include'))") 81 | export PYTHON_LIB_PATH 82 | echo "Using PYTHON_BIN_PATH: $PYTHON_BIN_PATH" 83 | echo "Using PYTHON_LIB_PATH: $PYTHON_LIB_PATH" 84 | 85 | if [ -e tmp_build ]; then 86 | rm -r tmp_build 87 | fi 88 | 89 | mkdir tmp_build 90 | cd tmp_build 91 | 92 | # C++17 93 | cmake ../ -DCMAKE_CXX_STANDARD=17 -DCMAKE_VERBOSE_MAKEFILE=ON 94 | make "$@" 95 | ctest --output-on-failure --extra-verbose 96 | 97 | rm -r ./* 98 | 99 | # C++20 100 | cmake ../ -DCMAKE_CXX_STANDARD=20 -DCMAKE_VERBOSE_MAKEFILE=ON 101 | make "$@" 102 | ctest --output-on-failure --extra-verbose 103 | 104 | cd ../ 105 | rm -r tmp_build 106 | --------------------------------------------------------------------------------