1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-23 11:34:18 +00:00

✏️ Make commands coroutines

This commit is contained in:
Steffo 2020-12-07 19:26:32 +01:00
parent b8607edb56
commit eb90daa241
3 changed files with 24 additions and 12 deletions

View file

@ -40,11 +40,11 @@ def parameter_to_field(param: inspect.Parameter, **kwargs) -> Tuple[type, pydant
def signature_to_model(f: Callable, __config__: pydantic.BaseConfig = ModelConfig, **extra_params): def signature_to_model(f: Callable, __config__: pydantic.BaseConfig = ModelConfig, **extra_params):
""" """
Convert the signature of a function to a pydantic model. Convert the signature of a async function to a pydantic model.
Arguments starting with ``_`` are ignored. Arguments starting with ``_`` are ignored.
:param f: The function to use the signature of. :param f: The async function to use the signature of.
:param __config__: The config the pydantic model should use. :param __config__: The config the pydantic model should use.
:param extra_params: Extra parameters to be added to the model. :param extra_params: Extra parameters to be added to the model.
:return: The created pydantic model. :return: The created pydantic model.

View file

@ -18,7 +18,8 @@ class EngineerRouter:
:param name: The name of the command (``start``, ``settings``, etc). If not specified, it will use the name :param name: The name of the command (``start``, ``settings``, etc). If not specified, it will use the name
of the wrapped function. of the wrapped function.
:param f: The function that should be executed when the command is called. It must have a ``.model`` property. :param f: The async function that should be executed when the command is called.
It must have a ``.model`` property.
.. seealso:: :meth:`.command`, :func:`.params.function_with_model` .. seealso:: :meth:`.command`, :func:`.params.function_with_model`
""" """
@ -33,13 +34,13 @@ class EngineerRouter:
.. code-block:: python .. code-block:: python
@command() @command()
def ping(): async def ping():
print("Pong!") print("Pong!")
.. code-block:: python .. code-block:: python
@command(name="ping") @command(name="ping")
def xyzzy(): async def xyzzy():
print("Pong!") print("Pong!")
:param name: The name of the command (``start``, ``settings``, etc). If not specified, it will use the name :param name: The name of the command (``start``, ``settings``, etc). If not specified, it will use the name
@ -61,7 +62,18 @@ class EngineerRouter:
return decorator return decorator
def call(self, __name: str, **kwargs): async def call(self, __name: str, **kwargs) -> Any:
"""
Call the command with the specified name using the passed kwargs.
:param __name: The name of the function.
:param kwargs: Kwargs to pass to the desired function:
- Kwargs starting with ``__`` are never passed to the function.
- Kwargs starting with ``_`` are passed as they are.
- Other kwargs are validated by the function's :mod:`pydantic` model.
:return: The return value of the function.
:raises pydantic.ValidationError: If the kwargs do not pass the :mod:`pydantic` model validation.
"""
model_params = {} model_params = {}
extra_params = {} extra_params = {}
for key, value in kwargs.items(): for key, value in kwargs.items():
@ -74,7 +86,7 @@ class EngineerRouter:
# noinspection PyPep8Naming # noinspection PyPep8Naming
Model: Type[pydantic.BaseModel] = f.model Model: Type[pydantic.BaseModel] = f.model
model: pydantic.BaseModel = Model(**model_params) model: pydantic.BaseModel = Model(**model_params)
return f(**model.dict(), **extra_params) return await f(**model.dict(), **extra_params)
__all__ = ( __all__ = (

View file

@ -6,14 +6,14 @@ import royalnet.engineer as re
@pytest.fixture @pytest.fixture
def a_random_function(): async def my_async_function():
def f(*, big_f: str, _hidden: int) -> str: def f(*, big_f: str, _hidden: int) -> str:
return big_f return big_f
return f return f
def test_parameter_to_field(a_random_function): def test_parameter_to_field(my_async_function):
signature = inspect.signature(a_random_function) signature = inspect.signature(my_async_function)
parameter = signature.parameters["big_f"] parameter = signature.parameters["big_f"]
t, fieldinfo = re.parameter_to_field(parameter) t, fieldinfo = re.parameter_to_field(parameter)
assert isinstance(fieldinfo, pydantic.fields.FieldInfo) assert isinstance(fieldinfo, pydantic.fields.FieldInfo)
@ -21,8 +21,8 @@ def test_parameter_to_field(a_random_function):
assert fieldinfo.title == parameter.name == "big_f" assert fieldinfo.title == parameter.name == "big_f"
def test_signature_to_model(a_random_function): def test_signature_to_model(my_async_function):
Model = re.signature_to_model(a_random_function) Model = re.signature_to_model(my_async_function)
assert callable(Model) assert callable(Model)
model = Model(big_f="banana") model = Model(big_f="banana")