mirror of
https://github.com/ChristianLight/tutor.git
synced 2024-11-14 09:14:14 +00:00
feat: filter priorities
Nothing revolutionary here, we just implement the same priority queue that existed in actions. It will be necessary to trigger init tasks in the right order.
This commit is contained in:
parent
7879506910
commit
e734f52f07
@ -8,6 +8,7 @@ will be backported to the master branch at every major release.
|
||||
When backporting changes to master, we should keep only the entries that correspond to user-
|
||||
facing changes.
|
||||
-->
|
||||
- [Feature] Implement hook filter priorities, which work like action priorities. (by @regisb)
|
||||
- 💥[Improvement] Remove the `local/dev bindmount` commands, which have been marked as deprecated for some time. The `--mount` option should be used instead.
|
||||
- 💥[Bugfix] Fix local installation requirements. Plugins that implemented the "openedx-dockerfile-post-python-requirements" patch and that needed access to the edx-platform repo will no longer work. Instead, these plugins should implement the "openedx-dockerfile-pre-assets" patch. This scenario should be very rare, though. (by @regisb)
|
||||
- 💥[Improvement] Rename the implementation of tutor <mode> quickstart to tutor <mode> launch. (by @Carlos-Muniz)
|
||||
|
@ -4,14 +4,13 @@ __license__ = "Apache 2.0"
|
||||
import sys
|
||||
import typing as t
|
||||
|
||||
from . import priorities
|
||||
from .contexts import Contextualized
|
||||
|
||||
# Similarly to CallableFilter, it should be possible to refine the definition of
|
||||
# CallableAction in the future.
|
||||
CallableAction = t.Callable[..., None]
|
||||
|
||||
DEFAULT_PRIORITY = 10
|
||||
|
||||
|
||||
class ActionCallback(Contextualized):
|
||||
def __init__(
|
||||
@ -21,7 +20,7 @@ class ActionCallback(Contextualized):
|
||||
):
|
||||
super().__init__()
|
||||
self.func = func
|
||||
self.priority = priority or DEFAULT_PRIORITY
|
||||
self.priority = priority or priorities.DEFAULT
|
||||
|
||||
def do(
|
||||
self, *args: t.Any, context: t.Optional[str] = None, **kwargs: t.Any
|
||||
@ -57,15 +56,7 @@ class Action:
|
||||
) -> t.Callable[[CallableAction], CallableAction]:
|
||||
def inner(func: CallableAction) -> CallableAction:
|
||||
callback = ActionCallback(func, priority=priority)
|
||||
# I wish we could use bisect.insort_right here but the `key=` parameter
|
||||
# is unsupported in Python 3.9
|
||||
position = 0
|
||||
while (
|
||||
position < len(self.callbacks)
|
||||
and self.callbacks[position].priority <= callback.priority
|
||||
):
|
||||
position += 1
|
||||
self.callbacks.insert(position, callback)
|
||||
priorities.insert_callback(callback, self.callbacks)
|
||||
return func
|
||||
|
||||
return inner
|
||||
@ -128,8 +119,7 @@ def get_template(name: str) -> ActionTemplate:
|
||||
|
||||
|
||||
def add(
|
||||
name: str,
|
||||
priority: t.Optional[int] = None,
|
||||
name: str, priority: t.Optional[int] = None
|
||||
) -> t.Callable[[CallableAction], CallableAction]:
|
||||
"""
|
||||
Decorator to add a callback action associated to a name.
|
||||
@ -139,8 +129,8 @@ def add(
|
||||
:py:class:`tutor.hooks.Actions` instead.
|
||||
:param priority: optional order in which the action callbacks are performed. Higher
|
||||
values mean that they will be performed later. The default value is
|
||||
``DEFAULT_PRIORITY`` (10). Actions that should be performed last should
|
||||
have a priority of 100.
|
||||
``priorities.DEFAULT`` (10). Actions that should be performed last should have a
|
||||
priority of 100.
|
||||
|
||||
Usage::
|
||||
|
||||
|
@ -4,7 +4,7 @@ __license__ = "Apache 2.0"
|
||||
import sys
|
||||
import typing as t
|
||||
|
||||
from . import contexts
|
||||
from . import contexts, priorities
|
||||
|
||||
# For now, this signature is not very restrictive. In the future, we could improve it by writing:
|
||||
#
|
||||
@ -22,9 +22,10 @@ CallableFilter = t.Callable[..., t.Any]
|
||||
|
||||
|
||||
class FilterCallback(contexts.Contextualized):
|
||||
def __init__(self, func: CallableFilter):
|
||||
def __init__(self, func: CallableFilter, priority: t.Optional[int] = None):
|
||||
super().__init__()
|
||||
self.func = func
|
||||
self.priority = priority or priorities.DEFAULT
|
||||
|
||||
def apply(
|
||||
self, value: T, *args: t.Any, context: t.Optional[str] = None, **kwargs: t.Any
|
||||
@ -36,7 +37,7 @@ class FilterCallback(contexts.Contextualized):
|
||||
|
||||
class Filter:
|
||||
"""
|
||||
Each filter is associated to a name and a list of callbacks.
|
||||
Each filter is associated to a name and a list of callbacks, sorted by priority.
|
||||
"""
|
||||
|
||||
INDEX: t.Dict[str, "Filter"] = {}
|
||||
@ -55,18 +56,21 @@ class Filter:
|
||||
"""
|
||||
return cls.INDEX.setdefault(name, cls(name))
|
||||
|
||||
def add(self) -> t.Callable[[CallableFilter], CallableFilter]:
|
||||
def add(
|
||||
self, priority: t.Optional[int] = None
|
||||
) -> t.Callable[[CallableFilter], CallableFilter]:
|
||||
def inner(func: CallableFilter) -> CallableFilter:
|
||||
self.callbacks.append(FilterCallback(func))
|
||||
callback = FilterCallback(func, priority=priority)
|
||||
priorities.insert_callback(callback, self.callbacks)
|
||||
return func
|
||||
|
||||
return inner
|
||||
|
||||
def add_item(self, item: T) -> None:
|
||||
self.add_items([item])
|
||||
def add_item(self, item: T, priority: t.Optional[int] = None) -> None:
|
||||
self.add_items([item], priority=priority)
|
||||
|
||||
def add_items(self, items: t.List[T]) -> None:
|
||||
@self.add()
|
||||
def add_items(self, items: t.List[T], priority: t.Optional[int] = None) -> None:
|
||||
@self.add(priority=priority)
|
||||
def callback(value: t.List[T], *_args: t.Any, **_kwargs: t.Any) -> t.List[T]:
|
||||
return value + items
|
||||
|
||||
@ -153,11 +157,17 @@ def get_template(name: str) -> FilterTemplate:
|
||||
return FilterTemplate(name)
|
||||
|
||||
|
||||
def add(name: str) -> t.Callable[[CallableFilter], CallableFilter]:
|
||||
def add(
|
||||
name: str, priority: t.Optional[int] = None
|
||||
) -> t.Callable[[CallableFilter], CallableFilter]:
|
||||
"""
|
||||
Decorator for functions that will be applied to a single named filter.
|
||||
|
||||
:param name: name of the filter to which the decorated function should be added.
|
||||
:param str name: name of the filter to which the decorated function should be added.
|
||||
:param int priority: optional order in which the filter callbacks are called. Higher
|
||||
values mean that they will be performed later. The default value is
|
||||
``priorities.DEFAULT`` (10). Filters that should be called last should have a
|
||||
priority of 100.
|
||||
|
||||
The return value of each filter function callback will be passed as the first argument to the next one.
|
||||
|
||||
@ -174,15 +184,16 @@ def add(name: str) -> t.Callable[[CallableFilter], CallableFilter]:
|
||||
# After filters have been created, the result of calling all filter callbacks is obtained by running:
|
||||
hooks.filters.apply("my-filter", initial_value, some_other_argument_value)
|
||||
"""
|
||||
return Filter.get(name).add()
|
||||
return Filter.get(name).add(priority=priority)
|
||||
|
||||
|
||||
def add_item(name: str, item: T) -> None:
|
||||
def add_item(name: str, item: T, priority: t.Optional[int] = None) -> None:
|
||||
"""
|
||||
Convenience function to add a single item to a filter that returns a list of items.
|
||||
|
||||
:param name: filter name.
|
||||
:param object item: item that will be appended to the resulting list.
|
||||
:param int priority: see :py:data:`add`.
|
||||
|
||||
Usage::
|
||||
|
||||
@ -193,10 +204,10 @@ def add_item(name: str, item: T) -> None:
|
||||
|
||||
assert ["item1", "item2"] == hooks.filters.apply("my-filter", [])
|
||||
"""
|
||||
get(name).add_item(item)
|
||||
get(name).add_item(item, priority=priority)
|
||||
|
||||
|
||||
def add_items(name: str, items: t.List[T]) -> None:
|
||||
def add_items(name: str, items: t.List[T], priority: t.Optional[int] = None) -> None:
|
||||
"""
|
||||
Convenience function to add multiple item to a filter that returns a list of items.
|
||||
|
||||
@ -211,7 +222,7 @@ def add_items(name: str, items: t.List[T]) -> None:
|
||||
|
||||
assert ["item1", "item2"] == hooks.filters.apply("my-filter", [])
|
||||
"""
|
||||
get(name).add_items(items)
|
||||
get(name).add_items(items, priority=priority)
|
||||
|
||||
|
||||
def iterate(
|
||||
|
25
tutor/hooks/priorities.py
Normal file
25
tutor/hooks/priorities.py
Normal file
@ -0,0 +1,25 @@
|
||||
import typing as t
|
||||
|
||||
from typing_extensions import Protocol
|
||||
|
||||
HIGH = 5
|
||||
DEFAULT = 10
|
||||
LOW = 50
|
||||
|
||||
|
||||
class PrioritizedCallback(Protocol):
|
||||
priority: int
|
||||
|
||||
|
||||
TPrioritized = t.TypeVar("TPrioritized", bound=PrioritizedCallback)
|
||||
|
||||
|
||||
def insert_callback(callback: TPrioritized, callbacks: t.List[TPrioritized]) -> None:
|
||||
# I wish we could use bisect.insort_right here but the `key=` parameter
|
||||
# is unsupported in Python 3.9
|
||||
position = 0
|
||||
while (
|
||||
position < len(callbacks) and callbacks[position].priority <= callback.priority
|
||||
):
|
||||
position += 1
|
||||
callbacks.insert(position, callback)
|
Loading…
Reference in New Issue
Block a user