From 9a04426b4ed9ad21b8bf7fb514742cd81fb35402 Mon Sep 17 00:00:00 2001 From: Marcelo Duarte Date: Wed, 30 Sep 2026 22:29:22 -0300 Subject: [PATCH] ci: always run codeql when using a new 'skip tests' comment instead of 'skip ci' --- .github/workflows/ci.yml | 5 +- .github/workflows/codeql.yml | 44 +------ .github/workflows/dependency-review.yml | 11 +- .github/workflows/scorecards.yml | 9 +- .pre-commit-config.yaml | 14 +- ci/build-wheel.sh | 68 +++++++--- ci/bump-version.sh | 8 +- ci/install-tools.sh | 26 +++- pyproject.toml | 6 +- requirements-dev.txt | 4 +- src/msilib/include/pythoncapi_compat.h | 168 ++++-------------------- 11 files changed, 137 insertions(+), 226 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1fca9c..b66a071 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,9 @@ permissions: jobs: pre_commit: name: Pre commit + if: | + contains(github.event.pull_request.title, '[skip tests]') == false && + contains(github.event.head_commit.message, '[skip tests]') == false permissions: contents: write # Required for pre-commit-ci lite id-token: write # Required for pre-commit-ci lite @@ -78,7 +81,7 @@ jobs: build_wheel: name: Build wheels - uses: ./.github/workflows/build.yml + uses: $/.github/workflows/build.yml needs: - pre_commit - type_check diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a5a5d13..fcdc1a1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,22 +1,13 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: CodeQL on: push: - branches: ["main"] + branches: + - main pull_request: # The branches below must be a subset of the branches above - branches: ["main"] + branches: + - main schedule: - cron: "0 0 * * 1" @@ -24,15 +15,13 @@ concurrency: group: sec-${{ github.ref }} cancel-in-progress: false -permissions: - contents: read +permissions: {} jobs: analyze: name: Analyze - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: - actions: read # MANDATORY contents: read security-events: write # Needed to upload the results to code-scanning dashboard. @@ -40,8 +29,6 @@ jobs: fail-fast: false matrix: language: ["python"] - # CodeQL supports [ $supported-codeql-languages ] - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: - name: Harden the runner (Audit all outbound calls) @@ -58,25 +45,8 @@ jobs: - name: Initialize CodeQL uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 with: + build-mode: none languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index f30f3c1..48c80ba 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -1,13 +1,16 @@ # Dependency Review Action # -# This Action will scan dependency manifest files that change as part of a Pull Request, -# surfacing known-vulnerable versions of the packages declared or updated in the PR. +# This Action will scan dependency manifest files that change as part of a +# Pull Request, surfacing known-vulnerable versions of the packages declared +# or updated in the PR. # Once installed, if the workflow run is marked as required, # PRs introducing known-vulnerable packages will be blocked from merging. # # Source repository: https://github.com/actions/dependency-review-action + name: Dependency Review -on: [pull_request] +on: + pull_request: concurrency: group: sec-${{ github.ref }} @@ -19,7 +22,7 @@ permissions: jobs: dependency-review: name: Dependency Review - runs-on: ubuntu-latest + runs-on: ubuntu-slim steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 86cf62a..660ccab 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -1,6 +1,6 @@ -# This workflow uses actions that are not certified by GitHub. They are provided -# by a third-party and are governed by separate terms of service, privacy -# policy, and support documentation. +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by separate terms of +# service, privacy policy, and support documentation. name: Scorecard supply-chain security on: @@ -12,7 +12,8 @@ on: schedule: - cron: "20 7 * * 2" push: - branches: ["main"] + branches: + - main concurrency: group: sec-${{ github.ref }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 04a774f..e440121 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,10 +23,10 @@ repos: hooks: - id: validate-pyproject additional_dependencies: - - validate-pyproject-schema-store[all]==2026.8.15 + - validate-pyproject-schema-store[all]==2026.09.30 - repo: https://github.com/astral-sh/ruff-pre-commit - rev: aab412d509121cb5f7533134b7e67f9fab59c682 # frozen: v0.16.4 + rev: a56c0b927e6465d37cae3e97d35d4d18ab2b96cd # frozen: v0.16.9 hooks: - id: ruff-check args: ["--fix", "--show-fixes", "--unsafe-fixes"] @@ -41,31 +41,31 @@ repos: args: ["--ignore-words-list=lief,LIEF", "-w", "--skip=*.rtf"] - repo: https://github.com/pre-commit/mirrors-clang-format - rev: f4d7745e17a28aad7eed2f4874ca8d1568c11c4c # frozen: v22.1.8 + rev: e2b496dc2bd8340c2524cb9a2d2a943cde1bb6df # frozen: v23.1.1 hooks: - id: clang-format exclude: (?x)^(src/msilib/include/pythoncapi_compat.h)$ types_or: [c, c++] - repo: https://github.com/rbubley/mirrors-prettier - rev: 0ee178619d696787ca73d210cc191d720868c631 # frozen: v3.9.6 + rev: ef4a397f916211b4a39ccf9d3d9cbb6562157251 # frozen: v3.9.9 hooks: - id: prettier types_or: [yaml, markdown, html, css, scss, javascript, json] - repo: https://github.com/shellcheck-py/shellcheck-py - rev: 745eface02aef23e168a8afb6b5737818efbea95 # frozen: v0.11.0.1 + rev: a6564f5d57444e123433a5c9af733e3975c77229 # frozen: v0.11.0.1-1 hooks: - id: shellcheck - repo: https://github.com/astral-sh/ty-pre-commit - rev: 1241d80d7f628b8b0c60540b7a8c83b947136a4f # frozen: v0.0.74 + rev: 6972e4c5a7e9f45f05a2f30b668f221f43b770c9 # frozen: v0.0.84 hooks: - id: ty args: [--no-sync] - repo: https://github.com/zizmorcore/zizmor-pre-commit - rev: 451b56af716f9f0d0c2b816503a3fd0cf8b036fa # frozen: v1.29.0 + rev: fa412071e4f5d44d44f9e365f4676f9df92456a2 # frozen: v1.30.1 hooks: - id: zizmor args: ["--fix=all", "--no-progress", "-p"] diff --git a/ci/build-wheel.sh b/ci/build-wheel.sh index 76d6667..dc24bec 100755 --- a/ci/build-wheel.sh +++ b/ci/build-wheel.sh @@ -16,7 +16,9 @@ if [ -n "$UV_PYTHON" ]; then PYTHON=$(uv python find "$UV_PYTHON") elif which python &>/dev/null; then PYTHON=python -else +fi +if [ -z "$PYTHON" ]; then + echo "Python not found!" exit 1 fi PY_PLATFORM=$($PYTHON -c "import sysconfig; print(sysconfig.get_platform(), end='')") @@ -59,6 +61,7 @@ if [ -n "$1" ] && [ "$1" == "--help" ]; then echo " TAG Force build the wheel for the given identifier." echo " [default: $BUILD_TAG_DEFAULT]" echo " --install Install after build [default on local builds]." + echo " --sdist Build a source distribution [default on Linux x64]." exit 1 fi @@ -68,6 +71,11 @@ if [ "$CI" == "true" ]; then else INSTALL="1" fi +if [ "$PY_PLATFORM" == "linux-x86_64" ]; then + BUILD_SDIST="1" +else + BUILD_SDIST="0" +fi while [ -n "$1" ]; do if [ "$1" == "--all" ]; then if [ "$ZIP_SAFE" == "true" ]; then @@ -77,6 +85,8 @@ while [ -n "$1" ]; do fi elif [ "$1" == "--install" ]; then INSTALL="1" + elif [ "$1" == "--sdist" ]; then + BUILD_SDIST="1" else BUILD_TAG="$1" fi @@ -102,7 +112,7 @@ _get_dirty () { _build_sdist () { if [ "$IS_CONDA" == "1" ] || [ "$IS_MINGW" == "1" ]; then $PYTHON -m build -n -x --sdist -o wheelhouse - elif [ "$PY_PLATFORM" == "linux-x86_64" ] || [ "$BUILD_SDIST" == "true" ]; then + elif [ "$BUILD_SDIST" == "1" ]; then uv build -p "$PY_VERSION$PY_ABI_THREAD" --sdist -o wheelhouse fi } @@ -110,26 +120,34 @@ _build_sdist () { _build_wheel () { local args read -ra args <<<"$*" + rm -f "$WHEELHOUSE/$PKG_NAME" if [ "$IS_CONDA" == "1" ] || [ "$IS_MINGW" == "1" ]; then $PYTHON -m build -n -x --wheel -o wheelhouse + if [ "$IS_CONDA" == "1" ]; then + rm -rf "$WHEELHOUSE/conda/$LOWER_NAME" + mkdir -p "$WHEELHOUSE/conda/$LOWER_NAME" + $CONDA_EXE pypi convert "$WHEELHOUSE/$PKG_NAME" \ + --output-folder "$WHEELHOUSE/conda/$LOWER_NAME/noarch" + $CONDA_EXE index "$WHEELHOUSE/conda/$LOWER_NAME" + fi else if [ "$CI" == "true" ] && [[ $PY_PLATFORM == win* ]]; then export UV_LINK_MODE=copy fi if [ "$ZIP_SAFE" == "true" ]; then - uv build -p "$PY_VERSION$PY_ABI_THREAD" --wheel -o wheelhouse - elif [[ $PY_PLATFORM == win* ]] && [[ ${args[0]} == *--only* ]]; then - uv build -p "$PY_VERSION$PY_ABI_THREAD" --wheel -o wheelhouse - elif [[ $PY_PLATFORM == macos* ]] && [[ ${args[0]} == *--only* ]]; then + UV_NO_BUILD=0 \ uv build -p "$PY_VERSION$PY_ABI_THREAD" --wheel -o wheelhouse else if ! [ "$CI" == "true" ] && which podman &>/dev/null; then export CIBW_CONTAINER_ENGINE=podman fi - if [ -f "$INSTALL_DIR/cibuildwheel" ]; then + if which uv &>/dev/null; then + uv tool run cibuildwheel "${args[@]}" + elif [ -f "$INSTALL_DIR/cibuildwheel" ]; then "$INSTALL_DIR/cibuildwheel" "${args[@]}" else - uv tool run cibuildwheel "${args[@]}" + echo "cibuildwheel not found!" + exit 1 fi fi fi @@ -154,6 +172,7 @@ else NORMALIZED_NAME=$(echo "$NAME" | tr '[:upper:]' '[:lower:]' | tr '-' '_') fi fi +LOWER_NAME=$(echo "$NORMALIZED_NAME" | tr '[:upper:]' '[:lower:]' | tr '_' '-') if [[ $VERSION == *-* ]]; then NORMALIZED_VERSION=$($PYTHON -c "print(''.join('$VERSION'.replace('-','.').rsplit('.',1)), end='')") else @@ -163,23 +182,25 @@ echo "Name: $NAME ($NORMALIZED_NAME)" echo "Version: $VERSION ($NORMALIZED_VERSION)" echo "::endgroup::" -mkdir -p wheelhouse >/dev/null +WHEELHOUSE=$PWD/wheelhouse +mkdir -p "$WHEELHOUSE" >/dev/null DIRTY=$(_get_dirty) -FILEMASK="$NORMALIZED_NAME-$NORMALIZED_VERSION" -FILEEXISTS=$(find "wheelhouse/$FILEMASK.tar.gz" 2>/dev/null || echo '') +PKG_BASENAME="$NORMALIZED_NAME-$NORMALIZED_VERSION" +FILEEXISTS=$(find "$WHEELHOUSE/$PKG_BASENAME.tar.gz" 2>/dev/null || echo '') if [ "$DIRTY" != "0" ] || [ -z "$FILEEXISTS" ]; then echo "::group::Build sdist" _build_sdist echo "::endgroup::" fi echo "::group::Build wheel(s)" +PKG_NAME=$PKG_BASENAME.whl if [ "$BUILD_TAG" == "$BUILD_TAG_DEFAULT" ]; then if [ "$ZIP_SAFE" == "true" ]; then - FILEMASK="$NORMALIZED_NAME-$NORMALIZED_VERSION-$BUILD_TAG_DEFAULT" + PKG_NAME="$PKG_BASENAME-$BUILD_TAG_DEFAULT.whl" else - FILEMASK="$NORMALIZED_NAME-$NORMALIZED_VERSION-$PYTHON_TAG-$PYTHON_TAG$PY_ABI_THREAD-$PLATFORM_TAG_MASK" + PKG_NAME="$PKG_BASENAME-$PYTHON_TAG-$PYTHON_TAG$PY_ABI_THREAD-$PLATFORM_TAG_MASK.whl" fi - FILEEXISTS=$(find "wheelhouse/$FILEMASK.whl" 2>/dev/null || echo '') + FILEEXISTS=$(find "$WHEELHOUSE/$PKG_NAME" 2>/dev/null || echo '') if [ "$DIRTY" != "0" ] || [ -z "$FILEEXISTS" ]; then _build_wheel --only "$BUILD_TAG_DEFAULT" fi @@ -192,12 +213,21 @@ echo "::endgroup::" if [ "$INSTALL" == "1" ]; then echo "::group::Install $NORMALIZED_NAME $NORMALIZED_VERSION" - if [[ $PY_PLATFORM == mingw* ]]; then - PIP_COMMAND="pip install --break-system-packages --force-reinstall" + if [ "$IS_CONDA" == "1" ]; then + PKG_CONDA="$WHEELHOUSE/conda/$LOWER_NAME/noarch/$NAME-$NORMALIZED_VERSION-pypi_0.conda" + if ! [ -f "$PKG_CONDA" ]; then + PKG_CONDA="$WHEELHOUSE/conda/$LOWER_NAME/noarch/$PKG_BASENAME-pypi_0.conda" + fi + $CONDA_EXE remove "$NORMALIZED_NAME" --force --yes || true + $CONDA_EXE install "$PKG_CONDA" --no-deps --yes else - PIP_COMMAND="uv pip install --no-build --prerelease=allow --reinstall" + if [ "$IS_MINGW" == "1" ]; then + PIP_COMMAND="pip install --break-system-packages --force-reinstall" + else + PIP_COMMAND="uv pip install --no-build --prerelease=allow --reinstall" + fi + $PIP_COMMAND "$NORMALIZED_NAME==$NORMALIZED_VERSION" -f "$WHEELHOUSE" \ + --no-deps --no-index fi - $PIP_COMMAND "$NORMALIZED_NAME==$NORMALIZED_VERSION" -f wheelhouse \ - --no-deps --no-index echo "::endgroup::" fi diff --git a/ci/bump-version.sh b/ci/bump-version.sh index 1513673..3411a44 100755 --- a/ci/bump-version.sh +++ b/ci/bump-version.sh @@ -13,7 +13,7 @@ fi # Usage _usage () { echo "Usage:" - echo "$0 " + echo "$0 " echo "Based on:" echo " https://docs.astral.sh/uv/reference/cli/#uv-version--bump" echo "Also can be used as:" @@ -27,7 +27,7 @@ fi echo "::group::Bump new version" VERSION=$(uv version --short) -if [ "$1" == "major" ] || [ "$1" == "minor" ] || [ "$1" == "patch" ]; then +if [ "$1" == "major" ] || [ "$1" == "minor" ] || [ "$1" == "patch" ] || [ "$1" == "post" ]; then uv version --no-sync --bump "$1" exit_value=$? elif [ "$1" == "stable" ]; then @@ -80,8 +80,8 @@ fi if (git branch --show-current | grep -q "main"); then git checkout -B release main fi -git commit -m "Bump version: ${VERSION} → ${NEW_VERSION} [ci skip]" -a -git log -1 +git commit -m "Bump version: ${VERSION} → ${NEW_VERSION} [skip tests]" -a +git log -1 | head -5 if ! [ "$CI" == "true" ]; then git push origin "$(git branch --show-current)" if ! (echo "$NEW_VERSION" | grep -q "\.dev"); then diff --git a/ci/install-tools.sh b/ci/install-tools.sh index 698e7c7..495a98c 100755 --- a/ci/install-tools.sh +++ b/ci/install-tools.sh @@ -65,12 +65,14 @@ done echo "::group::Install dependencies and build tools" if [ "$IS_CONDA" == "1" ]; then - # Install libmamba-solver and use it to speed up packages installation - echo "Update conda to use libmamba-solver" - $CONDA_EXE clean --index-cache --logfiles --quiet --yes - $CONDA_EXE update -n base conda --quiet --yes - $CONDA_EXE install -n base conda-libmamba-solver --quiet --yes - $CONDA_EXE config --set solver libmamba + # Cleanup + $CONDA_EXE config --remove-key solver 2>/dev/null || true + $CONDA_EXE config --remove channels conda-pypi 2>/dev/null || true + $CONDA_EXE clean --all --quiet --yes + # Install rattler-solver for faster solves + echo "Update conda to use rattler-solver with conda-pypi plugin" + $CONDA_EXE install -n base "conda>=26.5" --quiet --yes + $CONDA_EXE config --set solver rattler if ! which python &>/dev/null; then $CONDA_EXE install -c conda-forge python -S -q -y fi @@ -101,6 +103,18 @@ if [ "$IS_CONDA" == "1" ]; then done < tests/requirements.txt fi + # add setuptools + found=false + for pkg in "${pkgs[@]}"; do + if [[ $pkg == setuptools* ]]; then + found=true + break + fi + done + if [ "$found" == false ]; then + pkgs+=("setuptools") + fi + echo "Install packages" echo "${pkgs[@]}" $CONDA_EXE install -c conda-forge "${pkgs[@]}" -S -q -y diff --git a/pyproject.toml b/pyproject.toml index a665096..1f66c4e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] requires = [ - "setuptools>=83,<85", + "setuptools~=84.0", ] build-backend = "setuptools.build_meta" @@ -47,8 +47,8 @@ Documentation = "https://docs.python.org/3.12/library/msilib.html" [dependency-groups] dev = [ - "cibuildwheel>=4.2.0", - "prek>=0.4.12,<0.5.0", + "cibuildwheel>=4.2.1", + "prek>=0.5.4,<0.6.0", ] tests = [ "coverage>=7.13.0", diff --git a/requirements-dev.txt b/requirements-dev.txt index dc475a7..a682444 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,2 @@ -cibuildwheel>=4.2.0 -prek>=0.4.12,<0.5.0 +cibuildwheel>=4.2.1 +prek>=0.5.4,<0.6.0 diff --git a/src/msilib/include/pythoncapi_compat.h b/src/msilib/include/pythoncapi_compat.h index 08b6915..fa47980 100644 --- a/src/msilib/include/pythoncapi_compat.h +++ b/src/msilib/include/pythoncapi_compat.h @@ -1,4 +1,5 @@ // Header file providing new C API functions to old Python versions. +// Python 3.6 or newer is required. // // File distributed under the Zero Clause BSD (0BSD) license. // Copyright Contributors to the pythoncapi_compat project. @@ -88,27 +89,6 @@ static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) #endif -// Py_SETREF() and Py_XSETREF() were added to Python 3.5.2. -// It is excluded from the limited C API. -#if (PY_VERSION_HEX < 0x03050200 && !defined(Py_SETREF)) && !defined(Py_LIMITED_API) -#define Py_SETREF(dst, src) \ - do { \ - PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \ - PyObject *_tmp_dst = (*_tmp_dst_ptr); \ - *_tmp_dst_ptr = _PyObject_CAST(src); \ - Py_DECREF(_tmp_dst); \ - } while (0) - -#define Py_XSETREF(dst, src) \ - do { \ - PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \ - PyObject *_tmp_dst = (*_tmp_dst_ptr); \ - *_tmp_dst_ptr = _PyObject_CAST(src); \ - Py_XDECREF(_tmp_dst); \ - } while (0) -#endif - - // bpo-43753 added Py_Is(), Py_IsNone(), Py_IsTrue() and Py_IsFalse() // to Python 3.10.0b1. #if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_Is) @@ -146,7 +126,8 @@ static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) // bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1 -#if PY_VERSION_HEX < 0x030900B1 || defined(PYPY_VERSION) +// PyPy added PyFrame_GetCode() to PyPy3.12 v8.0.0 +#if PY_VERSION_HEX < 0x030900B1 || (defined(PYPY_VERSION) && PY_VERSION_HEX < 0x030C0000) static inline PyCodeObject* PyFrame_GetCode(PyFrameObject *frame) { assert(frame != _Py_NULL); @@ -186,13 +167,9 @@ static inline PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame) #if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION) static inline PyObject* PyFrame_GetLocals(PyFrameObject *frame) { -#if PY_VERSION_HEX >= 0x030400B1 if (PyFrame_FastToLocalsWithError(frame) < 0) { return NULL; } -#else - PyFrame_FastToLocals(frame); -#endif return Py_NewRef(frame->f_locals); } #endif @@ -245,22 +222,14 @@ static inline PyObject* PyFrame_GetVar(PyFrameObject *frame, PyObject *name) if (locals == NULL) { return NULL; } -#if PY_VERSION_HEX >= 0x03000000 value = PyDict_GetItemWithError(locals, name); -#else - value = _PyDict_GetItemWithError(locals, name); -#endif Py_DECREF(locals); if (value == NULL) { if (PyErr_Occurred()) { return NULL; } -#if PY_VERSION_HEX >= 0x03000000 PyErr_Format(PyExc_NameError, "variable %R does not exist", name); -#else - PyErr_SetString(PyExc_NameError, "variable does not exist"); -#endif return NULL; } return Py_NewRef(value); @@ -274,11 +243,7 @@ static inline PyObject* PyFrame_GetVarString(PyFrameObject *frame, const char *name) { PyObject *name_obj, *value; -#if PY_VERSION_HEX >= 0x03000000 name_obj = PyUnicode_FromString(name); -#else - name_obj = PyString_FromString(name); -#endif if (name_obj == NULL) { return NULL; } @@ -321,7 +286,8 @@ _PyThreadState_GetFrameBorrow(PyThreadState *tstate) // bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a5 -#if PY_VERSION_HEX < 0x030900A5 || defined(PYPY_VERSION) +// PyPy added PyInterpreterState_Get() to PyPy3.12 v8.0.0 +#if PY_VERSION_HEX < 0x030900A5 || (defined(PYPY_VERSION) && PY_VERSION_HEX < 0x030C0000) static inline PyInterpreterState* PyInterpreterState_Get(void) { PyThreadState *tstate; @@ -458,7 +424,7 @@ static inline int PyObject_GC_IsTracked(PyObject* obj) // bpo-40241 added PyObject_GC_IsFinalized() to Python 3.9.0a6. // bpo-18112 added _PyGCHead_FINALIZED() to Python 3.4.0 final. -#if PY_VERSION_HEX < 0x030900A6 && PY_VERSION_HEX >= 0x030400F0 && !defined(PYPY_VERSION) +#if PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION) static inline int PyObject_GC_IsFinalized(PyObject *obj) { PyGC_Head *gc = _Py_CAST(PyGC_Head*, obj) - 1; @@ -480,7 +446,7 @@ static inline int _Py_IS_TYPE(PyObject *ob, PyTypeObject *type) { // bpo-11734 added _PyFloat_Pack2() and _PyFloat_Unpack2() to Python 3.6.0b1. // Python 3.11a2 moved _PyFloat_Pack2() and _PyFloat_Unpack2() to the internal // C API: Python 3.11a2-3.11a6 versions are not supported. -#if 0x030600B1 <= PY_VERSION_HEX && PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION) +#if PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION) static inline int PyFloat_Pack2(double x, char *p, int le) { return _PyFloat_Pack2(x, (unsigned char*)p, le); } @@ -544,7 +510,7 @@ static inline PyObject* PyCode_GetCellvars(PyCodeObject *code) // Py_UNUSED() was added to Python 3.4.0b2. -#if PY_VERSION_HEX < 0x030400B2 && !defined(Py_UNUSED) +#ifndef Py_UNUSED # if defined(__GNUC__) || defined(__clang__) # define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) # else @@ -705,13 +671,8 @@ PyObject_GetOptionalAttr(PyObject *obj, PyObject *attr_name, PyObject **result) static inline int PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject **result) { - PyObject *name_obj; int rc; -#if PY_VERSION_HEX >= 0x03000000 - name_obj = PyUnicode_FromString(attr_name); -#else - name_obj = PyString_FromString(attr_name); -#endif + PyObject *name_obj = PyUnicode_FromString(attr_name); if (name_obj == NULL) { *result = NULL; return -1; @@ -743,13 +704,8 @@ PyMapping_GetOptionalItem(PyObject *obj, PyObject *key, PyObject **result) static inline int PyMapping_GetOptionalItemString(PyObject *obj, const char *key, PyObject **result) { - PyObject *key_obj; int rc; -#if PY_VERSION_HEX >= 0x03000000 - key_obj = PyUnicode_FromString(key); -#else - key_obj = PyString_FromString(key); -#endif + PyObject *key_obj = PyUnicode_FromString(key); if (key_obj == NULL) { *result = NULL; return -1; @@ -812,11 +768,7 @@ PyObject_HasAttrStringWithError(PyObject *obj, const char *attr) static inline int PyDict_GetItemRef(PyObject *mp, PyObject *key, PyObject **result) { -#if PY_VERSION_HEX >= 0x03000000 PyObject *item = PyDict_GetItemWithError(mp, key); -#else - PyObject *item = _PyDict_GetItemWithError(mp, key); -#endif if (item != NULL) { *result = Py_NewRef(item); return 1; // found @@ -833,11 +785,7 @@ static inline int PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result) { int res; -#if PY_VERSION_HEX >= 0x03000000 PyObject *key_obj = PyUnicode_FromString(key); -#else - PyObject *key_obj = PyString_FromString(key); -#endif if (key_obj == NULL) { *result = NULL; return -1; @@ -864,7 +812,7 @@ PyModule_Add(PyObject *mod, const char *name, PyObject *value) // gh-108014 added Py_IsFinalizing() to Python 3.13.0a1 // bpo-1856 added _Py_Finalizing to Python 3.2.1b1. // _Py_IsFinalizing() was added to PyPy 7.3.0. -#if (0x030201B1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030D00A1) \ +#if (PY_VERSION_HEX < 0x030D00A1) \ && (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x7030000) static inline int Py_IsFinalizing(void) { @@ -941,7 +889,7 @@ PyObject_ClearManagedDict(PyObject *obj) // gh-108867 added PyThreadState_GetUnchecked() to Python 3.13.0a1 // Python 3.5.2 added _PyThreadState_UncheckedGet(). -#if PY_VERSION_HEX >= 0x03050200 && PY_VERSION_HEX < 0x030D00A1 +#if PY_VERSION_HEX < 0x030D00A1 static inline PyThreadState* PyThreadState_GetUnchecked(void) { @@ -963,13 +911,12 @@ PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_ // API cannot report errors so save/restore the exception PyErr_Fetch(&exc_type, &exc_value, &exc_tb); - // Python 3.3.0a1 added PyUnicode_AsUTF8AndSize() -#if PY_VERSION_HEX >= 0x030300A1 if (PyUnicode_IS_ASCII(unicode)) { utf8 = PyUnicode_DATA(unicode); len = PyUnicode_GET_LENGTH(unicode); } else { + // Python 3.3.0a1 added PyUnicode_AsUTF8AndSize() utf8 = PyUnicode_AsUTF8AndSize(unicode, &len); if (utf8 == NULL) { // Memory allocation failure. The API cannot report error, @@ -984,31 +931,6 @@ PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_ goto done; } res = (memcmp(utf8, str, (size_t)len) == 0); -#else - PyObject *bytes = PyUnicode_AsUTF8String(unicode); - if (bytes == NULL) { - // Memory allocation failure. The API cannot report error, - // so ignore the exception and return 0. - res = 0; - goto done; - } - -#if PY_VERSION_HEX >= 0x03000000 - len = PyBytes_GET_SIZE(bytes); - utf8 = PyBytes_AS_STRING(bytes); -#else - len = PyString_GET_SIZE(bytes); - utf8 = PyString_AS_STRING(bytes); -#endif - if (len != str_len) { - Py_DECREF(bytes); - res = 0; - goto done; - } - - res = (memcmp(utf8, str, (size_t)len) == 0); - Py_DECREF(bytes); -#endif done: PyErr_Restore(exc_type, exc_value, exc_tb); @@ -1056,10 +978,8 @@ PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result) // bpo-16991 added _PyDict_Pop() to Python 3.5.0b2. // Python 3.6.0b3 changed _PyDict_Pop() first argument type to PyObject*. // Python 3.13.0a1 removed _PyDict_Pop(). -#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x030500b2 || PY_VERSION_HEX >= 0x030D0000 +#if defined(PYPY_VERSION) || PY_VERSION_HEX >= 0x030D0000 value = PyObject_CallMethod(dict, "pop", "O", key); -#elif PY_VERSION_HEX < 0x030600b3 - value = _PyDict_Pop(_Py_CAST(PyDictObject*, dict), key, NULL); #else value = _PyDict_Pop(dict, key, NULL); #endif @@ -1100,12 +1020,6 @@ PyDict_PopString(PyObject *dict, const char *key, PyObject **result) #endif -#if PY_VERSION_HEX < 0x030200A4 -// Python 3.2.0a4 added Py_hash_t type -typedef Py_ssize_t Py_hash_t; -#endif - - // gh-111545 added Py_HashPointer() to Python 3.13.0a3 #if PY_VERSION_HEX < 0x030D00A3 static inline Py_hash_t Py_HashPointer(const void *ptr) @@ -1121,7 +1035,7 @@ static inline Py_hash_t Py_HashPointer(const void *ptr) // Python 3.13a4 added a PyTime API. // Use the private API added to Python 3.5. -#if PY_VERSION_HEX < 0x030D00A4 && PY_VERSION_HEX >= 0x03050000 +#if PY_VERSION_HEX < 0x030D00A4 typedef _PyTime_t PyTime_t; #define PyTime_MIN _PyTime_MIN #define PyTime_MAX _PyTime_MAX @@ -1355,7 +1269,7 @@ PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value, # define Py_END_CRITICAL_SECTION2() } #endif -#if PY_VERSION_HEX < 0x030E0000 && PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION) +#if PY_VERSION_HEX < 0x030E0000 && !defined(PYPY_VERSION) typedef struct PyUnicodeWriter PyUnicodeWriter; static inline void PyUnicodeWriter_Discard(PyUnicodeWriter *writer) @@ -1594,7 +1508,7 @@ static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2) #if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION) return _PyUnicode_Equal(str1, str2); -#elif PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION) +#elif !defined(PYPY_VERSION) return _PyUnicode_EQ(str1, str2); #elif PY_VERSION_HEX >= 0x03090000 && defined(PYPY_VERSION) return _PyUnicode_EQ(str1, str2); @@ -1616,13 +1530,13 @@ static inline PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable) #if PY_VERSION_HEX < 0x030E00A0 -#if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) +#ifndef PYPY_VERSION PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void *src, Py_ssize_t len); #endif static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len) { -#if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) +#ifndef PYPY_VERSION return _Py_HashBytes(ptr, len); #else Py_hash_t hash; @@ -1748,7 +1662,7 @@ static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue) // gh-102471 added import and export API for integers to 3.14.0a2. -#if PY_VERSION_HEX < 0x030E00A2 && PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) +#if PY_VERSION_HEX < 0x030E00A2 && !defined(PYPY_VERSION) // Helpers to access PyLongObject internals. static inline void _PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size) @@ -1947,7 +1861,7 @@ PyLongWriter_Finish(PyLongWriter *writer) # define Py_T_ULONGLONG 18 # define Py_T_PYSSIZET 19 -# if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) +# ifndef PYPY_VERSION # define _Py_T_NONE 20 # endif @@ -1960,28 +1874,20 @@ PyLongWriter_Finish(PyLongWriter *writer) // gh-127350 added Py_fopen() and Py_fclose() to Python 3.14a4 #if PY_VERSION_HEX < 0x030E00A4 -#if 0x030400A2 <= PY_VERSION_HEX && !defined(PYPY_VERSION) +#ifndef PYPY_VERSION PyAPI_FUNC(FILE*) _Py_fopen_obj(PyObject *path, const char *mode); #endif static inline FILE* Py_fopen(PyObject *path, const char *mode) { -#if 0x030400A2 <= PY_VERSION_HEX && !defined(PYPY_VERSION) +#ifndef PYPY_VERSION return _Py_fopen_obj(path, mode); #else FILE *f; PyObject *bytes; -#if PY_VERSION_HEX >= 0x03000000 if (!PyUnicode_FSConverter(path, &bytes)) { return NULL; } -#else - if (!PyString_Check(path)) { - PyErr_SetString(PyExc_TypeError, "except str"); - return NULL; - } - bytes = Py_NewRef(path); -#endif const char *path_bytes = PyBytes_AS_STRING(bytes); f = fopen(path_bytes, mode); @@ -2226,7 +2132,8 @@ PyConfig_GetInt(const char *name, int *value) // gh-133144 added PyUnstable_Object_IsUniquelyReferenced() to Python 3.14.0b1. // Adapted from _PyObject_IsUniquelyReferenced() implementation. -#if PY_VERSION_HEX < 0x030E00B0 +// Not available on PyPy: Py_REFCNT() semantics is different on PyPy. +#if PY_VERSION_HEX < 0x030E00B0 && !defined(PYPY_VERSION) static inline int PyUnstable_Object_IsUniquelyReferenced(PyObject *obj) { #if !defined(Py_GIL_DISABLED) @@ -2244,7 +2151,8 @@ static inline int PyUnstable_Object_IsUniquelyReferenced(PyObject *obj) // gh-128926 added PyUnstable_TryIncRef() and PyUnstable_EnableTryIncRef() to // Python 3.14.0a5. Adapted from _Py_TryIncref() and _PyObject_SetMaybeWeakref(). -#if PY_VERSION_HEX < 0x030E00A5 +// Not available on PyPy: Py_REFCNT() semantics is different on PyPy. +#if PY_VERSION_HEX < 0x030E00A5 && !defined(PYPY_VERSION) static inline int PyUnstable_TryIncRef(PyObject *op) { #ifndef Py_GIL_DISABLED @@ -2315,18 +2223,14 @@ static inline void PyUnstable_EnableTryIncRef(PyObject *op) (void)op; // unused argument #endif } -#endif +#endif // PY_VERSION_HEX < 0x030E00A5 && !defined(PYPY_VERSION) #if PY_VERSION_HEX < 0x030F0000 static inline PyObject* PySys_GetAttrString(const char *name) { -#if PY_VERSION_HEX >= 0x03000000 PyObject *value = Py_XNewRef(PySys_GetObject(name)); -#else - PyObject *value = Py_XNewRef(PySys_GetObject((char*)name)); -#endif if (value != NULL) { return value; } @@ -2339,11 +2243,7 @@ PySys_GetAttrString(const char *name) static inline PyObject* PySys_GetAttr(PyObject *name) { -#if PY_VERSION_HEX >= 0x03000000 const char *name_str = PyUnicode_AsUTF8(name); -#else - const char *name_str = PyString_AsString(name); -#endif if (name_str == NULL) { return NULL; } @@ -2354,11 +2254,7 @@ PySys_GetAttr(PyObject *name) static inline int PySys_GetOptionalAttrString(const char *name, PyObject **value) { -#if PY_VERSION_HEX >= 0x03000000 *value = Py_XNewRef(PySys_GetObject(name)); -#else - *value = Py_XNewRef(PySys_GetObject((char*)name)); -#endif if (*value != NULL) { return 1; } @@ -2368,11 +2264,7 @@ PySys_GetOptionalAttrString(const char *name, PyObject **value) static inline int PySys_GetOptionalAttr(PyObject *name, PyObject **value) { -#if PY_VERSION_HEX >= 0x03000000 const char *name_str = PyUnicode_AsUTF8(name); -#else - const char *name_str = PyString_AsString(name); -#endif if (name_str == NULL) { *value = NULL; return -1; @@ -2665,10 +2557,8 @@ PyUnstable_Unicode_GET_CACHED_HASH(PyObject *op) #ifdef PYPY_VERSION (void)op; // unused argument return -1; -#elif PY_VERSION_HEX >= 0x03000000 - return ((PyASCIIObject*)op)->hash; #else - return ((PyUnicodeObject*)op)->hash; + return ((PyASCIIObject*)op)->hash; #endif } #endif