From 9c887a1331973db4c92852903b65216c09f01fe6 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 22 Jan 2026 22:59:58 +0300 Subject: [PATCH 01/30] Remove dependencies on Boost.StaticAssert. Boost.StaticAssert has been merged into Boost.Config, so remove the dependency. --- CMakeLists.txt | 1 - build.jam | 1 - test/Jamfile | 1 - 3 files changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 299ef84e9..71bad1552 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,6 @@ target_link_libraries(${_boost_python} Boost::numeric_conversion Boost::preprocessor Boost::smart_ptr - Boost::static_assert Boost::tuple Boost::type_traits Boost::utility diff --git a/build.jam b/build.jam index e9eb1a11a..55bed73ba 100644 --- a/build.jam +++ b/build.jam @@ -19,7 +19,6 @@ constant boost_dependencies : /boost/mpl//boost_mpl /boost/numeric_conversion//boost_numeric_conversion /boost/preprocessor//boost_preprocessor - /boost/static_assert//boost_static_assert /boost/tuple//boost_tuple /boost/type_traits//boost_type_traits /boost/utility//boost_utility ; diff --git a/test/Jamfile b/test/Jamfile index 40115d86c..265658892 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -63,7 +63,6 @@ alias base_deps : usage-requirements /boost/function//boost_function /boost/mpl//boost_mpl /boost/preprocessor//boost_preprocessor - /boost/static_assert//boost_static_assert /boost/type_traits//boost_type_traits ; test-suite python From e6917d9c58d86f1ac5f06cd6da7f033b70db7395 Mon Sep 17 00:00:00 2001 From: sdarwin Date: Fri, 13 Mar 2026 07:01:23 +0100 Subject: [PATCH 02/30] Docs: adjust template to support Sphinx 9 --- doc/numpy/_templates/layout.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/numpy/_templates/layout.html b/doc/numpy/_templates/layout.html index 69e1a868c..89f1ca0b3 100644 --- a/doc/numpy/_templates/layout.html +++ b/doc/numpy/_templates/layout.html @@ -47,7 +47,7 @@ }; {%- for scriptfile in script_files %} - + {%- endfor %} From b774e5948f4ccc31c1ba7f63d225968582399f13 Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Thu, 4 Jun 2026 00:15:55 +0000 Subject: [PATCH 03/30] Create vcpkg.json --- vcpkg.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 vcpkg.json diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 000000000..1d2d001f7 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json", + "name": "boost-python", + "version-string": "1.91.0", + "builtin-baseline": "d015e31e90838a4c9dfa3eed45979bc70d9357fc", + "dependencies": [ + "boost-config", + "boost-core", + "boost-function", + "boost-graph", + "boost-iterator", + "boost-lexical-cast", + "boost-mpl", + "boost-preprocessor", + "boost-smart-ptr", + "boost-static-assert", + "boost-align", + "python3" + ] +} From a5b21ee931a0428c0a5333adedf58bf6bf6dbf11 Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Thu, 4 Jun 2026 00:28:44 +0000 Subject: [PATCH 04/30] Update test-windows.yml --- .github/workflows/test-windows.yml | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 576e1f441..1f95821cb 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -10,6 +10,10 @@ jobs: matrix: python-version: [3.7] + env: + VCPKG_DEFAULT_TRIPLET: 'x64-windows' + VCPKG_DEFAULT_HOST_TRIPLET: 'x64-windows' + steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 @@ -17,23 +21,10 @@ jobs: python-version: ${{ matrix.python-version }} - uses: microsoft/setup-msbuild@v2 - name: setup boost prerequisites - uses: lukka/run-vcpkg@v6 + uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11.6 with: - vcpkgGitCommitId: '88b1071e39f13b632644d9d953738d345a4ac055' - vcpkgDirectory: '${{ runner.workspace }}/vcpkg' - vcpkgTriplet: x64-windows - vcpkgArguments: > - boost-config - boost-core - boost-function - boost-graph - boost-iterator - boost-lexical-cast - boost-mpl - boost-preprocessor - boost-smart-ptr - boost-static-assert - boost-align + vcpkgDirectory: '${{ github.workspace }}/vcpkg' + runVcpkgInstall: true - name: setup faber run: | python -m pip install --upgrade pip From d68c52f3c3ae3fbe8c8d3f4d4d38cef2aeef968e Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Wed, 17 Jun 2026 19:05:48 +0000 Subject: [PATCH 05/30] Update test-windows.yml: Fix the `--with-boost-include` directory passed to the `faber` commands --- .github/workflows/test-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 1f95821cb..639fe65d5 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -33,8 +33,8 @@ jobs: - name: build shell: cmd run: | - faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include=${{ runner.workspace }}\vcpkg\installed\x64-windows\include -j4 + faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include=${{ github.workspace }}\vcpkg\installed\x64-windows\include -j4 - name: test shell: cmd run: | - faber --builddir=build cxx.name=msvc --with-boost-include=${{ runner.workspace }}\vcpkg\installed\x64-windows\include -j4 test.report + faber --builddir=build cxx.name=msvc --with-boost-include=${{ github.workspace }}\vcpkg\installed\x64-windows\include -j4 test.report From 8b3a45d79ba1ac3fbed80206a2dead6c745bf4c4 Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Wed, 17 Jun 2026 15:26:35 -0700 Subject: [PATCH 06/30] List vcpkg directory contents, looking for config.hpp --- .github/workflows/test-windows.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 639fe65d5..35bfe79d6 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -25,6 +25,9 @@ jobs: with: vcpkgDirectory: '${{ github.workspace }}/vcpkg' runVcpkgInstall: true + - name: List directory contents + run: Get-ChildItem "${{ github.workspace }}/vcpkg" -Recurse -Force -File -Filter 'config.hpp' + shell: pwsh - name: setup faber run: | python -m pip install --upgrade pip From 874b21a680eae016d55546581d8aa9bb174dab71 Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Thu, 18 Jun 2026 10:01:12 -0700 Subject: [PATCH 07/30] vcpkg.json: Go back to the same commit for builtin-baseline as was used for `vcpkgGitCommitId` prior to this PR --- vcpkg.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcpkg.json b/vcpkg.json index 1d2d001f7..2c5bb02df 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -2,7 +2,7 @@ "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json", "name": "boost-python", "version-string": "1.91.0", - "builtin-baseline": "d015e31e90838a4c9dfa3eed45979bc70d9357fc", + "builtin-baseline": "88b1071e39f13b632644d9d953738d345a4ac055", "dependencies": [ "boost-config", "boost-core", From d5ab28a8cc64f3cf3591f63bf270dad1caa4edb1 Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Thu, 18 Jun 2026 13:53:19 -0700 Subject: [PATCH 08/30] test-windows.yml: Set VCPKG_ROOT environment variable, etc. --- .github/workflows/test-windows.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 35bfe79d6..f905e4c36 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -11,6 +11,7 @@ jobs: python-version: [3.7] env: + VCPKG_ROOT: ${{ github.workspace }}\vcpkg VCPKG_DEFAULT_TRIPLET: 'x64-windows' VCPKG_DEFAULT_HOST_TRIPLET: 'x64-windows' @@ -26,7 +27,7 @@ jobs: vcpkgDirectory: '${{ github.workspace }}/vcpkg' runVcpkgInstall: true - name: List directory contents - run: Get-ChildItem "${{ github.workspace }}/vcpkg" -Recurse -Force -File -Filter 'config.hpp' + run: Get-ChildItem "${{ github.workspace }}\vcpkg" -Recurse -Force -File -Filter 'config.hpp' shell: pwsh - name: setup faber run: | @@ -36,8 +37,8 @@ jobs: - name: build shell: cmd run: | - faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include=${{ github.workspace }}\vcpkg\installed\x64-windows\include -j4 + faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include="${{ github.workspace }}\vcpkg\installed\x64-windows\include" -j4 - name: test shell: cmd run: | - faber --builddir=build cxx.name=msvc --with-boost-include=${{ github.workspace }}\vcpkg\installed\x64-windows\include -j4 test.report + faber --builddir=build cxx.name=msvc --with-boost-include="${{ github.workspace }}\vcpkg\installed\x64-windows\include" -j4 test.report From 52ac3bdcafa91fb35b4e9838370c66aebb0b0035 Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Thu, 18 Jun 2026 15:18:53 -0700 Subject: [PATCH 09/30] test-windows.yml: Make workflow much more like my other, working projects that use vcpkg --- .github/workflows/test-windows.yml | 51 ++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index f905e4c36..0258b8aa9 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -11,34 +11,81 @@ jobs: python-version: [3.7] env: - VCPKG_ROOT: ${{ github.workspace }}\vcpkg + VCPKG_ROOT: '${{ github.workspace }}/vcpkg' + VCPKG_ASSET_SOURCES: "${{ github.workspace }}/vcpkgAssets" + X_VCPKG_ASSET_SOURCES: clear;x-azurl,file:///${{ github.workspace }}/vcpkgAssets,,readwrite + VCPKG_BINARY_SOURCES: clear;files,${{ github.workspace }}/vcpkgBin,readwrite + VCPKG_BUILD_TREES: "${{ github.workspace }}/vcpkgBuild" + VCPKG_INSTALL_OPTIONS: "--x-buildtrees-root=${{ github.workspace }}/vcpkgBuild" VCPKG_DEFAULT_TRIPLET: 'x64-windows' VCPKG_DEFAULT_HOST_TRIPLET: 'x64-windows' steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + + - name: Restore vcpkg cache + id: cache-vcpkg-restore + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: | + "${{ github.workspace }}/vcpkgAssets" + "${{ github.workspace }}/vcpkgBCache" + "${{ github.workspace }}/vcpkgBin" + "${{ github.workspace }}/vcpkgBuild" + key: vcpkgCache-${{ github.repository_owner }}-${{ matrix.os }}-${{ matrix.triplet }}-${{ hashFiles('vcpkg.json') }} + + - name: Create directories on cache miss + run: | + mkdir -p "${{ github.workspace }}/vcpkgAssets" + mkdir -p "${{ github.workspace }}/vcpkgBCache" + mkdir -p "${{ github.workspace }}/vcpkgBin" + mkdir -p "${{ github.workspace }}/vcpkgBuild" + if: steps.cache-vcpkg-restore.outputs.cache-hit != 'true' + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} + - uses: microsoft/setup-msbuild@v2 + + - name: Install CMake + uses: lukka/get-cmake@591817e96fcad43505fb4eae36172462abb3a42e # v4.3.3 + - name: setup boost prerequisites uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11.6 with: vcpkgDirectory: '${{ github.workspace }}/vcpkg' + binaryCachePath: "${{ github.workspace }}/vcpkgBCache" runVcpkgInstall: true + - name: List directory contents run: Get-ChildItem "${{ github.workspace }}\vcpkg" -Recurse -Force -File -Filter 'config.hpp' shell: pwsh + - name: setup faber run: | python -m pip install --upgrade pip python -m pip install setuptools faber numpy faber --info=tools cxx + - name: build shell: cmd run: | faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include="${{ github.workspace }}\vcpkg\installed\x64-windows\include" -j4 + - name: test shell: cmd run: | faber --builddir=build cxx.name=msvc --with-boost-include="${{ github.workspace }}\vcpkg\installed\x64-windows\include" -j4 test.report + + - name: Save vcpkg cache + id: cache-vcpkg-save + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: | + "${{ github.workspace }}/vcpkgAssets" + "${{ github.workspace }}/vcpkgBCache" + "${{ github.workspace }}/vcpkgBin" + "${{ github.workspace }}/vcpkgBuild" + key: ${{ steps.cache-vcpkg-restore.outputs.cache-primary-key }} + if: steps.cache-vcpkg-restore.outputs.cache-hit != 'true' From c7ce567e1722d4c353d1cfdee372f25ad800b4ee Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Sat, 20 Jun 2026 07:58:36 -0700 Subject: [PATCH 10/30] test-windows.yml: Search the entire github.workspace directory and subdirectories for config.hpp --- .github/workflows/test-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 0258b8aa9..243cae93a 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -59,7 +59,7 @@ jobs: runVcpkgInstall: true - name: List directory contents - run: Get-ChildItem "${{ github.workspace }}\vcpkg" -Recurse -Force -File -Filter 'config.hpp' + run: Get-ChildItem "${{ github.workspace }}" -Recurse -Force -File -Filter 'config.hpp' shell: pwsh - name: setup faber From 112ec2ab011bbdfb29f3001eb3f7b2b957718fd2 Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Sat, 20 Jun 2026 08:03:10 -0700 Subject: [PATCH 11/30] test-windows.yml: Update `microsoft/setup-msbuild` to latest version, v3.0.0 --- .github/workflows/test-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 243cae93a..ce1f70450 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -46,7 +46,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - - uses: microsoft/setup-msbuild@v2 + - uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3.0.0 - name: Install CMake uses: lukka/get-cmake@591817e96fcad43505fb4eae36172462abb3a42e # v4.3.3 From b0bac91a8174b082a44d0849bcddbfe1905c4f15 Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Sat, 20 Jun 2026 09:41:14 -0700 Subject: [PATCH 12/30] vcpkg.json: Go back to latest vcpkg release for builtin-baseline --- vcpkg.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcpkg.json b/vcpkg.json index 2c5bb02df..5a9e71d23 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -2,7 +2,7 @@ "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json", "name": "boost-python", "version-string": "1.91.0", - "builtin-baseline": "88b1071e39f13b632644d9d953738d345a4ac055", + "builtin-baseline": "f3e10653cc27d62a37a3763cd84b38bca07c6075", "dependencies": [ "boost-config", "boost-core", From 83d828d53d04f82e8038e819b4ffcb862622c4c0 Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Sat, 20 Jun 2026 11:00:01 -0700 Subject: [PATCH 13/30] test-windows.yml: Try again to set the correct with-boost-include directory --- .github/workflows/test-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index ce1f70450..706690470 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -71,12 +71,12 @@ jobs: - name: build shell: cmd run: | - faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include="${{ github.workspace }}\vcpkg\installed\x64-windows\include" -j4 + faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include="${{ github.workspace }}\\969f6665-88a2-4c98-938e-ca9259871fec\\vcpkg_installed\\x64-windows\\include" -j4 - name: test shell: cmd run: | - faber --builddir=build cxx.name=msvc --with-boost-include="${{ github.workspace }}\vcpkg\installed\x64-windows\include" -j4 test.report + faber --builddir=build cxx.name=msvc --with-boost-include="${{ github.workspace }}\\969f6665-88a2-4c98-938e-ca9259871fec\\vcpkg_installed\\x64-windows\\include" -j4 test.report - name: Save vcpkg cache id: cache-vcpkg-save From 7f1f7a8c9eac35d1db7f793744471bb11a9daece Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Sat, 20 Jun 2026 17:59:12 -0700 Subject: [PATCH 14/30] test-windows.yml: Set VCPKG_INSTALLED_DIR env var, and use its value in `--with-boost-include=` faber parameters --- .github/workflows/test-windows.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 706690470..2515f527d 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -16,6 +16,7 @@ jobs: X_VCPKG_ASSET_SOURCES: clear;x-azurl,file:///${{ github.workspace }}/vcpkgAssets,,readwrite VCPKG_BINARY_SOURCES: clear;files,${{ github.workspace }}/vcpkgBin,readwrite VCPKG_BUILD_TREES: "${{ github.workspace }}/vcpkgBuild" + VCPKG_INSTALLED_DIR: "${{ github.workspace }}/vcpkgInstalled" VCPKG_INSTALL_OPTIONS: "--x-buildtrees-root=${{ github.workspace }}/vcpkgBuild" VCPKG_DEFAULT_TRIPLET: 'x64-windows' VCPKG_DEFAULT_HOST_TRIPLET: 'x64-windows' @@ -71,12 +72,12 @@ jobs: - name: build shell: cmd run: | - faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include="${{ github.workspace }}\\969f6665-88a2-4c98-938e-ca9259871fec\\vcpkg_installed\\x64-windows\\include" -j4 + faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include="${{ github.workspace }}/vcpkgInstalled" -j4 - name: test shell: cmd run: | - faber --builddir=build cxx.name=msvc --with-boost-include="${{ github.workspace }}\\969f6665-88a2-4c98-938e-ca9259871fec\\vcpkg_installed\\x64-windows\\include" -j4 test.report + faber --builddir=build cxx.name=msvc --with-boost-include="${{ github.workspace }}/vcpkgInstalled" -j4 test.report - name: Save vcpkg cache id: cache-vcpkg-save From a017f0877027a814f8b21b8bd50fba11a05f0da1 Mon Sep 17 00:00:00 2001 From: Stephen G Tuggy Date: Sat, 20 Jun 2026 23:15:32 -0700 Subject: [PATCH 15/30] test-windows.yml: Forgot to include `/x64-windows/include` in `--with-boost-include=` faber parameters --- .github/workflows/test-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 2515f527d..feb827d23 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -72,12 +72,12 @@ jobs: - name: build shell: cmd run: | - faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include="${{ github.workspace }}/vcpkgInstalled" -j4 + faber --builddir=build cxx.name=msvc --log=commands --log=output --with-boost-include="${{ github.workspace }}/vcpkgInstalled/x64-windows/include" -j4 - name: test shell: cmd run: | - faber --builddir=build cxx.name=msvc --with-boost-include="${{ github.workspace }}/vcpkgInstalled" -j4 test.report + faber --builddir=build cxx.name=msvc --with-boost-include="${{ github.workspace }}/vcpkgInstalled/x64-windows/include" -j4 test.report - name: Save vcpkg cache id: cache-vcpkg-save From 521a86817da54cb28cac71287704b7ae39d1e0f6 Mon Sep 17 00:00:00 2001 From: Stefan Seefeld Date: Sun, 21 Jun 2026 14:13:22 -0400 Subject: [PATCH 16/30] Windows build cleanup. --- .github/workflows/test-windows.yml | 8 +------- vcpkg.json => .github/workflows/vcpkg.json | 0 2 files changed, 1 insertion(+), 7 deletions(-) rename vcpkg.json => .github/workflows/vcpkg.json (100%) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index feb827d23..d13b6bf86 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -49,19 +49,13 @@ jobs: - uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3.0.0 - - name: Install CMake - uses: lukka/get-cmake@591817e96fcad43505fb4eae36172462abb3a42e # v4.3.3 - - name: setup boost prerequisites uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11.6 with: vcpkgDirectory: '${{ github.workspace }}/vcpkg' binaryCachePath: "${{ github.workspace }}/vcpkgBCache" runVcpkgInstall: true - - - name: List directory contents - run: Get-ChildItem "${{ github.workspace }}" -Recurse -Force -File -Filter 'config.hpp' - shell: pwsh + vcpkgJsonGlob: .github/workflows/vcpkg.json - name: setup faber run: | diff --git a/vcpkg.json b/.github/workflows/vcpkg.json similarity index 100% rename from vcpkg.json rename to .github/workflows/vcpkg.json From 14f1bbe6b884d9363378f42898d198a99a584e48 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Sun, 3 May 2026 15:55:57 +0900 Subject: [PATCH 17/30] refactor: use PyUnicode_AsUTF8 with Python 3.14+ _PyUnicode_AsString is deprecated since Python 3.14 https://docs.python.org/3.14/deprecations/index.html#id2 fix #512 --- src/converter/builtin_converters.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/converter/builtin_converters.cpp b/src/converter/builtin_converters.cpp index ee2d5b479..227fe2f80 100644 --- a/src/converter/builtin_converters.cpp +++ b/src/converter/builtin_converters.cpp @@ -40,22 +40,18 @@ namespace // An lvalue conversion function which extracts a char const* from a // Python String. -#if PY_VERSION_HEX < 0x03000000 void* convert_to_cstring(PyObject* obj) { +#if PY_VERSION_HEX < 0x03000000 return PyString_Check(obj) ? PyString_AsString(obj) : 0; - } #elif PY_VERSION_HEX < 0x03070000 - void* convert_to_cstring(PyObject* obj) - { return PyUnicode_Check(obj) ? _PyUnicode_AsString(obj) : 0; - } -#else - void* convert_to_cstring(PyObject* obj) - { +#elif PY_VERSION_HEX < 0x030E0000 return PyUnicode_Check(obj) ? const_cast(reinterpret_cast(_PyUnicode_AsString(obj))) : 0; - } +#else + return PyUnicode_Check(obj) ? const_cast(reinterpret_cast(PyUnicode_AsUTF8(obj))) : 0; #endif + } // Given a target type and a SlotPolicy describing how to perform a // given conversion, registers from_python converters which use the From 9e2f5191e53f12248175a434f7f7496454e09fa4 Mon Sep 17 00:00:00 2001 From: O01eg <397177+o01eg@users.noreply.github.com> Date: Sun, 20 Apr 2025 09:24:16 +0400 Subject: [PATCH 18/30] Add support for multi-phase module initialization --- include/boost/python/module.hpp | 3 ++ include/boost/python/module_init.hpp | 54 ++++++++++++++++++++++++++++ src/module.cpp | 12 +++++++ test/fabscript | 5 +++ test/module_multi_phase.cpp | 15 ++++++++ test/module_multi_phase.py | 23 ++++++++++++ 6 files changed, 112 insertions(+) create mode 100644 test/module_multi_phase.cpp create mode 100644 test/module_multi_phase.py diff --git a/include/boost/python/module.hpp b/include/boost/python/module.hpp index 8ad69f5a3..f6f9fa871 100644 --- a/include/boost/python/module.hpp +++ b/include/boost/python/module.hpp @@ -9,5 +9,8 @@ # include # define BOOST_PYTHON_MODULE BOOST_PYTHON_MODULE_INIT +# if PY_VERSION_HEX >= 0x03050000 +# define BOOST_PYTHON_MODULE_MULTI_PHASE BOOST_PYTHON_MODULE_MULTI_PHASE_INIT +# endif #endif // MODULE_DWA20011221_HPP diff --git a/include/boost/python/module_init.hpp b/include/boost/python/module_init.hpp index 390db82cf..f12550b22 100644 --- a/include/boost/python/module_init.hpp +++ b/include/boost/python/module_init.hpp @@ -47,6 +47,12 @@ namespace detail { BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef&, void(*)(), bool gil_not_used = false); +# if PY_VERSION_HEX >= 0x03050000 + +BOOST_PYTHON_DECL int exec_module(PyObject*, void(*)()); + +# endif + #else BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); @@ -115,6 +121,46 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); void BOOST_PP_CAT(init_module_, name)() # endif // HAS_CXX11 +# if PY_VERSION_HEX >= 0x03050000 + +# define _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) \ + int BOOST_PP_CAT(exec_module_,name)(PyObject* module) \ + { \ + return boost::python::detail::exec_module( \ + module, BOOST_PP_CAT(init_module_, name) ); \ + } \ + extern "C" BOOST_SYMBOL_EXPORT PyObject* BOOST_PP_CAT(PyInit_, name)() \ + { \ + static PyModuleDef_Base initial_m_base = { \ + PyObject_HEAD_INIT(NULL) \ + 0, /* m_init */ \ + 0, /* m_index */ \ + 0 /* m_copy */ }; \ + static PyMethodDef initial_methods[] = { { 0, 0, 0, 0 } }; \ + \ + static PyModuleDef_Slot slots[] = { \ + {Py_mod_exec, reinterpret_cast(reinterpret_cast(BOOST_PP_CAT(exec_module_, name)))}, \ + {0, NULL} \ + }; \ + \ + static struct PyModuleDef moduledef = { \ + initial_m_base, \ + BOOST_PP_STRINGIZE(name), \ + 0, /* m_doc */ \ + 0, /* m_size */ \ + initial_methods, \ + slots, /* m_slots */ \ + 0, /* m_traverse */ \ + 0, /* m_clear */ \ + 0, /* m_free */ \ + }; \ + \ + return PyModuleDef_Init(&moduledef); \ + } \ + void BOOST_PP_CAT(init_module_, name)() + +# endif + # else # define _BOOST_PYTHON_MODULE_INIT(name) \ @@ -137,6 +183,14 @@ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_INIT(name, __VA_ARGS__) extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_INIT(name) # endif // HAS_CXX11 && Python 3 +# if PY_VERSION_HEX >= 0x03050000 + +# define BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) \ + void BOOST_PP_CAT(init_module_,name)(); \ +extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) + +# endif + # endif #endif // MODULE_INIT_DWA20020722_HPP diff --git a/src/module.cpp b/src/module.cpp index c32f4187b..ef83d3180 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -52,6 +52,18 @@ BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef& moduledef, init_function); } +# if PY_VERSION_HEX >= 0x03050000 + +BOOST_PYTHON_DECL int exec_module(PyObject* module, void(*init_function)()) +{ + PyObject* retval = init_module_in_scope( + module, + init_function); + return retval ? 0 : -1; +} + +# endif + #else namespace diff --git a/test/fabscript b/test/fabscript index 7cf22f9c0..362ff82d1 100644 --- a/test/fabscript +++ b/test/fabscript @@ -174,4 +174,9 @@ for t in ['numpy/dtype', tests.append(extension_test(t, numpy=True, condition=set.define.contains('HAS_NUMPY'))) +python_version_major, python_version_minor = map(int, python.instance().version.split('.')[:2]) + +tests.append(extension_test("module_multi_phase", + condition=python_version_major > 3 or (python_version_major == 3 and python_version_minor >= 5))) + default = report('report', tests, fail_on_failures=True) diff --git a/test/module_multi_phase.cpp b/test/module_multi_phase.cpp new file mode 100644 index 000000000..dcbbe7430 --- /dev/null +++ b/test/module_multi_phase.cpp @@ -0,0 +1,15 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +using namespace boost::python; + +BOOST_PYTHON_MODULE_MULTI_PHASE(module_multi_phase_ext) +{ + scope().attr("x") = "x"; +} + +#include "module_tail.cpp" diff --git a/test/module_multi_phase.py b/test/module_multi_phase.py new file mode 100644 index 000000000..138f5d982 --- /dev/null +++ b/test/module_multi_phase.py @@ -0,0 +1,23 @@ +# Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> import module_multi_phase_ext +>>> module_multi_phase_ext.x +'x' +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print("running...") + import sys + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) From 0796140961369513bdf230596861eec781867885 Mon Sep 17 00:00:00 2001 From: O01eg <397177+o01eg@users.noreply.github.com> Date: Sat, 4 Apr 2026 22:34:27 +0400 Subject: [PATCH 19/30] Fix indent and add more remarks to make it more manageable --- include/boost/python/module_init.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/boost/python/module_init.hpp b/include/boost/python/module_init.hpp index f12550b22..ba62259bf 100644 --- a/include/boost/python/module_init.hpp +++ b/include/boost/python/module_init.hpp @@ -13,7 +13,7 @@ namespace boost { namespace python { -#ifdef HAS_CXX11 +# ifdef HAS_CXX11 // Use to activate the Py_MOD_GIL_NOT_USED flag. class mod_gil_not_used { public: @@ -39,7 +39,7 @@ inline bool gil_not_used_option(F &&, O &&...o) { } } -#endif // HAS_CXX11 +# endif // HAS_CXX11 namespace detail { @@ -51,13 +51,13 @@ BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef&, void(*)(), bool gil_not_us BOOST_PYTHON_DECL int exec_module(PyObject*, void(*)()); -# endif +# endif // PY_VERSION_HEX >= 0x03050000 -#else +# else // PY_VERSION_HEX >= 0x03000000 BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); -#endif +# endif // PY_VERSION_HEX >= 0x03000000 }}} @@ -159,9 +159,9 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); } \ void BOOST_PP_CAT(init_module_, name)() -# endif +# endif // PY_VERSION_HEX >= 0x03050000 -# else +# else // ! PY_VERSION_HEX >= 0x03000000 # define _BOOST_PYTHON_MODULE_INIT(name) \ void BOOST_PP_CAT(init,name)() \ @@ -171,7 +171,7 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); } \ void BOOST_PP_CAT(init_module_,name)() -# endif +# endif // PY_VERSION_HEX >= 0x03000000 # if defined(HAS_CXX11) && (PY_VERSION_HEX >= 0x03000000) # define BOOST_PYTHON_MODULE_INIT(name, ...) \ @@ -189,8 +189,8 @@ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_INIT(name) void BOOST_PP_CAT(init_module_,name)(); \ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) -# endif +# endif // PY_VERSION_HEX >= 0x03050000 -# endif +# endif // BOOST_PYTHON_MODULE_INIT #endif // MODULE_INIT_DWA20020722_HPP From b8b00933c6cecbb47e871855ebef431524fc9869 Mon Sep 17 00:00:00 2001 From: O01eg <397177+o01eg@users.noreply.github.com> Date: Sat, 4 Apr 2026 22:51:30 +0400 Subject: [PATCH 20/30] Add mod_gil_not_used option to BOOST_PYTHON_MODULE_MULTI_PHASE_INIT --- include/boost/python/module_init.hpp | 51 +++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/include/boost/python/module_init.hpp b/include/boost/python/module_init.hpp index ba62259bf..05ead85c7 100644 --- a/include/boost/python/module_init.hpp +++ b/include/boost/python/module_init.hpp @@ -123,7 +123,8 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); # if PY_VERSION_HEX >= 0x03050000 -# define _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) \ +# if defined(HAS_CXX11) && (PY_VERSION_HEX >= 0x030D0000) +# define _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name, ...) \ int BOOST_PP_CAT(exec_module_,name)(PyObject* module) \ { \ return boost::python::detail::exec_module( \ @@ -140,6 +141,7 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); \ static PyModuleDef_Slot slots[] = { \ {Py_mod_exec, reinterpret_cast(reinterpret_cast(BOOST_PP_CAT(exec_module_, name)))}, \ + {Py_mod_gil, boost::python::detail::gil_not_used_option(__VA_ARGS__) ? Py_MOD_GIL_NOT_USED : Py_MOD_GIL_USED}, \ {0, NULL} \ }; \ \ @@ -158,6 +160,43 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); return PyModuleDef_Init(&moduledef); \ } \ void BOOST_PP_CAT(init_module_, name)() +# else // ! HAS_CXX11 && Python 3.13+ +# define _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) \ + int BOOST_PP_CAT(exec_module_,name)(PyObject* module) \ + { \ + return boost::python::detail::exec_module( \ + module, BOOST_PP_CAT(init_module_, name) ); \ + } \ + extern "C" BOOST_SYMBOL_EXPORT PyObject* BOOST_PP_CAT(PyInit_, name)() \ + { \ + static PyModuleDef_Base initial_m_base = { \ + PyObject_HEAD_INIT(NULL) \ + 0, /* m_init */ \ + 0, /* m_index */ \ + 0 /* m_copy */ }; \ + static PyMethodDef initial_methods[] = { { 0, 0, 0, 0 } }; \ + \ + static PyModuleDef_Slot slots[] = { \ + {Py_mod_exec, reinterpret_cast(reinterpret_cast(BOOST_PP_CAT(exec_module_, name)))}, \ + {0, NULL} \ + }; \ + \ + static struct PyModuleDef moduledef = { \ + initial_m_base, \ + BOOST_PP_STRINGIZE(name), \ + 0, /* m_doc */ \ + 0, /* m_size */ \ + initial_methods, \ + slots, /* m_slots */ \ + 0, /* m_traverse */ \ + 0, /* m_clear */ \ + 0, /* m_free */ \ + }; \ + \ + return PyModuleDef_Init(&moduledef); \ + } \ + void BOOST_PP_CAT(init_module_, name)() +# endif // HAS_CXX11 && Python 3.13+ # endif // PY_VERSION_HEX >= 0x03050000 @@ -184,11 +223,15 @@ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_INIT(name) # endif // HAS_CXX11 && Python 3 # if PY_VERSION_HEX >= 0x03050000 - -# define BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) \ +# if defined(HAS_CXX11) && (PY_VERSION_HEX >= 0x030D0000) +# define BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name, ...) \ + void BOOST_PP_CAT(init_module_,name)(); \ +extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name, __VA_ARGS__) +# else +# define BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) \ void BOOST_PP_CAT(init_module_,name)(); \ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) - +# endif // HAS_CXX11 && Python 3.13+ # endif // PY_VERSION_HEX >= 0x03050000 # endif // BOOST_PYTHON_MODULE_INIT From b34c8953a6543c50ad2ce5dd9e1cb01d3dea6c0c Mon Sep 17 00:00:00 2001 From: O01eg <397177+o01eg@users.noreply.github.com> Date: Sat, 4 Apr 2026 22:53:54 +0400 Subject: [PATCH 21/30] Rename module to mod --- include/boost/python/module_init.hpp | 8 ++++---- src/module.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/boost/python/module_init.hpp b/include/boost/python/module_init.hpp index 05ead85c7..0d826be65 100644 --- a/include/boost/python/module_init.hpp +++ b/include/boost/python/module_init.hpp @@ -125,10 +125,10 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); # if defined(HAS_CXX11) && (PY_VERSION_HEX >= 0x030D0000) # define _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name, ...) \ - int BOOST_PP_CAT(exec_module_,name)(PyObject* module) \ + int BOOST_PP_CAT(exec_module_,name)(PyObject* mod) \ { \ return boost::python::detail::exec_module( \ - module, BOOST_PP_CAT(init_module_, name) ); \ + mod, BOOST_PP_CAT(init_module_, name) ); \ } \ extern "C" BOOST_SYMBOL_EXPORT PyObject* BOOST_PP_CAT(PyInit_, name)() \ { \ @@ -162,10 +162,10 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); void BOOST_PP_CAT(init_module_, name)() # else // ! HAS_CXX11 && Python 3.13+ # define _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) \ - int BOOST_PP_CAT(exec_module_,name)(PyObject* module) \ + int BOOST_PP_CAT(exec_module_,name)(PyObject* mod) \ { \ return boost::python::detail::exec_module( \ - module, BOOST_PP_CAT(init_module_, name) ); \ + mod, BOOST_PP_CAT(init_module_, name) ); \ } \ extern "C" BOOST_SYMBOL_EXPORT PyObject* BOOST_PP_CAT(PyInit_, name)() \ { \ diff --git a/src/module.cpp b/src/module.cpp index ef83d3180..22c4c5868 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -54,10 +54,10 @@ BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef& moduledef, # if PY_VERSION_HEX >= 0x03050000 -BOOST_PYTHON_DECL int exec_module(PyObject* module, void(*init_function)()) +BOOST_PYTHON_DECL int exec_module(PyObject* mod, void(*init_function)()) { PyObject* retval = init_module_in_scope( - module, + mod, init_function); return retval ? 0 : -1; } From 97a623d3ed1b62605d3b8d57d3b5e6bde237f0f1 Mon Sep 17 00:00:00 2001 From: O01eg <397177+o01eg@users.noreply.github.com> Date: Sat, 4 Apr 2026 23:12:47 +0400 Subject: [PATCH 22/30] Add tests --- test/fabscript | 2 ++ test/module_multi_phase_nogil.cpp | 25 +++++++++++++++++++++++++ test/module_multi_phase_nogil.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 test/module_multi_phase_nogil.cpp create mode 100644 test/module_multi_phase_nogil.py diff --git a/test/fabscript b/test/fabscript index 362ff82d1..f418ed3ef 100644 --- a/test/fabscript +++ b/test/fabscript @@ -178,5 +178,7 @@ python_version_major, python_version_minor = map(int, python.instance().version. tests.append(extension_test("module_multi_phase", condition=python_version_major > 3 or (python_version_major == 3 and python_version_minor >= 5))) +tests.append(extension_test("module_multi_phase_nogil", + condition=python_version_major > 3 or (python_version_major == 3 and python_version_minor >= 5))) default = report('report', tests, fail_on_failures=True) diff --git a/test/module_multi_phase_nogil.cpp b/test/module_multi_phase_nogil.cpp new file mode 100644 index 000000000..6de74c29d --- /dev/null +++ b/test/module_multi_phase_nogil.cpp @@ -0,0 +1,25 @@ +// Test for BOOST_PYTHON_MODULE_MULTI_PHASE with optional mod_gil_not_used argument + +#include +#include + +// Simple function to export +int get_value() { + return 1234; +} + +#if defined(HAS_CXX11) && (PY_VERSION_HEX >= 0x030D0000) +// C++11 build with Python 3.13+: test with mod_gil_not_used option +BOOST_PYTHON_MODULE_MULTI_PHASE(module_multi_phase_nogil_ext, boost::python::mod_gil_not_used()) +{ + using namespace boost::python; + def("get_value", get_value); +} +#else +// C++98 build or Python 3.12-: test without optional arguments +BOOST_PYTHON_MODULE_MULTI_PHASE(module_multi_phase_nogil_ext) +{ + using namespace boost::python; + def("get_value", get_value); +} +#endif diff --git a/test/module_multi_phase_nogil.py b/test/module_multi_phase_nogil.py new file mode 100644 index 000000000..30c6bcb98 --- /dev/null +++ b/test/module_multi_phase_nogil.py @@ -0,0 +1,29 @@ +""" +>>> from module_multi_phase_nogil_ext import * +>>> get_value() +1234 +>>> import sys, sysconfig +>>> Py_GIL_DISABLED = bool(sysconfig.get_config_var('Py_GIL_DISABLED')) +>>> if Py_GIL_DISABLED and sys._is_gil_enabled(): +... print('GIL is enabled and should not be') +... else: +... print('okay') +okay +""" + +from __future__ import print_function + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print("running...") + import sys + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) From d018bb17d4083565a23b14ad254d1b92353b804c Mon Sep 17 00:00:00 2001 From: O01eg <397177+o01eg@users.noreply.github.com> Date: Fri, 26 Jun 2026 08:12:02 +0400 Subject: [PATCH 23/30] Add POD state for multi-phase modules --- include/boost/python/module.hpp | 1 + include/boost/python/module_init.hpp | 86 ++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/include/boost/python/module.hpp b/include/boost/python/module.hpp index f6f9fa871..4ec34868b 100644 --- a/include/boost/python/module.hpp +++ b/include/boost/python/module.hpp @@ -11,6 +11,7 @@ # define BOOST_PYTHON_MODULE BOOST_PYTHON_MODULE_INIT # if PY_VERSION_HEX >= 0x03050000 # define BOOST_PYTHON_MODULE_MULTI_PHASE BOOST_PYTHON_MODULE_MULTI_PHASE_INIT +# define BOOST_PYTHON_MODULE_WITH_STATE BOOST_PYTHON_MODULE_WITH_STATE_INIT # endif #endif // MODULE_DWA20011221_HPP diff --git a/include/boost/python/module_init.hpp b/include/boost/python/module_init.hpp index 0d826be65..910421d4e 100644 --- a/include/boost/python/module_init.hpp +++ b/include/boost/python/module_init.hpp @@ -9,6 +9,11 @@ # include # include +# if PY_VERSION_HEX >= 0x03050000 +# include +# include +# endif + # ifndef BOOST_PYTHON_MODULE_INIT namespace boost { namespace python { @@ -160,6 +165,44 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); return PyModuleDef_Init(&moduledef); \ } \ void BOOST_PP_CAT(init_module_, name)() +# define _BOOST_PYTHON_MODULE_WITH_STATE_INIT(name, StateType, ...) \ + int BOOST_PP_CAT(exec_module_,name)(PyObject* mod) \ + { \ + return boost::python::detail::exec_module( \ + mod, BOOST_PP_CAT(init_module_, name) ); \ + } \ + extern "C" BOOST_SYMBOL_EXPORT PyObject* BOOST_PP_CAT(PyInit_, name)() \ + { \ + BOOST_STATIC_ASSERT_MSG(boost::is_pod::value, \ + "Module State MUST be a plain POD structure!"); \ + static PyModuleDef_Base initial_m_base = { \ + PyObject_HEAD_INIT(NULL) \ + 0, /* m_init */ \ + 0, /* m_index */ \ + 0 /* m_copy */ }; \ + static PyMethodDef initial_methods[] = { { 0, 0, 0, 0 } }; \ + \ + static PyModuleDef_Slot slots[] = { \ + {Py_mod_exec, reinterpret_cast(reinterpret_cast(BOOST_PP_CAT(exec_module_, name)))}, \ + {Py_mod_gil, boost::python::detail::gil_not_used_option(__VA_ARGS__) ? Py_MOD_GIL_NOT_USED : Py_MOD_GIL_USED}, \ + {0, NULL} \ + }; \ + \ + static struct PyModuleDef moduledef = { \ + initial_m_base, \ + BOOST_PP_STRINGIZE(name), \ + 0, /* m_doc */ \ + sizeof(StateType), /* m_size */ \ + initial_methods, \ + slots, /* m_slots */ \ + 0, /* m_traverse */ \ + 0, /* m_clear */ \ + 0, /* m_free */ \ + }; \ + \ + return PyModuleDef_Init(&moduledef); \ + } \ + void BOOST_PP_CAT(init_module_, name)() # else // ! HAS_CXX11 && Python 3.13+ # define _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) \ int BOOST_PP_CAT(exec_module_,name)(PyObject* mod) \ @@ -196,6 +239,43 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); return PyModuleDef_Init(&moduledef); \ } \ void BOOST_PP_CAT(init_module_, name)() +# define _BOOST_PYTHON_MODULE_WITH_STATE_INIT(name, StateType) \ + int BOOST_PP_CAT(exec_module_,name)(PyObject* mod) \ + { \ + return boost::python::detail::exec_module( \ + mod, BOOST_PP_CAT(init_module_, name) ); \ + } \ + extern "C" BOOST_SYMBOL_EXPORT PyObject* BOOST_PP_CAT(PyInit_, name)() \ + { \ + BOOST_STATIC_ASSERT_MSG(boost::is_pod::value, \ + "Module State MUST be a plain POD structure!"); \ + static PyModuleDef_Base initial_m_base = { \ + PyObject_HEAD_INIT(NULL) \ + 0, /* m_init */ \ + 0, /* m_index */ \ + 0 /* m_copy */ }; \ + static PyMethodDef initial_methods[] = { { 0, 0, 0, 0 } }; \ + \ + static PyModuleDef_Slot slots[] = { \ + {Py_mod_exec, reinterpret_cast(reinterpret_cast(BOOST_PP_CAT(exec_module_, name)))}, \ + {0, NULL} \ + }; \ + \ + static struct PyModuleDef moduledef = { \ + initial_m_base, \ + BOOST_PP_STRINGIZE(name), \ + 0, /* m_doc */ \ + sizeof(StateType), /* m_size */ \ + initial_methods, \ + slots, /* m_slots */ \ + 0, /* m_traverse */ \ + 0, /* m_clear */ \ + 0, /* m_free */ \ + }; \ + \ + return PyModuleDef_Init(&moduledef); \ + } \ + void BOOST_PP_CAT(init_module_, name)() # endif // HAS_CXX11 && Python 3.13+ # endif // PY_VERSION_HEX >= 0x03050000 @@ -227,10 +307,16 @@ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_INIT(name) # define BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name, ...) \ void BOOST_PP_CAT(init_module_,name)(); \ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name, __VA_ARGS__) +# define BOOST_PYTHON_MODULE_WITH_STATE_INIT(name, StateType, ...) \ + void BOOST_PP_CAT(init_module_,name)(); \ +extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_WITH_STATE_INIT(name, StateType, __VA_ARGS__) # else # define BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) \ void BOOST_PP_CAT(init_module_,name)(); \ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) +# define BOOST_PYTHON_MODULE_WITH_STATE_INIT(name, StateType) \ + void BOOST_PP_CAT(init_module_,name)(); \ +extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_WITH_STATE_INIT(name) # endif // HAS_CXX11 && Python 3.13+ # endif // PY_VERSION_HEX >= 0x03050000 From afd27c63d5b7e261cfe0ef2bc45414d65b2ad81d Mon Sep 17 00:00:00 2001 From: O01eg <397177+o01eg@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:09:01 +0400 Subject: [PATCH 24/30] Provide 'state' accessor in module definition --- include/boost/python/module_init.hpp | 16 +++++++------ src/module.cpp | 36 ++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/include/boost/python/module_init.hpp b/include/boost/python/module_init.hpp index 910421d4e..0478cd9c4 100644 --- a/include/boost/python/module_init.hpp +++ b/include/boost/python/module_init.hpp @@ -56,6 +56,8 @@ BOOST_PYTHON_DECL PyObject* init_module(PyModuleDef&, void(*)(), bool gil_not_us BOOST_PYTHON_DECL int exec_module(PyObject*, void(*)()); +BOOST_PYTHON_DECL int exec_module_with_state(PyObject*, void(*)(void*)); + # endif // PY_VERSION_HEX >= 0x03050000 # else // PY_VERSION_HEX >= 0x03000000 @@ -169,7 +171,7 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); int BOOST_PP_CAT(exec_module_,name)(PyObject* mod) \ { \ return boost::python::detail::exec_module( \ - mod, BOOST_PP_CAT(init_module_, name) ); \ + mod, reinterpret_cast(BOOST_PP_CAT(init_module_, name)) ); \ } \ extern "C" BOOST_SYMBOL_EXPORT PyObject* BOOST_PP_CAT(PyInit_, name)() \ { \ @@ -202,7 +204,7 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); \ return PyModuleDef_Init(&moduledef); \ } \ - void BOOST_PP_CAT(init_module_, name)() + void BOOST_PP_CAT(init_module_, name)(StateType* state) # else // ! HAS_CXX11 && Python 3.13+ # define _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) \ int BOOST_PP_CAT(exec_module_,name)(PyObject* mod) \ @@ -243,7 +245,7 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); int BOOST_PP_CAT(exec_module_,name)(PyObject* mod) \ { \ return boost::python::detail::exec_module( \ - mod, BOOST_PP_CAT(init_module_, name) ); \ + mod, reinterpret_cast(BOOST_PP_CAT(init_module_, name)) ); \ } \ extern "C" BOOST_SYMBOL_EXPORT PyObject* BOOST_PP_CAT(PyInit_, name)() \ { \ @@ -275,7 +277,7 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); \ return PyModuleDef_Init(&moduledef); \ } \ - void BOOST_PP_CAT(init_module_, name)() + void BOOST_PP_CAT(init_module_, name)(StateType* state) # endif // HAS_CXX11 && Python 3.13+ # endif // PY_VERSION_HEX >= 0x03050000 @@ -308,15 +310,15 @@ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_INIT(name) void BOOST_PP_CAT(init_module_,name)(); \ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name, __VA_ARGS__) # define BOOST_PYTHON_MODULE_WITH_STATE_INIT(name, StateType, ...) \ - void BOOST_PP_CAT(init_module_,name)(); \ + void BOOST_PP_CAT(init_module_,name)(StateType* state); \ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_WITH_STATE_INIT(name, StateType, __VA_ARGS__) # else # define BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) \ void BOOST_PP_CAT(init_module_,name)(); \ extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_MULTI_PHASE_INIT(name) # define BOOST_PYTHON_MODULE_WITH_STATE_INIT(name, StateType) \ - void BOOST_PP_CAT(init_module_,name)(); \ -extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_WITH_STATE_INIT(name) + void BOOST_PP_CAT(init_module_,name)(StateType* state); \ +extern "C" BOOST_SYMBOL_EXPORT _BOOST_PYTHON_MODULE_WITH_STATE_INIT(name, StateType) # endif // HAS_CXX11 && Python 3.13+ # endif // PY_VERSION_HEX >= 0x03050000 diff --git a/src/module.cpp b/src/module.cpp index 22c4c5868..200b0bb78 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -26,6 +26,34 @@ namespace return m; } +# if PY_VERSION_HEX >= 0x03050000 + class init_function_with_state { + public: + init_function_with_state(void(*init_function)(void*), void* state) + : init_function_(init_function), state_(state) {} + + void operator()() const { init_function_(state_); } + private: + void(*const init_function_)(void*); + void* const state_; + }; + + PyObject* init_module_in_scope_with_state(PyObject* m, void(*init_function)(void*)) + { + if (m != 0) + { + // Create the current module scope + object m_obj(((borrowed_reference_t*)m)); + scope current_module(m_obj); + + void* state = PyModule_GetState(m); + + if (handle_exception(init_function_with_state(init_function, state))) return NULL; + } + + return m; + } +# endif } BOOST_PYTHON_DECL void scope_setattr_doc(char const* name, object const& x, char const* doc) @@ -62,6 +90,14 @@ BOOST_PYTHON_DECL int exec_module(PyObject* mod, void(*init_function)()) return retval ? 0 : -1; } +BOOST_PYTHON_DECL int exec_module_with_state(PyObject* mod, void(*init_function)(void*)) +{ + PyObject* retval = init_module_in_scope_with_state( + mod, + init_function); + return retval ? 0 : -1; +} + # endif #else From c86ea207d1a7eb84c34f7b606e62a7a22b43538d Mon Sep 17 00:00:00 2001 From: O01eg <397177+o01eg@users.noreply.github.com> Date: Sat, 27 Jun 2026 00:16:21 +0400 Subject: [PATCH 25/30] Fix and add tests for module state --- include/boost/python/module_init.hpp | 4 ++-- test/fabscript | 2 ++ test/module_multi_phase_state.cpp | 30 ++++++++++++++++++++++++++++ test/module_multi_phase_state.py | 23 +++++++++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 test/module_multi_phase_state.cpp create mode 100644 test/module_multi_phase_state.py diff --git a/include/boost/python/module_init.hpp b/include/boost/python/module_init.hpp index 0478cd9c4..abf1ce252 100644 --- a/include/boost/python/module_init.hpp +++ b/include/boost/python/module_init.hpp @@ -170,7 +170,7 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); # define _BOOST_PYTHON_MODULE_WITH_STATE_INIT(name, StateType, ...) \ int BOOST_PP_CAT(exec_module_,name)(PyObject* mod) \ { \ - return boost::python::detail::exec_module( \ + return boost::python::detail::exec_module_with_state( \ mod, reinterpret_cast(BOOST_PP_CAT(init_module_, name)) ); \ } \ extern "C" BOOST_SYMBOL_EXPORT PyObject* BOOST_PP_CAT(PyInit_, name)() \ @@ -244,7 +244,7 @@ BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); # define _BOOST_PYTHON_MODULE_WITH_STATE_INIT(name, StateType) \ int BOOST_PP_CAT(exec_module_,name)(PyObject* mod) \ { \ - return boost::python::detail::exec_module( \ + return boost::python::detail::exec_module_with_state( \ mod, reinterpret_cast(BOOST_PP_CAT(init_module_, name)) ); \ } \ extern "C" BOOST_SYMBOL_EXPORT PyObject* BOOST_PP_CAT(PyInit_, name)() \ diff --git a/test/fabscript b/test/fabscript index f418ed3ef..c6d834aa0 100644 --- a/test/fabscript +++ b/test/fabscript @@ -180,5 +180,7 @@ tests.append(extension_test("module_multi_phase", condition=python_version_major > 3 or (python_version_major == 3 and python_version_minor >= 5))) tests.append(extension_test("module_multi_phase_nogil", condition=python_version_major > 3 or (python_version_major == 3 and python_version_minor >= 5))) +tests.append(extension_test("module_multi_phase_state", + condition=python_version_major > 3 or (python_version_major == 3 and python_version_minor >= 5))) default = report('report', tests, fail_on_failures=True) diff --git a/test/module_multi_phase_state.cpp b/test/module_multi_phase_state.cpp new file mode 100644 index 000000000..0e497fc9c --- /dev/null +++ b/test/module_multi_phase_state.cpp @@ -0,0 +1,30 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +using namespace boost::python; + +struct TestState +{ + int x; +}; + +int get_state_x() { + TestState* state = reinterpret_cast(PyModule_GetState(import("module_multi_phase_state_ext").ptr())); + if (state != nullptr) { + return state->x; + } + return -1; +} + +BOOST_PYTHON_MODULE_WITH_STATE(module_multi_phase_state_ext, TestState) +{ + state->x = 42; + def("x", get_state_x); +} + +#include "module_tail.cpp" diff --git a/test/module_multi_phase_state.py b/test/module_multi_phase_state.py new file mode 100644 index 000000000..1df4b9623 --- /dev/null +++ b/test/module_multi_phase_state.py @@ -0,0 +1,23 @@ +# Distributed under the Boost +# Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> import module_multi_phase_state_ext +>>> module_multi_phase_state_ext.x() +42 +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print("running...") + import sys + status = run()[0] + if (status == 0): print("Done.") + sys.exit(status) From e08584a4ed0f87b3f2d6b590c3198a5df66f07c3 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Sun, 5 Apr 2026 17:36:56 +0900 Subject: [PATCH 26/30] feat(vector_indexing_suite): implement __iadd__ --- .../boost/python/suite/indexing/vector_indexing_suite.hpp | 8 ++++++++ test/vector_indexing_suite.py | 3 +++ 2 files changed, 11 insertions(+) diff --git a/include/boost/python/suite/indexing/vector_indexing_suite.hpp b/include/boost/python/suite/indexing/vector_indexing_suite.hpp index 34c29ecc6..6ca31896a 100644 --- a/include/boost/python/suite/indexing/vector_indexing_suite.hpp +++ b/include/boost/python/suite/indexing/vector_indexing_suite.hpp @@ -61,6 +61,7 @@ namespace boost { namespace python { extension_def(Class& cl) { cl + .def("__iadd__", &base_iadd) .def("append", &base_append) .def("extend", &base_extend) ; @@ -235,6 +236,13 @@ namespace boost { namespace python { container_utils::extend_container(temp, v); DerivedPolicies::extend(container, temp.begin(), temp.end()); } + + static object + base_iadd(Container& container, object v) + { + base_extend(container, v); + return object(container); + } }; }} // namespace boost::python diff --git a/test/vector_indexing_suite.py b/test/vector_indexing_suite.py index 478cd0151..5e5e8f7a3 100644 --- a/test/vector_indexing_suite.py +++ b/test/vector_indexing_suite.py @@ -320,6 +320,9 @@ >>> v.extend(['f','g','h','i','j']) >>> print_xvec(v) [ a b c d e f g h i j ] +>>> v += ['k','l','m'] +>>> print_xvec(v) +[ a b c d e f g h i j k l m ] ##################################################################### # extend using a generator expression From d8668c5963fc085076828b77bfda75a52eb72289 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Sun, 5 Apr 2026 16:20:09 +0900 Subject: [PATCH 27/30] feat(indexing_suite): implement clear --- include/boost/python/suite/indexing/indexing_suite.hpp | 7 +++++++ include/boost/python/suite/indexing/map_indexing_suite.hpp | 6 ++++++ .../boost/python/suite/indexing/vector_indexing_suite.hpp | 6 ++++++ test/map_indexing_suite.py | 4 ++++ test/vector_indexing_suite.py | 4 ++++ 5 files changed, 27 insertions(+) diff --git a/include/boost/python/suite/indexing/indexing_suite.hpp b/include/boost/python/suite/indexing/indexing_suite.hpp index 3469a2a40..140e3a665 100644 --- a/include/boost/python/suite/indexing/indexing_suite.hpp +++ b/include/boost/python/suite/indexing/indexing_suite.hpp @@ -184,6 +184,7 @@ namespace boost { namespace python { .def("__getitem__", &base_get_item) .def("__contains__", &base_contains) .def("__iter__", def_iterator()) + .def("clear", &base_clear) ; DerivedPolicies::extension_def(cl); @@ -288,6 +289,12 @@ namespace boost { namespace python { return false; } } + + static void + base_clear(Container& container) + { + return DerivedPolicies::clear(container); + } }; }} // namespace boost::python diff --git a/include/boost/python/suite/indexing/map_indexing_suite.hpp b/include/boost/python/suite/indexing/map_indexing_suite.hpp index 7fbad4cac..567abe4e7 100644 --- a/include/boost/python/suite/indexing/map_indexing_suite.hpp +++ b/include/boost/python/suite/indexing/map_indexing_suite.hpp @@ -137,6 +137,12 @@ namespace boost { namespace python { container.erase(i); } + static void + clear(Container& container) + { + container.clear(); + } + static size_t size(Container& container) { diff --git a/include/boost/python/suite/indexing/vector_indexing_suite.hpp b/include/boost/python/suite/indexing/vector_indexing_suite.hpp index 6ca31896a..264eac013 100644 --- a/include/boost/python/suite/indexing/vector_indexing_suite.hpp +++ b/include/boost/python/suite/indexing/vector_indexing_suite.hpp @@ -135,6 +135,12 @@ namespace boost { namespace python { container.erase(container.begin()+from, container.begin()+to); } + static void + clear(Container& container) + { + container.clear(); + } + static size_t size(Container& container) { diff --git a/test/map_indexing_suite.py b/test/map_indexing_suite.py index 6d3e57a10..939d984c7 100644 --- a/test/map_indexing_suite.py +++ b/test/map_indexing_suite.py @@ -202,6 +202,10 @@ ... dom = el.data() joel kimpo +>>> tm.clear() +>>> print_xmap(tm) +[ ] + ##################################################################### # Test custom converter... ##################################################################### diff --git a/test/vector_indexing_suite.py b/test/vector_indexing_suite.py index 5e5e8f7a3..24d1caba4 100644 --- a/test/vector_indexing_suite.py +++ b/test/vector_indexing_suite.py @@ -337,6 +337,10 @@ >>> print_xvec(v) [ a b c d e f h i j ] +>>> v.clear() +>>> print_xvec(v) +[ ] + ##################################################################### # vector of strings ##################################################################### From 27ff6f6f37775792e98dcfd5a87258fc106e536c Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Sun, 5 Apr 2026 16:13:45 +0900 Subject: [PATCH 28/30] feat(vector_indexing_suite): implement count --- .../suite/indexing/vector_indexing_suite.hpp | 16 ++++++++++++++++ test/vector_indexing_suite.py | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/include/boost/python/suite/indexing/vector_indexing_suite.hpp b/include/boost/python/suite/indexing/vector_indexing_suite.hpp index 264eac013..7cbdd2c6e 100644 --- a/include/boost/python/suite/indexing/vector_indexing_suite.hpp +++ b/include/boost/python/suite/indexing/vector_indexing_suite.hpp @@ -63,6 +63,7 @@ namespace boost { namespace python { cl .def("__iadd__", &base_iadd) .def("append", &base_append) + .def("count", &base_count) .def("extend", &base_extend) ; } @@ -208,6 +209,21 @@ namespace boost { namespace python { } private: + + static size_t + base_count(Container& container, object v) + { + extract elem(v); + if (elem.check()) { + return std::count(container.begin(), container.end(), elem()); + } else { + extract elem(v); + if (!elem.check()) { + return 0; + } + return std::count(container.begin(), container.end(), elem()); + } + } static void base_append(Container& container, object v) diff --git a/test/vector_indexing_suite.py b/test/vector_indexing_suite.py index 24d1caba4..6abca6140 100644 --- a/test/vector_indexing_suite.py +++ b/test/vector_indexing_suite.py @@ -297,6 +297,13 @@ >>> assert not 12345 in v ##################################################################### +# Count +##################################################################### +>>> v.count('a') +1 +>>> v.count(12345) +0 + # Show that iteration allows mutable access to the elements ##################################################################### >>> v[:] = ['a','b','c','d','e'] # reset again From 660e8944ffcfd02890e3cfdff4c168219f65a495 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Sun, 5 Apr 2026 17:50:35 +0900 Subject: [PATCH 29/30] feat(vector_indexing_suite): implement remove --- .../suite/indexing/vector_indexing_suite.hpp | 37 +++++++++++++++++++ test/vector_indexing_suite.py | 8 ++++ 2 files changed, 45 insertions(+) diff --git a/include/boost/python/suite/indexing/vector_indexing_suite.hpp b/include/boost/python/suite/indexing/vector_indexing_suite.hpp index 7cbdd2c6e..fd5d86c40 100644 --- a/include/boost/python/suite/indexing/vector_indexing_suite.hpp +++ b/include/boost/python/suite/indexing/vector_indexing_suite.hpp @@ -65,6 +65,7 @@ namespace boost { namespace python { .def("append", &base_append) .def("count", &base_count) .def("extend", &base_extend) + .def("remove", &base_remove) ; } @@ -265,6 +266,42 @@ namespace boost { namespace python { base_extend(container, v); return object(container); } + + static void + base_remove(Container& container, object v) + { + extract key(v); + if (key.check()) + { + auto i = std::find(container.begin(), container.end(), key()); + if (i == container.end()) + { + PyErr_SetString(PyExc_ValueError, "remove(x): x not in vector_indexing_suite"); + throw_error_already_set(); + } + container.erase(i); + } + else + { + extract key(v); + if (key.check()) + { + auto i = std::find(container.begin(), container.end(), key()); + if (i == container.end()) + { + PyErr_SetString(PyExc_ValueError, "remove(x): x not in vector_indexing_suite"); + throw_error_already_set(); + } + container.erase(i); + } + else + { + PyErr_SetString(PyExc_TypeError, + "Attempting to remove an invalid type"); + throw_error_already_set(); + } + } + } }; }} // namespace boost::python diff --git a/test/vector_indexing_suite.py b/test/vector_indexing_suite.py index 6abca6140..c0b72c6ab 100644 --- a/test/vector_indexing_suite.py +++ b/test/vector_indexing_suite.py @@ -78,6 +78,14 @@ >>> print_xvec(v) [ yaba c d e ] +>>> v2 = XVec() +>>> v2[:] = [X('b'), X('a'), X('c'), X('b'), X('a')] +>>> try: v2.remove("z") +... except ValueError: pass +>>> v2.remove("a") +>>> print_xvec(v2) +[ b c b a ] + ##################################################################### # Calling a mutating function of a container element ##################################################################### From fe087f9c2ff586d9b105c3c4507e2d913238a106 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Sun, 5 Apr 2026 16:29:32 +0900 Subject: [PATCH 30/30] feat(vector_indexing_suite): implement reverse --- .../python/suite/indexing/vector_indexing_suite.hpp | 10 ++++++++++ test/vector_indexing_suite.py | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/include/boost/python/suite/indexing/vector_indexing_suite.hpp b/include/boost/python/suite/indexing/vector_indexing_suite.hpp index fd5d86c40..f1b27c738 100644 --- a/include/boost/python/suite/indexing/vector_indexing_suite.hpp +++ b/include/boost/python/suite/indexing/vector_indexing_suite.hpp @@ -66,6 +66,7 @@ namespace boost { namespace python { .def("count", &base_count) .def("extend", &base_extend) .def("remove", &base_remove) + .def("reverse", &base_reverse) ; } @@ -302,6 +303,15 @@ namespace boost { namespace python { } } } + + static void + base_reverse(Container& container) + { + using std::swap; + const unsigned n = size(container); + for (unsigned i = 0; i < n / 2; i++) + swap(container[i], container[n - i - 1]); + } }; }} // namespace boost::python diff --git a/test/vector_indexing_suite.py b/test/vector_indexing_suite.py index c0b72c6ab..fb2b92a1e 100644 --- a/test/vector_indexing_suite.py +++ b/test/vector_indexing_suite.py @@ -312,6 +312,14 @@ >>> v.count(12345) 0 +##################################################################### +# Reverse +##################################################################### +>>> v.reverse() +>>> print_xvec(v) +[ e d c b a ] + +##################################################################### # Show that iteration allows mutable access to the elements ##################################################################### >>> v[:] = ['a','b','c','d','e'] # reset again