refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2022-02-07 17:11:43 +00:00
|
|
|
# The Tutor plugin system is licensed under the terms of the Apache 2.0 license.
|
|
|
|
__license__ = "Apache 2.0"
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import typing as t
|
|
|
|
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
from typing_extensions import ParamSpec
|
|
|
|
|
2022-11-08 15:09:16 +00:00
|
|
|
from . import priorities
|
2022-02-07 17:11:43 +00:00
|
|
|
from .contexts import Contextualized
|
|
|
|
|
2023-01-06 18:02:17 +00:00
|
|
|
#: Action generic signature.
|
|
|
|
T = ParamSpec("T")
|
|
|
|
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
# Similarly to CallableFilter, it should be possible to create a CallableAction alias in
|
|
|
|
# the future.
|
2023-01-06 18:02:17 +00:00
|
|
|
# CallableAction = t.Callable[T, None]
|
2022-02-07 17:11:43 +00:00
|
|
|
|
|
|
|
|
2023-01-06 18:02:17 +00:00
|
|
|
class ActionCallback(Contextualized, t.Generic[T]):
|
2022-02-07 17:11:43 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
2023-01-06 18:02:17 +00:00
|
|
|
func: t.Callable[T, None],
|
2022-02-07 17:11:43 +00:00
|
|
|
priority: t.Optional[int] = None,
|
|
|
|
):
|
|
|
|
super().__init__()
|
|
|
|
self.func = func
|
2022-11-08 15:09:16 +00:00
|
|
|
self.priority = priority or priorities.DEFAULT
|
2022-02-07 17:11:43 +00:00
|
|
|
|
|
|
|
def do(
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
self,
|
2023-01-06 18:02:17 +00:00
|
|
|
*args: T.args,
|
|
|
|
**kwargs: T.kwargs,
|
2022-02-07 17:11:43 +00:00
|
|
|
) -> None:
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
self.func(*args, **kwargs)
|
2022-02-07 17:11:43 +00:00
|
|
|
|
|
|
|
|
2023-01-06 18:02:17 +00:00
|
|
|
class Action(t.Generic[T]):
|
2022-02-07 17:11:43 +00:00
|
|
|
"""
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
Action hooks have callbacks that are triggered independently from one another.
|
|
|
|
|
|
|
|
Several actions are defined across the codebase. Each action is given a unique name.
|
|
|
|
To each action are associated zero or more callbacks, sorted by priority.
|
|
|
|
|
|
|
|
This is the typical action lifecycle:
|
|
|
|
|
2023-01-06 18:02:17 +00:00
|
|
|
1. Create an action with method :py:meth:`get`.
|
|
|
|
2. Add callbacks with method :py:meth:`add`.
|
|
|
|
3. Call the action callbacks with method :py:meth:`do`.
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
|
2023-01-06 18:02:17 +00:00
|
|
|
The ``P`` type parameter of the Action class corresponds to the expected signature of
|
|
|
|
the action callbacks. For instance, ``Action[[str, int]]`` means that the action
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
callbacks are expected to take two arguments: one string and one integer.
|
|
|
|
|
|
|
|
This strong typing makes it easier for plugin developers to quickly check whether they are adding and calling action callbacks correctly.
|
2022-02-07 17:11:43 +00:00
|
|
|
"""
|
|
|
|
|
refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
INDEX: dict[str, "Action[t.Any]"] = {}
|
2022-02-07 17:11:43 +00:00
|
|
|
|
|
|
|
def __init__(self, name: str) -> None:
|
|
|
|
self.name = name
|
2023-01-06 18:02:17 +00:00
|
|
|
self.callbacks: list[ActionCallback[T]] = []
|
2022-02-07 17:11:43 +00:00
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
return f"{self.__class__.__name__}('{self.name}')"
|
|
|
|
|
|
|
|
@classmethod
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
def get(cls, name: str) -> "Action[t.Any]":
|
2022-02-07 17:11:43 +00:00
|
|
|
"""
|
|
|
|
Get an existing action with the given name from the index, or create one.
|
|
|
|
"""
|
|
|
|
return cls.INDEX.setdefault(name, cls(name))
|
|
|
|
|
|
|
|
def add(
|
|
|
|
self, priority: t.Optional[int] = None
|
2023-01-06 18:02:17 +00:00
|
|
|
) -> t.Callable[[t.Callable[T, None]], t.Callable[T, None]]:
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
"""
|
2023-01-06 18:02:17 +00:00
|
|
|
Decorator to add a callback to an action.
|
|
|
|
|
|
|
|
:param priority: optional order in which the action callbacks are performed. Higher
|
|
|
|
values mean that they will be performed later. The default value is
|
|
|
|
``priorities.DEFAULT`` (10). Actions that should be performed last should have a
|
|
|
|
priority of 100.
|
|
|
|
|
|
|
|
Usage::
|
|
|
|
|
|
|
|
@my_action.add("my-action")
|
|
|
|
def do_stuff(my_arg):
|
|
|
|
...
|
|
|
|
|
|
|
|
The ``do_stuff`` callback function will be called on ``my_action.do(some_arg)``.
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
|
2023-01-06 18:02:17 +00:00
|
|
|
The signature of each callback action function must match the signature of the
|
|
|
|
corresponding :py:meth:`do` method. Callback action functions are not supposed
|
|
|
|
to return any value. Returned values will be ignored.
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
"""
|
|
|
|
|
2023-01-06 18:02:17 +00:00
|
|
|
def inner(func: t.Callable[T, None]) -> t.Callable[T, None]:
|
2022-02-07 17:11:43 +00:00
|
|
|
callback = ActionCallback(func, priority=priority)
|
2022-11-08 15:09:16 +00:00
|
|
|
priorities.insert_callback(callback, self.callbacks)
|
2022-02-07 17:11:43 +00:00
|
|
|
return func
|
|
|
|
|
|
|
|
return inner
|
|
|
|
|
|
|
|
def do(
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
self,
|
2023-01-06 18:02:17 +00:00
|
|
|
*args: T.args,
|
|
|
|
**kwargs: T.kwargs,
|
2022-02-07 17:11:43 +00:00
|
|
|
) -> None:
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
"""
|
2023-01-06 18:02:17 +00:00
|
|
|
Run the action callbacks in sequence.
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
|
2023-01-06 18:02:17 +00:00
|
|
|
:param name: name of the action for which callbacks will be run.
|
|
|
|
|
|
|
|
Extra ``*args`` and ``*kwargs`` arguments will be passed as-is to
|
|
|
|
callback functions.
|
|
|
|
|
|
|
|
Callbacks are executed in order of priority, then FIFO. There is no error
|
|
|
|
management here: a single exception will cause all following callbacks
|
|
|
|
not to be run and the exception will be bubbled up.
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
"""
|
|
|
|
self.do_from_context(None, *args, **kwargs)
|
|
|
|
|
|
|
|
def do_from_context(
|
|
|
|
self,
|
|
|
|
context: t.Optional[str],
|
2023-01-06 18:02:17 +00:00
|
|
|
*args: T.args,
|
|
|
|
**kwargs: T.kwargs,
|
2022-02-07 17:11:43 +00:00
|
|
|
) -> None:
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
"""
|
2023-01-06 18:02:17 +00:00
|
|
|
Same as :py:meth:`do` but only run the callbacks from a given context.
|
|
|
|
|
|
|
|
:param name: name of the action for which callbacks will be run.
|
|
|
|
:param context: limit the set of callback actions to those that
|
|
|
|
were declared within a certain context (see
|
|
|
|
:py:func:`tutor.core.hooks.contexts.enter`).
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
"""
|
2022-02-07 17:11:43 +00:00
|
|
|
for callback in self.callbacks:
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
if callback.is_in_context(context):
|
|
|
|
try:
|
|
|
|
callback.do(
|
|
|
|
*args,
|
|
|
|
**kwargs,
|
|
|
|
)
|
|
|
|
except:
|
|
|
|
sys.stderr.write(
|
|
|
|
f"Error applying action '{self.name}': func={callback.func} contexts={callback.contexts}'\n"
|
|
|
|
)
|
|
|
|
raise
|
2022-02-07 17:11:43 +00:00
|
|
|
|
|
|
|
def clear(self, context: t.Optional[str] = None) -> None:
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
"""
|
|
|
|
Clear all or part of the callbacks associated to an action
|
|
|
|
|
2023-01-06 18:02:17 +00:00
|
|
|
:param name: name of the action callbacks to remove.
|
|
|
|
:param context: when defined, will clear only the actions that were
|
|
|
|
created within that context.
|
|
|
|
|
|
|
|
Actions will be removed from the list of callbacks and will no longer be
|
|
|
|
run in :py:meth:`do` calls.
|
|
|
|
|
|
|
|
This function should almost certainly never be called by plugins. It is
|
|
|
|
mostly useful to disable some plugins at runtime or in unit tests.
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
"""
|
2022-02-07 17:11:43 +00:00
|
|
|
self.callbacks = [
|
|
|
|
callback
|
|
|
|
for callback in self.callbacks
|
|
|
|
if not callback.is_in_context(context)
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2023-01-06 18:02:17 +00:00
|
|
|
class ActionTemplate(t.Generic[T]):
|
2022-02-07 17:11:43 +00:00
|
|
|
"""
|
|
|
|
Action templates are for actions for which the name needs to be formatted
|
|
|
|
before the action can be applied.
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
|
|
|
|
Action templates can generate different :py:class:`Action` objects for which the
|
|
|
|
name matches a certain template.
|
2023-01-06 18:02:17 +00:00
|
|
|
|
|
|
|
Templated actions must be formatted with ``(*args)`` before being applied. For example::
|
|
|
|
|
|
|
|
action_template = ActionTemplate("namespace:{0}")
|
|
|
|
|
|
|
|
# Return the action named "namespace:name"
|
|
|
|
my_action = action_template("name")
|
|
|
|
|
|
|
|
@my_action.add()
|
|
|
|
def my_callback():
|
|
|
|
...
|
|
|
|
|
|
|
|
my_action.do()
|
2022-02-07 17:11:43 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, name: str):
|
|
|
|
self.template = name
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
return f"{self.__class__.__name__}('{self.template}')"
|
|
|
|
|
2023-01-06 18:02:17 +00:00
|
|
|
def __call__(self, *args: t.Any, **kwargs: t.Any) -> Action[T]:
|
|
|
|
name = self.template.format(*args, **kwargs)
|
|
|
|
action: Action[T] = Action.get(name)
|
|
|
|
return action
|
2022-02-07 17:11:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
# Syntactic sugar
|
|
|
|
get = Action.get
|
|
|
|
|
|
|
|
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
def get_template(name: str) -> ActionTemplate[t.Any]:
|
2022-02-07 17:11:43 +00:00
|
|
|
"""
|
|
|
|
Create an action with a template name.
|
|
|
|
"""
|
|
|
|
return ActionTemplate(name)
|
|
|
|
|
|
|
|
|
|
|
|
def add(
|
2022-11-08 15:09:16 +00:00
|
|
|
name: str, priority: t.Optional[int] = None
|
2023-01-06 18:02:17 +00:00
|
|
|
) -> t.Callable[[t.Callable[T, None]], t.Callable[T, None]]:
|
2022-02-07 17:11:43 +00:00
|
|
|
"""
|
|
|
|
Decorator to add a callback action associated to a name.
|
|
|
|
"""
|
|
|
|
return get(name).add(priority=priority)
|
|
|
|
|
|
|
|
|
|
|
|
def do(
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
name: str,
|
2023-01-06 18:02:17 +00:00
|
|
|
*args: T.args,
|
|
|
|
**kwargs: T.kwargs,
|
2022-02-07 17:11:43 +00:00
|
|
|
) -> None:
|
|
|
|
"""
|
|
|
|
Run action callbacks associated to a name/context.
|
|
|
|
"""
|
2023-01-06 18:02:17 +00:00
|
|
|
action: Action[T] = Action.get(name)
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
action.do(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
def do_from_context(
|
|
|
|
context: str,
|
|
|
|
name: str,
|
2023-01-06 18:02:17 +00:00
|
|
|
*args: T.args,
|
|
|
|
**kwargs: T.kwargs,
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
) -> None:
|
|
|
|
"""
|
|
|
|
Same as :py:func:`do` but only run the callbacks that were created in a given context.
|
|
|
|
"""
|
2023-01-06 18:02:17 +00:00
|
|
|
action: Action[T] = Action.get(name)
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
action.do_from_context(context, *args, **kwargs)
|
2022-02-07 17:11:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
def clear_all(context: t.Optional[str] = None) -> None:
|
|
|
|
"""
|
|
|
|
Clear any previously defined filter with the given context.
|
|
|
|
|
|
|
|
This will call :py:func:`clear` with all action names.
|
|
|
|
"""
|
|
|
|
for name in Action.INDEX:
|
|
|
|
clear(name, context=context)
|
|
|
|
|
|
|
|
|
|
|
|
def clear(name: str, context: t.Optional[str] = None) -> None:
|
|
|
|
"""
|
|
|
|
Clear any previously defined action with the given name and context.
|
|
|
|
"""
|
feat: strongly typed hooks
Now that the mypy bugs have been resolved, we are able to define more precisely
and cleanly the types of Actions and Filters.
Moreover, can now strongly type named actions and hooks (in consts.py). With
such a strong typing, we get early alerts of hooks called with incorrect
arguments, which is nothing short of awesome :)
This change breaks the hooks API by removing the `context=...` argument. The
reason for that is that we cannot insert arbitrary arguments between `P.args,
P.kwargs`: https://peps.python.org/pep-0612/#the-components-of-a-paramspec
> A function declared as def inner(a: A, b: B, *args: P.args, **kwargs:
> P.kwargs) -> R has type Callable[Concatenate[A, B, P], R]. Placing
> keyword-only parameters between the *args and **kwargs is forbidden.
Getting the documentation to build in nitpicky mode is quite difficult... We
need to add `nitpick_ignore` to the docs conf.py, otherwise sphinx complains
about many missing class references. This, despite upgrading almost all doc
requirements (except docutils).
2022-10-06 10:05:01 +00:00
|
|
|
Action.get(name).clear(context=context)
|