From dae3351862ccc84f84045dcc1b8b9a023a988ca6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:18:54 +0000 Subject: [PATCH 1/5] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.14.14 → v0.15.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.14...v0.15.2) - [github.com/kynan/nbstripout: 0.9.0 → 0.9.1](https://github.com/kynan/nbstripout/compare/0.9.0...0.9.1) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ceee0ce..b89b1ab 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,12 +26,12 @@ repos: - id: python-use-type-annotations - id: text-unicode-replacement-char - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.14 + rev: v0.15.2 hooks: - id: ruff-check - id: ruff-format - repo: https://github.com/kynan/nbstripout - rev: 0.9.0 + rev: 0.9.1 hooks: - id: nbstripout - repo: https://github.com/executablebooks/mdformat From cd14e38feabde1f8ef305e1e243da5216be88bf2 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sun, 1 Mar 2026 11:05:56 +0100 Subject: [PATCH 2/5] Fix ty check for CoiledFunction construction --- src/pytask_parallel/wrappers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pytask_parallel/wrappers.py b/src/pytask_parallel/wrappers.py index e26deba..219f3fc 100644 --- a/src/pytask_parallel/wrappers.py +++ b/src/pytask_parallel/wrappers.py @@ -178,7 +178,9 @@ def wrap_task_in_process( # noqa: PLR0913 def rewrap_task_with_coiled_function(task: PTask) -> CoiledFunction: - wrapped = CoiledFunction(wrap_task_in_process, **task.attributes["coiled_kwargs"]) + wrapped = cast("Any", CoiledFunction)( + wrap_task_in_process, **task.attributes["coiled_kwargs"] + ) decorated = functools.wraps(wrap_task_in_process)( cast("Callable[..., Any]", wrapped) ) From 1e998b24ae5d65961d95bed2cf2ef45303789129 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 28 Mar 2026 09:55:26 +0100 Subject: [PATCH 3/5] Harden GitHub Actions workflows with zizmor --- .github/dependabot.yml | 4 +++ .github/workflows/main.yml | 24 ++++++++++---- .github/workflows/publish-to-pypi.yml | 34 +++++++++++-------- .github/workflows/zizmor.yml | 48 +++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/zizmor.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml index be4ca53..f0b9eaf 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,6 +5,8 @@ updates: directory: "/" schedule: interval: "weekly" + cooldown: + default-days: 7 groups: github-actions: patterns: @@ -13,3 +15,5 @@ updates: directory: "/" schedule: interval: "weekly" + cooldown: + default-days: 7 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7f7a5c0..4e9fb36 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,20 +15,26 @@ on: - '*' merge_group: +permissions: {} + jobs: run-type-checking: name: Run tests for type-checking runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v6 - - uses: astral-sh/setup-uv@v7 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: enable-cache: true - name: Install just - uses: extractions/setup-just@v3 + uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b # v3 - name: Run type checking run: just typing @@ -36,6 +42,8 @@ jobs: name: Run tests for ${{ matrix.os }} on ${{ matrix.python-version }} runs-on: ${{ matrix.os }} + permissions: + contents: read strategy: fail-fast: false @@ -44,15 +52,17 @@ jobs: python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] steps: - - uses: actions/checkout@v6 - - uses: astral-sh/setup-uv@v7 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: python-version: ${{ matrix.python-version }} enable-cache: true - name: Install just - uses: extractions/setup-just@v3 + uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b # v3 - name: Run tests run: just test - name: Upload test coverage reports to Codecov with GitHub Action - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5 diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index dd7ae5c..742b361 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -2,15 +2,21 @@ name: Publish Python 🐍 distribution 📦 to PyPI on: push +permissions: {} + jobs: build: name: Build distribution 📦 runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version: "3.x" - name: Install pypa/build @@ -22,7 +28,7 @@ jobs: - name: Build a binary wheel and a source tarball run: python3 -m build - name: Store the distribution packages - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: python-package-distributions path: dist/ @@ -41,12 +47,12 @@ jobs: steps: - name: Download all the dists - uses: actions/download-artifact@v7 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 with: name: python-package-distributions path: dist/ - name: Publish distribution 📦 to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1 github-release: name: >- @@ -62,12 +68,12 @@ jobs: steps: - name: Download all the dists - uses: actions/download-artifact@v7 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 with: name: python-package-distributions path: dist/ - name: Sign the dists with Sigstore - uses: sigstore/gh-action-sigstore-python@v3.2.0 + uses: sigstore/gh-action-sigstore-python@a5caf349bc536fbef3668a10ed7f5cd309a4b53d # v3.2.0 with: inputs: >- ./dist/*.tar.gz @@ -75,17 +81,19 @@ jobs: - name: Create GitHub Release env: GITHUB_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ github.ref_name }} + REPOSITORY: ${{ github.repository }} run: >- gh release create - '${{ github.ref_name }}' - --repo '${{ github.repository }}' + "$RELEASE_TAG" + --repo "$REPOSITORY" --notes "" - name: Upload artifact signatures to GitHub Release env: GITHUB_TOKEN: ${{ github.token }} - # Upload to GitHub Release using the `gh` CLI. `dist/` contains the built - # packages, and the sigstore-produced signatures and certificates. + RELEASE_TAG: ${{ github.ref_name }} + REPOSITORY: ${{ github.repository }} run: >- gh release upload - '${{ github.ref_name }}' dist/** - --repo '${{ github.repository }}' + "$RELEASE_TAG" dist/** + --repo "$REPOSITORY" diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000..9e959bc --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,48 @@ +name: zizmor + +on: + push: + branches: + - main + pull_request: + branches: + - '*' + schedule: + - cron: '0 7 * * 1' + workflow_dispatch: + +permissions: {} + +jobs: + zizmor: + name: Scan GitHub Actions + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 + with: + enable-cache: true + python-version: '3.13' + + - name: Run zizmor + run: uvx --from zizmor zizmor --format=github . + + - name: Generate SARIF report + if: always() + run: uvx --from zizmor zizmor --format=sarif --no-exit-codes . > zizmor.sarif + + - name: Upload SARIF report + if: > + always() && + (github.event_name != 'pull_request' || + github.event.pull_request.head.repo.full_name == github.repository) + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4 + with: + sarif_file: zizmor.sarif From 56c270d8f39174762dea145777b53a34dceec229 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 28 Mar 2026 10:14:39 +0100 Subject: [PATCH 4/5] Fix typing regressions after merging main --- src/pytask_parallel/config.py | 3 ++- src/pytask_parallel/execute.py | 6 +++--- src/pytask_parallel/utils.py | 6 +++--- src/pytask_parallel/wrappers.py | 6 +++++- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/pytask_parallel/config.py b/src/pytask_parallel/config.py index e39440b..cd85869 100644 --- a/src/pytask_parallel/config.py +++ b/src/pytask_parallel/config.py @@ -27,7 +27,8 @@ def pytask_parse_config(config: dict[str, Any]) -> None: raise ValueError(msg) from None if config["n_workers"] == "auto": - config["n_workers"] = max(os.cpu_count() - 1, 1) # type: ignore[operator] + cpu_count = os.cpu_count() or 1 + config["n_workers"] = max(cpu_count - 1, 1) # If more than one worker is used, and no backend is set, use loky. if config["n_workers"] > 1 and config["parallel_backend"] == ParallelBackend.NONE: diff --git a/src/pytask_parallel/execute.py b/src/pytask_parallel/execute.py index aa0f3a0..1b31a24 100644 --- a/src/pytask_parallel/execute.py +++ b/src/pytask_parallel/execute.py @@ -137,7 +137,7 @@ def pytask_execute_build(session: Session) -> bool | None: # noqa: C901, PLR091 newly_collected_reports.append( ExecutionReport.from_task_and_exception( task, - wrapper_result.exc_info, # type: ignore[arg-type] + cast("Any", wrapper_result.exc_info), ) ) running_tasks.pop(task_name) @@ -213,7 +213,7 @@ def pytask_execute_task(session: Session, task: PTask) -> Future[WrapperResult]: # cloudpickle will pickle it with the function. See cloudpickle#417, pytask#373 # and pytask#374. task_module = get_module(task.function, getattr(task, "path", None)) - if should_pickle_module_by_value(task_module): + if task_module is not None and should_pickle_module_by_value(task_module): cloudpickle.register_pickle_by_value(task_module) return cast("Any", wrapper_func).submit( @@ -237,7 +237,7 @@ def pytask_execute_task(session: Session, task: PTask) -> Future[WrapperResult]: # cloudpickle will pickle it with the function. See cloudpickle#417, pytask#373 # and pytask#374. task_module = get_module(task.function, getattr(task, "path", None)) - if should_pickle_module_by_value(task_module): + if task_module is not None and should_pickle_module_by_value(task_module): cloudpickle.register_pickle_by_value(task_module) return session.config["_parallel_executor"].submit( diff --git a/src/pytask_parallel/utils.py b/src/pytask_parallel/utils.py index fa1137c..c76dce9 100644 --- a/src/pytask_parallel/utils.py +++ b/src/pytask_parallel/utils.py @@ -136,7 +136,7 @@ def _parse_future_exception( return None if exc is None else (type(exc), exc, exc.__traceback__) -def get_module(func: Callable[..., Any], path: Path | None) -> ModuleType: +def get_module(func: Callable[..., Any], path: Path | None) -> ModuleType | None: """Get the module of a python function. ``functools.partial`` obfuscates the module of the function and @@ -151,8 +151,8 @@ def get_module(func: Callable[..., Any], path: Path | None) -> ModuleType: func = func.func if path: - return inspect.getmodule(func, path.as_posix()) # type: ignore[return-value] - return inspect.getmodule(func) # type: ignore[return-value] + return inspect.getmodule(func, path.as_posix()) + return inspect.getmodule(func) def strip_annotation_locals(task: PTask) -> None: diff --git a/src/pytask_parallel/wrappers.py b/src/pytask_parallel/wrappers.py index 219f3fc..63cdf61 100644 --- a/src/pytask_parallel/wrappers.py +++ b/src/pytask_parallel/wrappers.py @@ -138,7 +138,11 @@ def wrap_task_in_process( # noqa: PLR0913 except Exception: # noqa: BLE001 exc_info = sys.exc_info() processed_exc_info = _render_traceback_to_string( - exc_info, # type: ignore[arg-type] + ( + cast("type[BaseException]", exc_info[0]), + cast("BaseException", exc_info[1]), + exc_info[2], + ), show_locals, console_options, ) From 7cc39757ad64ce1502651ca43fc11f37325c7d40 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 28 Mar 2026 11:02:53 +0100 Subject: [PATCH 5/5] Use uv in publish workflow --- .github/workflows/publish-to-pypi.yml | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index 3c7a51b..0c7930e 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -15,18 +15,13 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - name: Set up Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 + - name: Install uv + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 with: - python-version: "3.x" - - name: Install pypa/build - run: >- - python3 -m - pip install - build - --user + enable-cache: true + python-version: "3.13" - name: Build a binary wheel and a source tarball - run: python3 -m build + run: uv build - name: Store the distribution packages uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 with: @@ -51,8 +46,10 @@ jobs: with: name: python-package-distributions path: dist/ + - name: Install uv + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 - name: Publish distribution 📦 to PyPI - uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1 + run: uv publish github-release: name: >-