diff --git a/src/labthings/apispec/utilities.py b/src/labthings/apispec/utilities.py index 48a95ea..822bd29 100644 --- a/src/labthings/apispec/utilities.py +++ b/src/labthings/apispec/utilities.py @@ -5,18 +5,19 @@ from typing import Dict, Union from .. import fields + def field2property(field): """Convert a marshmallow Field to OpenAPI dictionary""" converter = FieldConverterMixin() converter.init_attribute_functions() return converter.field2pattern(field) + def ensure_schema( - schema: Union[fields.Field, Schema, Dict[str, Union[fields.Field, type]]], - name: str = "GeneratedFromDict" + schema: Union[fields.Field, Schema, Dict[str, Union[fields.Field, type]]], + name: str = "GeneratedFromDict", ) -> Union[dict, Schema]: - """Create a Schema object, or OpenAPI dictionary, given a Field, Schema, or Dict. - """ + """Create a Schema object, or OpenAPI dictionary, given a Field, Schema, or Dict.""" if schema is None: return None if isinstance(schema, fields.Field): @@ -30,9 +31,10 @@ def ensure_schema( f"Invalid schema type {type(schema)}. Must be a Schema or Mapping/dict" ) + def get_marshamallow_plugin(spec): """Extract the marshmallow plugin object from an APISpec""" for p in spec.plugins: if isinstance(p, MarshmallowPlugin): return p - raise AttributeError("The APISpec does not seem to have a Marshmallow plugin.") \ No newline at end of file + raise AttributeError("The APISpec does not seem to have a Marshmallow plugin.") diff --git a/src/labthings/default_views/actions.py b/src/labthings/default_views/actions.py index 05a1632..951fa05 100644 --- a/src/labthings/default_views/actions.py +++ b/src/labthings/default_views/actions.py @@ -7,27 +7,23 @@ from ..views import View - class ActionQueueView(View): """List of all actions from the session""" def get(self): """Action queue - - This endpoint returns a list of all actions that have run since - the server was started, including ones that have completed and - actions that are still running. Each entry includes links to + + This endpoint returns a list of all actions that have run since + the server was started, including ones that have completed and + actions that are still running. Each entry includes links to manage and inspect that action. """ return ActionSchema(many=True).dump(current_labthing().actions.threads) + get.responses = { "200": { "description": "List of Action objects", - "content": { - "application/json": { - "schema": ActionSchema(many=True) - } - } + "content": {"application/json": {"schema": ActionSchema(many=True)}}, } } @@ -43,7 +39,7 @@ class ActionObjectView(View): def get(self, task_id): """Show the status of an Action - + A `GET` request will return the current status of an action, including logs. For completed actions, it will include the return value. @@ -56,24 +52,19 @@ def get(self, task_id): task = task_dict.get(task_id) return ActionSchema().dump(task) + get.responses = { "200": { "description": "Action object", - "content": { - "application/json": { - "schema": ActionSchema - } - } + "content": {"application/json": {"schema": ActionSchema}}, }, - "404": { - "description": "Action not found" - } + "404": {"description": "Action not found"}, } @use_args({"timeout": fields.Int()}) def delete(self, args, task_id): """Cancel a running Action - + A `DELETE` request will stop a running action. """ timeout = args.get("timeout", None) @@ -85,16 +76,11 @@ def delete(self, args, task_id): task = task_dict.get(task_id) task.stop(timeout=timeout) return ActionSchema().dump(task) + delete.responses = { "200": { "description": "Action object that was cancelled", - "content": { - "application/json": { - "schema": ActionSchema - } - } + "content": {"application/json": {"schema": ActionSchema}}, }, - "404": { - "description": "Action not found" - } + "404": {"description": "Action not found"}, } diff --git a/src/labthings/default_views/extensions.py b/src/labthings/default_views/extensions.py index a837452..05c4350 100644 --- a/src/labthings/default_views/extensions.py +++ b/src/labthings/default_views/extensions.py @@ -16,14 +16,10 @@ def get(self): Describes server methods, web views, and other relevant Lab Things metadata. """ return ExtensionSchema(many=True).dump(registered_extensions().values() or []) - + get.responses = { "200": { "description": "A list of available extensions and their properties", - "content": { - "application/json":{ - "schema": ExtensionSchema - } - } + "content": {"application/json": {"schema": ExtensionSchema}}, } } diff --git a/src/labthings/default_views/root.py b/src/labthings/default_views/root.py index 608d678..699f5d9 100644 --- a/src/labthings/default_views/root.py +++ b/src/labthings/default_views/root.py @@ -24,6 +24,6 @@ def get(self): get.responses = { "200": { "description": "W3C Thing Description", - "content": {"application/json":{}}, + "content": {"application/json": {}}, } - } \ No newline at end of file + } diff --git a/src/labthings/schema.py b/src/labthings/schema.py index 64b9ce2..6b1edc2 100644 --- a/src/labthings/schema.py +++ b/src/labthings/schema.py @@ -88,7 +88,9 @@ class ActionSchema(Schema): _ID = fields.String(data_key="id") _status = fields.String( data_key="status", - validate=validate.OneOf(["pending", "running", "completed", "cancelled", "error"]), + validate=validate.OneOf( + ["pending", "running", "completed", "cancelled", "error"] + ), ) progress = fields.Integer() data = fields.Raw() @@ -128,6 +130,7 @@ def generate_links(self, data, **_): return data + def nest_if_needed(schema): """Convert a schema, dict, or field into a field.""" # If we have a real schema, nest it @@ -139,13 +142,14 @@ def nest_if_needed(schema): # If a single field, set it as the output Field, and override its data_key if isinstance(schema, fields.Field): return schema - + raise TypeError( f"Unsupported schema type {schema}. " "Ensure schema is a Schema object, Field object, " "or dictionary of Field objects" ) + def build_action_schema( output_schema: Optional[FuzzySchemaType], input_schema: Optional[FuzzySchemaType], @@ -161,7 +165,7 @@ def build_action_schema( :param name: str: (Default value = None) """ - #FIXME: this seems to lose the schemas. I suspect this is down to `nest_if_needed`. + # FIXME: this seems to lose the schemas. I suspect this is down to `nest_if_needed`. # Create a name for the generated schema if not name: name = str(id(output_schema)) @@ -172,7 +176,9 @@ class GenSchema(base_class): pass GenSchema.__name__ = name - GenSchema.__doc__ = f"Description of an action, with specific parameters for `{name}`" + GenSchema.__doc__ = ( + f"Description of an action, with specific parameters for `{name}`" + ) if input_schema: GenSchema.input = nest_if_needed(input_schema) if output_schema: @@ -182,10 +188,8 @@ class GenSchema(base_class): def openapi_array(schema: FuzzySchemaType) -> Dict: - return { - "type":"array", - "items": schema - } + return {"type": "array", "items": schema} + class EventSchema(Schema): event = fields.String() diff --git a/src/labthings/views/builder.py b/src/labthings/views/builder.py index dbd8c25..7403f88 100644 --- a/src/labthings/views/builder.py +++ b/src/labthings/views/builder.py @@ -37,7 +37,9 @@ def _get(_, path=""): return send_file(indexes[0]) _get.summary = "Serve static files" - _get.description = "Files and folders within this path will be served from a static directory." + _get.description = ( + "Files and folders within this path will be served from a static directory." + ) _get.responses = { "200": { "description": "Static file",