Source code for repobee_plug._tasks

"""Task data structure and related functionality.

.. module:: tasks
    :synopsis: Task data structure and related functionality.

.. moduleauthor:: Simon Larsén
"""
import collections

from pathlib import Path
from argparse import ArgumentParser, Namespace
from typing import Callable, Optional

from repobee_plug._containers import Result
from repobee_plug._apimeta import API


[docs]class Task( collections.namedtuple( "Task", ("act", "add_option", "handle_args", "persist_changes") ) ): """A data structure for describing a task. Tasks are operations that plugins can define to run on for example cloned student repos (a clone task) or on master repos before setting up student repos (a setup task). Only the ``act`` attribute is required, all other attributes can be omitted. The callback methods should have the following headers. .. code-block:: python def act( path: pathlib.Path, api: repobee_plug.API ) -> Optional[containers.Result]: def add_option(parser: argparse.ArgumentParser) -> None: def handle_args(args: argparse.Namespace) -> None: .. note:: The functions are called in the following order: ``add_option`` -> ``handle_args`` -> ``act``. .. important:: The ``act`` callback should *never* change the Git repository it acts upon (e.g. running commands such as ``git add``, ``git checkout`` or ``git commit``). This can have adverse and unexpected effects on RepoBee's functionality. It is however absolutely fine to change the files in the Git working tree, as long as nothing is added or committed. Each callback is called at most once. They are not guaranteed to execute, because there may be an unexpected crash somewhere else, or the plugin may not come into scope (for example, a clone task plugin will not come into scope if ``repobee setup`` is run). The callbacks can do whatever is appropriate for the plugin, except for changing any Git repositories. For information on the types used in the callbacks, see the Python stdlib documentation for :py:mod:`argparse`. As an example, a simple clone task can be defined like so: .. code-block:: python import repobee_plug as plug def act(path, api): return plug.Result( name="example", msg="IT LIVES!", status=plug.Status.SUCCESS ) @plug.repobee_hook def clone_task(): return plug.Task(act=act) If your task plugin also needs to access the configuration file, then implement the separate ``config_hook`` hook. For more elaborate instructions on creating tasks, see the tutorial. """ def __new__( cls, act: Callable[[Path, API], Result], add_option: Optional[Callable[[ArgumentParser], None]] = None, handle_args: Optional[Callable[[Namespace], None]] = None, persist_changes: bool = False, ): return super().__new__( cls, act, add_option, handle_args, persist_changes ) # The init method is just added for documentation purposes def __init__( self, act: Callable[[Path, API], Result], add_option: Optional[Callable[[ArgumentParser], None]] = None, handle_args: Optional[Callable[[Namespace], None]] = None, persist_changes: bool = False, ): """ Args: act: A required callback function that takes the path to a repository worktree and an API instance, and optionally returns a Result to report results. add_option: An optional callback function that adds options to the CLI parser. handle_args: An optional callback function that receives the parsed CLI args. persist_changes: If True, the task requires that changes to the repository that has been acted upon be persisted. This means different things in different contexts (e.g. whether the task is executed in a clone context or in a setup context), and may not be supported for all contexts. """ super().__init__()