Skip to content

Commit

Permalink
squashme fixes
Browse files Browse the repository at this point in the history
At this point the docs build correctly with python 3.8, but not with python
3.10. I have already spent too much time on this problem and I don't know how
to improve it. Sphinx is making me mad. We are at a point where we have a
viable conf.py file and I'd rather not change it too much.

Here are the errors on python 3.10:

    /home/data/regis/projets/overhang/repos/overhang/tutor/tutor/hooks/catalog.py:docstring of tutor.hooks.Actions.COMPOSE_PROJECT_STARTED:1: WARNING: py:class reference target not found: tutor.core.hooks.actions.Action[(<class 'str'>, typing.Dict[str, typing.Union[str, float, NoneType, bool, typing.List[str], typing.List[typing.Any], typing.Dict[str, typing.Any], typing.Dict[typing.Any, typing.Any]]], <class 'str'>)]
    /home/data/regis/projets/overhang/repos/overhang/tutor/tutor/hooks/catalog.py:docstring of tutor.hooks.Actions.DO_JOB:1: WARNING: py:class reference target not found: tutor.core.hooks.actions.Action[(<class 'str'>, typing.Any)]
    /home/data/regis/projets/overhang/repos/overhang/tutor/tutor/hooks/catalog.py:docstring of tutor.hooks.Actions.PLUGIN_UNLOADED:1: WARNING: py:class reference target not found: tutor.core.hooks.actions.Action[(<class 'str'>, <class 'str'>, typing.Dict[str, typing.Union[str, float, NoneType, bool, typing.List[str], typing.List[typing.Any], typing.Dict[str, typing.Any], typing.Dict[typing.Any, typing.Any]]])]
    /home/data/regis/projets/overhang/repos/overhang/tutor/tutor/hooks/catalog.py:docstring of tutor.hooks.Actions.PROJECT_ROOT_READY:1: WARNING: py:class reference target not found: tutor.core.hooks.actions.Action[(<class 'str'>,)]
    /home/data/regis/projets/overhang/repos/overhang/tutor/tutor/hooks/catalog.py:docstring of tutor.hooks.Filters.COMPOSE_MOUNTS:1: WARNING: py:class reference target not found: tutor.core.hooks.filters.Filter[list[tuple[str, str]], (<class 'str'>,)]

This PR addresses this developer experience issue: openedx-unsupported/wg-developer-experience#125
  • Loading branch information
regisb committed Jan 27, 2023
1 parent 4d2fb85 commit 842bc16
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 115 deletions.
53 changes: 27 additions & 26 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import io
import os
import sys
Expand All @@ -9,8 +11,8 @@
# -- Project information -----------------------------------------------------

project = "Tutor"
copyright = ""
author = "Overhang.io"
copyright = "" # pylint: disable=redefined-builtin
author = "Overhang.IO"

