diff --git a/src/pydase/utils/serializer.py b/src/pydase/utils/serializer.py index 9e364a7..2dad78e 100644 --- a/src/pydase/utils/serializer.py +++ b/src/pydase/utils/serializer.py @@ -148,63 +148,72 @@ class Serializer: "doc": doc, } + @staticmethod + def _get_default_value_of_method_arg( + obj: Callable[..., Any], arg_name: str, arg_value: inspect.Parameter + ) -> Any: + default_value = arg_value.default + if default_value is None: + raise KeywordArgumentError( + f"Default value for keyword {arg_name!r} of function {obj.__name__!r} " + "cannot be 'None'." + ) + + if default_value is inspect.Parameter.empty: + annotation = arg_value.annotation + if annotation is not inspect._empty: + if annotation is None: + raise KeywordArgumentError( + f"Type hint of keyword {arg_name!r} of function " + f"{obj.__name__!r} cannot be 'None'." + ) + if issubclass(annotation, u.Quantity): + raise KeywordArgumentError( + f"Keyword {arg_name!r} of function {obj.__name__!r} needs " + "default argument. Quantity objects have no obvious default " + "value." + ) + + if annotation == str: + default_value = "" + elif annotation == int: + default_value = 0 + elif annotation == float: + default_value = 0.0 + elif annotation == bool: + default_value = False + elif issubclass(annotation, Enum): + default_value = next(iter(annotation)) + else: + raise KeywordArgumentError( + f"Type of keyword {arg_name!r} of function {obj.__name__} " + "should be a simple type (str, int, float, bool, Enum, Quantity" + ")." + ) + else: + logger.warning( + "Keyword %a of function %a has no type hint. " + "Defaulting to float...", + arg_name, + obj.__name__, + ) + default_value = 0.0 + return default_value + @staticmethod def _serialize_method(obj: Callable[..., Any]) -> dict[str, Any]: obj_type = "method" value = None readonly = True doc = get_attribute_doc(obj) + frontend_render = render_in_frontend(obj) # Store parameters and their anotations in a dictionary sig = inspect.signature(obj) parameters: dict[str, dict[str, Any]] = {} for k, v in sig.parameters.items(): - default_value = v.default - if default_value is None: - raise KeywordArgumentError( - f"Default value for keyword {k!r} of function {obj.__name__!r} " - "cannot be 'None'." - ) - - if default_value is inspect.Parameter.empty: - annotation = v.annotation - if annotation is not inspect._empty: - if annotation is None: - raise KeywordArgumentError( - f"Type hint of keyword {k!r} of function {obj.__name__!r} " - "cannot be 'None'." - ) - if issubclass(annotation, u.Quantity): - raise KeywordArgumentError( - f"Keyword {k!r} of function {obj.__name__!r} needs default " - "argument. Quantity objects have no obvious default value." - ) - - if annotation == str: - default_value = "" - elif annotation == int: - default_value = 0 - elif annotation == float: - default_value = 0.0 - elif annotation == bool: - default_value = False - elif issubclass(annotation, Enum): - default_value = next(iter(annotation)) - else: - raise KeywordArgumentError( - f"Type of keyword {k!r} of function {obj.__name__} should " - "be a simple type (str, int, float, bool, Enum, Quantity)." - ) - else: - logger.warning( - "Keyword %a of function %a has no type hint. " - "Defaulting to float...", - k, - obj.__name__, - ) - default_value = 0.0 - + default_value = Serializer._get_default_value_of_method_arg(obj, k, v) parameters[k] = dump(default_value) return { @@ -214,7 +223,7 @@ class Serializer: "doc": doc, "async": inspect.iscoroutinefunction(obj), "parameters": parameters, - "frontend_render": render_in_frontend(obj), + "frontend_render": frontend_render, } @staticmethod