Skip to content

Add types to the package. #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 15, 2022
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
15 changes: 15 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ repos:
rev: v2.1.0
hooks:
- id: codespell
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v0.930'
hooks:
- id: mypy
args: [
--no-strict-optional,
--ignore-missing-imports,
]
additional_dependencies: [
types-attrs,
types-click,
types-setuptools
]
pass_filenames: false
language_version: "3.9"
- repo: https://github.com/mgedmin/check-manifest
rev: "0.48"
hooks:
Expand Down
4 changes: 3 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ chronological order. Releases follow [semantic versioning](https://semver.org/)
releases are available on [PyPI](https://pypi.org/project/pytask-parallel) and
[Anaconda.org](https://anaconda.org/conda-forge/pytask-parallel).

## 0.1.2 - 2022-xx-xx
## 0.2.0 - 2022-xx-xx

- {pull}`31` adds types to the package.
- {pull}`36` adds a test for <https://github.com/pytask-dev/pytask/issues/216>.
- {pull}`37` aligns pytask-parallel with pytask v0.2.

## 0.1.1 - 2022-02-08

Expand Down
17 changes: 17 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,20 @@ build-backend = "setuptools.build_meta"

[tool.setuptools_scm]
write_to = "src/pytask_parallel/_version.py"


[tool.mypy]
files = ["src", "tests"]
check_untyped_defs = true
disallow_any_generics = true
disallow_incomplete_defs = true
disallow_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true


[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
ignore_errors = true
2 changes: 1 addition & 1 deletion src/pytask_parallel/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


@hookimpl
def pytask_extend_command_line_interface(cli):
def pytask_extend_command_line_interface(cli: click.Group) -> None:
"""Extend the command line interface."""
additional_parameters = [
click.Option(
Expand Down
8 changes: 5 additions & 3 deletions src/pytask_parallel/callbacks.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"""Validate command line inputs and configuration values."""
from __future__ import annotations

from typing import Any

from pytask_parallel.backends import PARALLEL_BACKENDS


def n_workers_callback(value):
def n_workers_callback(value: Any) -> int:
"""Validate the n-workers option."""
if value == "auto":
pass
Expand All @@ -20,7 +22,7 @@ def n_workers_callback(value):
return value


def parallel_backend_callback(value):
def parallel_backend_callback(value: Any) -> str | None:
"""Validate the input for the parallel backend."""
if value in [None, "None", "none"]:
value = None
Expand All @@ -33,7 +35,7 @@ def parallel_backend_callback(value):
return value


def delay_callback(value):
def delay_callback(value: Any) -> float | None:
"""Validate the delay option."""
if value in [None, "None", "none"]:
value = None
Expand Down
8 changes: 6 additions & 2 deletions src/pytask_parallel/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@


@hookimpl
def pytask_parse_config(config, config_from_cli, config_from_file):
def pytask_parse_config(
config: dict[str, Any],
config_from_cli: dict[str, Any],
config_from_file: dict[str, Any],
) -> None:
"""Parse the configuration."""
config["n_workers"] = _get_first_non_none_value(
config_from_cli,
Expand Down Expand Up @@ -43,7 +47,7 @@ def pytask_parse_config(config, config_from_cli, config_from_file):


@hookimpl
def pytask_post_parse(config):
def pytask_post_parse(config: dict[str, Any]) -> None:
"""Disable parallelization if debugging is enabled."""
if config["pdb"] or config["trace"]:
config["n_workers"] = 1
Expand Down
36 changes: 26 additions & 10 deletions src/pytask_parallel/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import inspect
import sys
import time
from concurrent.futures import Future
from types import TracebackType
from typing import Any

import cloudpickle
Expand All @@ -12,13 +14,15 @@
from pytask import ExecutionReport
from pytask import hookimpl
from pytask import remove_internal_traceback_frames_from_exc_info
from pytask import Session
from pytask import Task
from pytask_parallel.backends import PARALLEL_BACKENDS
from rich.console import ConsoleOptions
from rich.traceback import Traceback


@hookimpl
def pytask_post_parse(config):
def pytask_post_parse(config: dict[str, Any]) -> None:
"""Register the parallel backend."""
if config["parallel_backend"] in ("loky", "processes"):
config["pm"].register(ProcessesNameSpace)
Expand All @@ -27,7 +31,7 @@ def pytask_post_parse(config):


@hookimpl(tryfirst=True)
def pytask_execute_build(session):
def pytask_execute_build(session: Session) -> bool | None:
"""Execute tasks with a parallel backend.

There are three phases while the scheduler has tasks which need to be executed.
Expand All @@ -40,7 +44,7 @@ def pytask_execute_build(session):
"""
if session.config["n_workers"] > 1:
reports = session.execution_reports
running_tasks = {}
running_tasks: dict[str, Future[Any]] = {}

parallel_backend = PARALLEL_BACKENDS[session.config["parallel_backend"]]

Expand Down Expand Up @@ -137,13 +141,15 @@ def pytask_execute_build(session):
break

return True
return None


class ProcessesNameSpace:
"""The name space for hooks related to processes."""

@staticmethod
@hookimpl(tryfirst=True)
def pytask_execute_task(session, task): # noqa: N805
def pytask_execute_task(session: Session, task: Task) -> Future[Any] | None:
"""Execute a task.

Take a task, pickle it and send the bytes over to another process.
Expand All @@ -162,11 +168,15 @@ def pytask_execute_task(session, task): # noqa: N805
show_locals=session.config["show_locals"],
console_options=console.options,
)
return None


def _unserialize_and_execute_task(
bytes_function, bytes_kwargs, show_locals, console_options
):
bytes_function: bytes,
bytes_kwargs: bytes,
show_locals: bool,
console_options: ConsoleOptions,
) -> tuple[type[BaseException], BaseException, str] | None:
"""Unserialize and execute task.

This function receives bytes and unpickles them to a task which is them execute
Expand All @@ -184,11 +194,14 @@ def _unserialize_and_execute_task(
exc_info = sys.exc_info()
processed_exc_info = _process_exception(exc_info, show_locals, console_options)
return processed_exc_info
return None


def _process_exception(
exc_info: tuple[Any], show_locals: bool, console_options: ConsoleOptions
) -> tuple[Any]:
exc_info: tuple[type[BaseException], BaseException, TracebackType | None],
show_locals: bool,
console_options: ConsoleOptions,
) -> tuple[type[BaseException], BaseException, str]:
"""Process the exception and convert the traceback to a string."""
exc_info = remove_internal_traceback_frames_from_exc_info(exc_info)
traceback = Traceback.from_exception(*exc_info, show_locals=show_locals)
Expand All @@ -200,8 +213,9 @@ def _process_exception(
class DefaultBackendNameSpace:
"""The name space for hooks related to threads."""

@staticmethod
@hookimpl(tryfirst=True)
def pytask_execute_task(session, task): # noqa: N805
def pytask_execute_task(session: Session, task: Task) -> Future[Any] | None:
"""Execute a task.

Since threads have shared memory, it is not necessary to pickle and unpickle the
Expand All @@ -211,9 +225,11 @@ def pytask_execute_task(session, task): # noqa: N805
if session.config["n_workers"] > 1:
kwargs = _create_kwargs_for_task(task)
return session.executor.submit(task.execute, **kwargs)
else:
return None


def _create_kwargs_for_task(task):
def _create_kwargs_for_task(task: Task) -> dict[Any, Any]:
"""Create kwargs for task function."""
kwargs = {**task.kwargs}

Expand Down
3 changes: 2 additions & 1 deletion src/pytask_parallel/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@

from pytask import console
from pytask import hookimpl
from pytask import Session


@hookimpl(trylast=True)
def pytask_log_session_header(session):
def pytask_log_session_header(session: Session) -> None:
"""Add a note for how many workers are spawned."""
n_workers = session.config["n_workers"]
if n_workers > 1:
Expand Down
3 changes: 2 additions & 1 deletion src/pytask_parallel/plugin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Entry-point for the plugin."""
from __future__ import annotations

from pluggy import PluginManager
from pytask import hookimpl
from pytask_parallel import build
from pytask_parallel import config
Expand All @@ -9,7 +10,7 @@


@hookimpl
def pytask_add_hooks(pm):
def pytask_add_hooks(pm: PluginManager) -> None:
"""Register plugins."""
pm.register(build)
pm.register(config)
Expand Down
Empty file added tests/__init__.py
Empty file.