# The short X.Y version
version = ""
Expand All @@ -35,33 +37,34 @@
# To make matters worse, some ignores are only required for some versions of Python,
# from 3.7 to 3.10...
nitpick_ignore = [
("py:class", "Config"),
# Sphinx does not handle ParamSpec arguments
("py:class", "T.args"),
("py:class", "T.kwargs"),
("py:class", "T2.args"),
("py:class", "T2.kwargs"),
# Sphinx doesn't know about the following classes
("py:class", "click.Command"),
("py:class", "click.core.Command"),
("py:class", "E"),
("py:class", "~E"),
("py:class", "tutor.core.hooks.filters.E"),
("py:class", "P"),
("py:class", "~P"),
("py:class", "typing.~P"),
("py:class", "P.args"),
("py:class", "P.kwargs"),
("py:class", "tutor.core.hooks.actions.P"),
("py:class", "tutor.core.hooks.filters.P"),
("py:class", "T"),
("py:class", "tutor.core.hooks.filters.T"),
("py:class", "t.Any"),
("py:class", "t.Callable"),
("py:class", "t.Iterator"),
("py:class", "t.Optional"),
("py:class", "NoneType"),
# python 3.7
("py:class", "Concatenate"),
# python 3.10
("py:class", "NoneType"),
("py:class", "click.core.Command"),
]
autodoc_type_aliases = {
# required for python 3.10
"P": "tutor.core.hooks.filters.P"
# Resolve type aliases here
# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_type_aliases
autodoc_type_aliases: dict[str, str] = {
"T1": "tutor.core.hooks.filters.T1",
"L": "tutor.core.hooks.filters.L",
# python 3.10
"T": "tutor.core.hooks.actions.T",
"T2": "tutor.core.hooks.filters.T2",
}


# -- Sphinx-Click configuration
# https://sphinx-click.readthedocs.io/
extensions.append("sphinx_click")
Expand Down Expand Up @@ -103,13 +106,11 @@
with io.open(
os.path.join(here, "..", "tutor", "__about__.py"), "rt", encoding="utf-8"
) as f:
# pylint: disable=exec-used
exec(f.read(), about)
rst_prolog = """
.. |tutor_version| replace:: {}
""".format(
about["__version__"],
)

rst_prolog = f"""
.. |tutor_version| replace:: {about["__version__"]}
"""

# Custom directives
def youtube(
Expand Down
4 changes: 4 additions & 0 deletions docs/reference/api/hooks/actions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ Actions are one of the two types of hooks (the other being :ref:`filters`) that

.. autoclass:: tutor.core.hooks.ActionTemplate
:members:

.. The following are only to ensure that the docs build without warnings
.. class:: tutor.core.hooks.actions.T
.. class:: tutor.types.Config
9 changes: 0 additions & 9 deletions docs/reference/api/hooks/catalog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,11 @@ Tutor can be extended by making use of "hooks". Hooks are either "actions" or "f

The internal Python implementation of hooks is documented :ref:`here <hooks_api>`.

Actions
=======

.. autoclass:: tutor.hooks.Actions
:members:

Filters
=======

.. autoclass:: tutor.hooks.Filters
:members:

Contexts
========

.. autoclass:: tutor.hooks.Contexts
:members:
5 changes: 5 additions & 0 deletions docs/reference/api/hooks/filters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ Filters are one of the two types of hooks (the other being :ref:`actions`) that

.. autoclass:: tutor.core.hooks.FilterTemplate
:members:

.. The following are only to ensure that the docs build without warnings
.. class:: tutor.core.hooks.filters.T1
.. class:: tutor.core.hooks.filters.T2
.. class:: tutor.core.hooks.filters.L
6 changes: 3 additions & 3 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#
# This file is autogenerated by pip-compile with Python 3.8
# by the following command:
# This file is autogenerated by pip-compile with python 3.8
# To update, run:
#
# pip-compile requirements/dev.in
#
Expand Down Expand Up @@ -62,7 +62,7 @@ idna==3.4
# via
# -r requirements/base.txt
# requests
importlib-metadata==5.1.0
importlib-metadata==6.0.0
# via
# keyring
# twine
Expand Down
54 changes: 30 additions & 24 deletions tutor/core/hooks/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@
from . import priorities
from .contexts import Contextualized

P = ParamSpec("P")
#: Action generic signature.
T = ParamSpec("T")

# Similarly to CallableFilter, it should be possible to create a CallableAction alias in
# the future.
# CallableAction = t.Callable[P, None]
# CallableAction = t.Callable[T, None]


class ActionCallback(Contextualized, t.Generic[P]):
class ActionCallback(Contextualized, t.Generic[T]):
def __init__(
self,
func: t.Callable[P, None],
func: t.Callable[T, None],
priority: t.Optional[int] = None,
):
super().__init__()
Expand All @@ -29,13 +31,13 @@ def __init__(

def do(
self,
*args: P.args,
**kwargs: P.kwargs,
*args: T.args,
**kwargs: T.kwargs,
) -> None:
self.func(*args, **kwargs)


class Action(t.Generic[P]):
class Action(t.Generic[T]):
"""
Action hooks have callbacks that are triggered independently from one another.
Expand All @@ -59,7 +61,7 @@ class Action(t.Generic[P]):

def __init__(self, name: str) -> None:
self.name = name
self.callbacks: list[ActionCallback[P]] = []
self.callbacks: list[ActionCallback[T]] = []

def __repr__(self) -> str:
return f"{self.__class__.__name__}('{self.name}')"
Expand All @@ -73,7 +75,7 @@ def get(cls, name: str) -> "Action[t.Any]":

def add(
self, priority: t.Optional[int] = None
) -> t.Callable[[t.Callable[P, None]], t.Callable[P, None]]:
) -> t.Callable[[t.Callable[T, None]], t.Callable[T, None]]:
"""
Decorator to add a callback to an action.
Expand All @@ -95,7 +97,7 @@ def do_stuff(my_arg):
to return any value. Returned values will be ignored.
"""

def inner(func: t.Callable[P, None]) -> t.Callable[P, None]:
def inner(func: t.Callable[T, None]) -> t.Callable[T, None]:
callback = ActionCallback(func, priority=priority)
priorities.insert_callback(callback, self.callbacks)
return func
Expand All @@ -104,8 +106,8 @@ def inner(func: t.Callable[P, None]) -> t.Callable[P, None]:

def do(
self,
*args: P.args,
**kwargs: P.kwargs,
*args: T.args,
**kwargs: T.kwargs,
) -> None:
"""
Run the action callbacks in sequence.
Expand All @@ -124,8 +126,8 @@ def do(
def do_from_context(
self,
context: t.Optional[str],
*args: P.args,
**kwargs: P.kwargs,
*args: T.args,
**kwargs: T.kwargs,
) -> None:
"""
Same as :py:meth:`do` but only run the callbacks from a given context.
Expand Down Expand Up @@ -169,7 +171,7 @@ def clear(self, context: t.Optional[str] = None) -> None:
]


class ActionTemplate(t.Generic[P]):
class ActionTemplate(t.Generic[T]):
"""
Action templates are for actions for which the name needs to be formatted
before the action can be applied.
Expand All @@ -180,6 +182,8 @@ class ActionTemplate(t.Generic[P]):
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()
Expand All @@ -195,8 +199,10 @@ def __init__(self, name: str):
def __repr__(self) -> str:
return f"{self.__class__.__name__}('{self.template}')"

def __call__(self, *args: t.Any, **kwargs: t.Any) -> Action[P]:
return get(self.template.format(*args, **kwargs))
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


# Syntactic sugar
Expand All @@ -212,7 +218,7 @@ def get_template(name: str) -> ActionTemplate[t.Any]:

def add(
name: str, priority: t.Optional[int] = None
) -> t.Callable[[t.Callable[P, None]], t.Callable[P, None]]:
) -> t.Callable[[t.Callable[T, None]], t.Callable[T, None]]:
"""
Decorator to add a callback action associated to a name.
"""
Expand All @@ -221,26 +227,26 @@ def add(

def do(
name: str,
*args: P.args,
**kwargs: P.kwargs,
*args: T.args,
**kwargs: T.kwargs,
) -> None:
"""
Run action callbacks associated to a name/context.
"""
action: Action[P] = Action.get(name)
action: Action[T] = Action.get(name)
action.do(*args, **kwargs)


def do_from_context(
context: str,
name: str,
*args: P.args,
**kwargs: P.kwargs,
*args: T.args,
**kwargs: T.kwargs,
) -> None:
"""
Same as :py:func:`do` but only run the callbacks that were created in a given context.
"""
action: Action[P] = Action.get(name)
action: Action[T] = Action.get(name)
action.do_from_context(context, *args, **kwargs)


Expand Down
Loading

0 comments on commit 842bc16

Please sign in to comment.