Skip to content

collection ¤

Module containing all the logic.

Classes:

  • Collection

    A collection of duties.

  • Duty

    The main duty class.

Collection ¤

Collection(path: str = default_duties_file)

A collection of duties.

Attributes:

  • path

    The path to the duties file.

  • duties (dict[str, Duty]) –

    The list of duties.

  • aliases (dict[str, Duty]) –

    A dictionary of aliases pointing to their respective duties.

Parameters:

  • path (str, default: default_duties_file ) –

    The path to the duties file.

Methods:

  • add

    Add a duty to the collection.

  • clear

    Clear the collection.

  • format_help

    Format a message listing the duties.

  • get

    Get a duty by its name or alias.

  • load

    Load duties from a Python file.

  • names

    Return the list of duties names and aliases.

Source code in src/duty/collection.py
123
124
125
126
127
128
129
130
131
def __init__(self, path: str = default_duties_file) -> None:
    """Initialize the collection.

    Parameters:
        path: The path to the duties file.
    """
    self.path = path
    self.duties: dict[str, Duty] = {}
    self.aliases: dict[str, Duty] = {}

add ¤

add(duty: Duty) -> None

Add a duty to the collection.

Parameters:

  • duty (Duty) –

    The duty to add.

Source code in src/duty/collection.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
def add(self, duty: Duty) -> None:
    """Add a duty to the collection.

    Parameters:
        duty: The duty to add.
    """
    if duty.collection is not None:
        # we must copy the duty to be able to add it
        # in multiple collections
        duty = deepcopy(duty)
    duty.collection = self
    self.duties[duty.name] = duty
    for alias in duty.aliases:
        self.aliases[alias] = duty

clear ¤

clear() -> None

Clear the collection.

Source code in src/duty/collection.py
133
134
135
136
def clear(self) -> None:
    """Clear the collection."""
    self.duties.clear()
    self.aliases.clear()

format_help ¤

format_help() -> str

Format a message listing the duties.

Returns:

  • str

    A string listing the duties and their summary.

Source code in src/duty/collection.py
160
161
162
163
164
165
166
167
168
169
170
171
172
def format_help(self) -> str:
    """Format a message listing the duties.

    Returns:
        A string listing the duties and their summary.
    """
    lines = []
    # 20 makes the summary aligned with options description
    longest_name = max(*(len(name) for name in self.duties), 20)
    for name, duty in self.duties.items():
        description = duty.description.split("\n")[0]
        lines.append(f"{name:{longest_name}}  {description}")
    return "\n".join(lines)

get ¤

get(name_or_alias: str) -> Duty

Get a duty by its name or alias.

Parameters:

  • name_or_alias (str) –

    The name or alias of the duty.

Returns:

Source code in src/duty/collection.py
146
147
148
149
150
151
152
153
154
155
156
157
158
def get(self, name_or_alias: str) -> Duty:
    """Get a duty by its name or alias.

    Parameters:
        name_or_alias: The name or alias of the duty.

    Returns:
        A duty.
    """
    try:
        return self.duties[name_or_alias]
    except KeyError:
        return self.aliases[name_or_alias]

load ¤

load(path: str | None = None) -> None

Load duties from a Python file.

Parameters:

  • path (str | None, default: None ) –

    The path to the Python file to load. Uses the collection's path by default.

Source code in src/duty/collection.py
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
def load(self, path: str | None = None) -> None:
    """Load duties from a Python file.

    Parameters:
        path: The path to the Python file to load.
            Uses the collection's path by default.
    """
    path = path or self.path
    spec = importlib_util.spec_from_file_location("duty.duties", path)
    if spec:
        duties = importlib_util.module_from_spec(spec)
        sys.modules["duty.duties"] = duties
        spec.loader.exec_module(duties)  # type: ignore[union-attr]
        declared_duties = inspect.getmembers(duties, lambda member: isinstance(member, Duty))
        for _, duty in declared_duties:
            self.add(duty)

names ¤

names() -> list[str]

Return the list of duties names and aliases.

