diff --git a/src/labthings/apispec/plugins.py b/src/labthings/apispec/plugins.py index 7d9459b6..88adc45b 100644 --- a/src/labthings/apispec/plugins.py +++ b/src/labthings/apispec/plugins.py @@ -60,14 +60,19 @@ def spec_for_interaction(cls, interaction): for method in http_method_funcs: if hasattr(interaction, method): + prop = getattr(interaction, method) d[method] = { - "description": getattr(interaction, "description", None) - or get_docstring(interaction), - "summary": getattr(interaction, "summary", None) + "description": getattr(prop, "description", None) + or get_docstring(prop, remove_newlines=False) + or getattr(interaction, "description", None) + or get_docstring(interaction, remove_newlines=False), + "summary": getattr(prop, "summary", None) + or get_summary(prop) + or getattr(interaction, "summary", None) or get_summary(interaction), "tags": list(interaction.get_tags()), "responses": { - "default": { + "5XX": { "description": "Unexpected error", "content": { "application/json": { diff --git a/src/labthings/utilities.py b/src/labthings/utilities.py index 9a4407cd..35d5c710 100644 --- a/src/labthings/utilities.py +++ b/src/labthings/utilities.py @@ -1,4 +1,5 @@ import copy +import inspect import operator import os import re @@ -152,12 +153,12 @@ def get_docstring(obj: Any, remove_newlines=True) -> str: """ ds = obj.__doc__ - if ds: + if not ds: + return "" + if remove_newlines: stripped = [line.strip() for line in ds.splitlines() if line] - if not remove_newlines: - return "\n".join(stripped) return " ".join(stripped).replace("\n", " ").replace("\r", "") - return "" + return inspect.cleandoc(ds) # Strip spurious indentation/newlines def get_summary(obj: Any) -> str: diff --git a/src/labthings/views/__init__.py b/src/labthings/views/__init__.py index 68604f8b..d5c198b9 100644 --- a/src/labthings/views/__init__.py +++ b/src/labthings/views/__init__.py @@ -18,7 +18,6 @@ build_action_schema, ) from ..utilities import unpack -from . import builder, op __all__ = ["MethodView", "View", "ActionView", "PropertyView", "op", "builder"] @@ -172,7 +171,12 @@ def __init_subclass__(cls): @classmethod def get(cls): """ - Default method for GET requests. Returns the action queue (including already finished actions) for this action + List running and completed actions. + + Actions are run with `POST` requests. See the `POST` method for this URL for + details of the action. Sending a `GET` request to an action endpoint will return + action descriptions for each time the action has been run, including whether they + have completed, and any return values. """ queue_schema = build_action_schema(cls.schema, cls.args)(many=True) return queue_schema.dump(cls._deque) diff --git a/src/labthings/views/builder.py b/src/labthings/views/builder.py index 03bccc6b..d6868a3f 100644 --- a/src/labthings/views/builder.py +++ b/src/labthings/views/builder.py @@ -4,10 +4,10 @@ from typing import Type from flask import abort, send_file -from flask.views import MethodView +from . import View -def static_from(static_folder: str, name=None) -> Type[MethodView]: +def static_from(static_folder: str, name=None) -> Type[View]: """ :param static_folder: str: :param name: (Default value = None) @@ -37,6 +37,6 @@ def _get(_, path=""): return send_file(indexes[0]) # Generate a basic property class - generated_class = type(name, (MethodView, object), {"get": _get}) + generated_class = type(name, (View, object), {"get": _get}) return generated_class diff --git a/tests/test_utilities.py b/tests/test_utilities.py index fecd6856..eab062a4 100644 --- a/tests/test_utilities.py +++ b/tests/test_utilities.py @@ -30,6 +30,10 @@ def test_get_docstring(example_class): utilities.get_docstring(example_class) == "First line of class docstring. Second line of class docstring. " ) + assert ( + utilities.get_docstring(example_class, remove_newlines=False) + == "First line of class docstring.\nSecond line of class docstring." + ) assert utilities.get_docstring(example_class.class_method) == ( "First line of class method docstring. Second line of class method docstring. "