diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ff24424..ff9cc5e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,7 +42,7 @@ jobs: fail-fast: false matrix: os: ['ubuntu-latest', 'macos-latest', 'windows-latest'] - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index 65c4cc6..0f21e40 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ tests/test_jupyter/*.txt .pytest_cache .ruff_cache .venv +uv.lock diff --git a/pyproject.toml b/pyproject.toml index 79d429c..a067839 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,16 +6,16 @@ classifiers = [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3 :: Only" + "Programming Language :: Python :: 3 :: Only", ] -requires-python = ">=3.8" +requires-python = ">=3.9" dependencies = [ "attrs>=21.3.0", "click", "cloudpickle", "loky", "pluggy>=1.0.0", - "pytask>=0.5.0", + "pytask>=0.5.2", "rich", ] dynamic = ["version"] @@ -40,12 +40,7 @@ docs = [ "sphinx-toolbox", "sphinxext-opengraph", ] -test = [ - "pytask-parallel[coiled,dask]", - "nbmake", - "pytest", - "pytest-cov", -] +test = ["pytask-parallel[coiled,dask]", "nbmake", "pytest", "pytest-cov"] [project.readme] file = "README.md" @@ -70,9 +65,7 @@ build-backend = "hatchling.build" [tool.rye] managed = true -dev-dependencies = [ - "s3fs>=2024.3.1", -] +dev-dependencies = ["s3fs>=2024.3.1", "tox-uv>=1.7.0"] [tool.rye.scripts] clean-docs = { cmd = "rm -rf docs/build" } @@ -112,17 +105,17 @@ disallow_untyped_defs = false ignore_errors = true [tool.ruff] -target-version = "py38" +target-version = "py39" fix = true unsafe-fixes = true [tool.ruff.lint] extend-ignore = [ - "ANN101", # type annotating self - "ANN102", # type annotating cls - "ANN401", # flake8-annotate typing.Any - "COM812", # Comply with ruff-format. - "ISC001", # Comply with ruff-format. + "ANN101", # type annotating self + "ANN102", # type annotating cls + "ANN401", # flake8-annotate typing.Any + "COM812", # Comply with ruff-format. + "ISC001", # Comply with ruff-format. ] select = ["ALL"] diff --git a/src/pytask_parallel/backends.py b/src/pytask_parallel/backends.py index 582833b..a0e0b12 100644 --- a/src/pytask_parallel/backends.py +++ b/src/pytask_parallel/backends.py @@ -29,10 +29,10 @@ def _deserialize_and_run_with_cloudpickle(fn: bytes, kwargs: bytes) -> Any: class _CloudpickleProcessPoolExecutor(ProcessPoolExecutor): """Patches the standard executor to serialize functions with cloudpickle.""" - # The type signature is wrong for Python >3.8. Fix when support is dropped. - def submit( # type: ignore[override] + def submit( self, fn: Callable[..., Any], + /, *args: Any, # noqa: ARG002 **kwargs: Any, ) -> Future[Any]: diff --git a/src/pytask_parallel/execute.py b/src/pytask_parallel/execute.py index ec922a4..d2e9cd3 100644 --- a/src/pytask_parallel/execute.py +++ b/src/pytask_parallel/execute.py @@ -282,12 +282,14 @@ def _update_carry_over_node( return x raise NotImplementedError - structure_carry_over_products = tree_structure(carry_over_products) - structure_produces = tree_structure(task.produces) + structure_carry_over_products = tree_structure(carry_over_products) # type: ignore[arg-type] + structure_produces = tree_structure(task.produces) # type: ignore[arg-type] # strict must be false when none is leaf. if structure_produces.is_prefix(structure_carry_over_products, strict=False): task.produces = tree_map( - _update_carry_over_node, task.produces, carry_over_products + _update_carry_over_node, + task.produces, # type: ignore[arg-type] + carry_over_products, # type: ignore[arg-type] ) # type: ignore[assignment] diff --git a/src/pytask_parallel/wrappers.py b/src/pytask_parallel/wrappers.py index 6157873..a7b7d8c 100644 --- a/src/pytask_parallel/wrappers.py +++ b/src/pytask_parallel/wrappers.py @@ -106,9 +106,11 @@ def wrap_task_in_process( # noqa: PLR0913 captured_stderr_buffer = StringIO() # Catch warnings and store them in a list. - with warnings.catch_warnings(record=True) as log, redirect_stdout( - captured_stdout_buffer - ), redirect_stderr(captured_stderr_buffer): + with ( + warnings.catch_warnings(record=True) as log, + redirect_stdout(captured_stdout_buffer), + redirect_stderr(captured_stderr_buffer), + ): # Apply global filterwarnings. for arg in session_filterwarnings: warnings.filterwarnings(*parse_warning_filter(arg, escape=False)) @@ -267,7 +269,7 @@ def _save_and_carry_over_product( node.save(value) return None - return tree_map_with_path(_save_and_carry_over_product, task.produces) + return tree_map_with_path(_save_and_carry_over_product, task.produces) # type: ignore[arg-type] def _write_local_files_to_remote( @@ -279,7 +281,7 @@ def _write_local_files_to_remote( to be resolved. """ - return tree_map(lambda x: x.load() if isinstance(x, RemotePathNode) else x, kwargs) # type: ignore[return-value] + return tree_map(lambda x: x.load() if isinstance(x, RemotePathNode) else x, kwargs) # type: ignore[arg-type, return-value] def _delete_local_files_on_remote(kwargs: dict[str, PyTree[Any]]) -> None: @@ -296,4 +298,4 @@ def _delete(potential_node: Any) -> None: os.close(potential_node.fd) Path(potential_node.remote_path).unlink(missing_ok=True) - tree_map(_delete, kwargs) + tree_map(_delete, kwargs) # type: ignore[arg-type] diff --git a/tests/test_jupyter/test_functional_interface.ipynb b/tests/test_jupyter/test_functional_interface.ipynb index 95e34dc..7b885cc 100644 --- a/tests/test_jupyter/test_functional_interface.ipynb +++ b/tests/test_jupyter/test_functional_interface.ipynb @@ -8,12 +8,12 @@ "outputs": [], "source": [ "from pathlib import Path\n", + "from typing import Annotated\n", "\n", "import pytask\n", "from pytask import ExitCode\n", "from pytask import PathNode\n", - "from pytask import PythonNode\n", - "from typing_extensions import Annotated" + "from pytask import PythonNode" ] }, { diff --git a/tests/test_jupyter/test_functional_interface_w_relative_path.ipynb b/tests/test_jupyter/test_functional_interface_w_relative_path.ipynb index d56a5b6..02b2635 100644 --- a/tests/test_jupyter/test_functional_interface_w_relative_path.ipynb +++ b/tests/test_jupyter/test_functional_interface_w_relative_path.ipynb @@ -8,12 +8,12 @@ "outputs": [], "source": [ "from pathlib import Path\n", + "from typing import Annotated\n", "\n", "import pytask\n", "from pytask import ExitCode\n", "from pytask import PathNode\n", - "from pytask import PythonNode\n", - "from typing_extensions import Annotated" + "from pytask import PythonNode" ] }, {