Returns:

  • list[str]

    The list of duties names and aliases.

Source code in src/duty/collection.py
138
139
140
141
142
143
144
def names(self) -> list[str]:
    """Return the list of duties names and aliases.

    Returns:
        The list of duties names and aliases.
    """
    return list(self.duties.keys()) + list(self.aliases.keys())

Duty ¤

Duty(
    name: str,
    description: str,
    function: Callable,
    collection: Collection | None = None,
    aliases: set | None = None,
    pre: DutyListType | None = None,
    post: DutyListType | None = None,
    opts: dict[str, Any] | None = None,
)

The main duty class.

Parameters:

  • name (str) –

    The duty name.

  • description (str) –

    The duty description.

  • function (Callable) –

    The duty function.

  • collection (Collection | None, default: None ) –

    The collection on which to attach this duty.

  • aliases (set | None, default: None ) –

    A list of aliases for this duty.

  • pre (DutyListType | None, default: None ) –

    A list of duties to run before this one.

  • post (DutyListType | None, default: None ) –

    A list of duties to run after this one.

  • opts (dict[str, Any] | None, default: None ) –

    Options used to create the context instance.

Methods:

Attributes:

Source code in src/duty/collection.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def __init__(
    self,
    name: str,
    description: str,
    function: Callable,
    collection: Collection | None = None,
    aliases: set | None = None,
    pre: DutyListType | None = None,
    post: DutyListType | None = None,
    opts: dict[str, Any] | None = None,
) -> None:
    """Initialize the duty.

    Parameters:
        name: The duty name.
        description: The duty description.
        function: The duty function.
        collection: The collection on which to attach this duty.
        aliases: A list of aliases for this duty.
        pre: A list of duties to run before this one.
        post: A list of duties to run after this one.
        opts: Options used to create the context instance.
    """
    self.name = name
    self.description = description
    self.function = function
    self.aliases = aliases or set()
    self.pre = pre or []
    self.post = post or []
    self.options = opts or self.default_options
    self.options_override: dict = {}

    self.collection: Collection | None = None
    if collection:
        collection.add(self)

context property ¤

context: Context

Return a new context instance.

Returns:

  • Context

    A new context instance.

run ¤

run(*args: Any, **kwargs: Any) -> None

Run the duty.

This is just a shortcut for duty(duty.context, *args, **kwargs).

Parameters:

  • args (Any, default: () ) –

    Positional arguments passed to the function.

  • kwargs (Any, default: {} ) –

    Keyword arguments passed to the function.

Source code in src/duty/collection.py
67
68
69
70
71
72
73
74
75
76
def run(self, *args: Any, **kwargs: Any) -> None:
    """Run the duty.

    This is just a shortcut for `duty(duty.context, *args, **kwargs)`.

    Parameters:
        args: Positional arguments passed to the function.
        kwargs: Keyword arguments passed to the function.
    """
    self(self.context, *args, **kwargs)

run_duties ¤

run_duties(
    context: Context, duties_list: DutyListType
) -> None

Run a list of duties.

Parameters:

  • context (Context) –

    The context to use.

  • duties_list (DutyListType) –

    The list of duties to run.

Raises:

  • RuntimeError

    When a duty name is given to pre or post duties. Indeed, without a parent collection, it is impossible to find another duty by its name.

Source code in src/duty/collection.py
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
def run_duties(self, context: Context, duties_list: DutyListType) -> None:
    """Run a list of duties.

    Parameters:
        context: The context to use.
        duties_list: The list of duties to run.

    Raises:
        RuntimeError: When a duty name is given to pre or post duties.
            Indeed, without a parent collection, it is impossible
            to find another duty by its name.
    """
    for duty_item in duties_list:
        if callable(duty_item):
            # Item is a proper duty, or a callable: run it.
            duty_item(context)
        elif isinstance(duty_item, str):
            # Item is a reference to a duty.
            if self.collection is None:
                raise RuntimeError(f"Can't find duty by name without a collection ({duty_item})")
            # Get the duty and run it.
            self.collection.get(duty_item)(context)