Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ updates:
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 7
groups:
github-actions:
patterns:
Expand All @@ -13,3 +15,5 @@ updates:
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 7
24 changes: 17 additions & 7 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,35 @@ 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

run-tests:

name: Run tests for ${{ matrix.os }} on ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
permissions:
contents: read

strategy:
fail-fast: false
Expand All @@ -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
34 changes: 21 additions & 13 deletions .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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@v7
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: python-package-distributions
path: dist/
Expand All @@ -41,12 +47,12 @@ jobs:

steps:
- name: Download all the dists
uses: actions/download-artifact@v8
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
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: >-
Expand All @@ -62,30 +68,32 @@ jobs:

steps:
- name: Download all the dists
uses: actions/download-artifact@v8
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
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
./dist/*.whl
- 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"
48 changes: 48 additions & 0 deletions .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion src/pytask_parallel/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
6 changes: 3 additions & 3 deletions src/pytask_parallel/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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(
Expand All @@ -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(
Expand Down
6 changes: 3 additions & 3 deletions src/pytask_parallel/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down
6 changes: 5 additions & 1 deletion src/pytask_parallel/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand Down
Loading