From c9d29688baae05f82ed1875755d2f1f2dfcecf65 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Mon, 27 May 2024 14:55:55 -0400 Subject: [PATCH] swap naming to 'namespace' --- src/pyflask/apis/__init__.py | 6 - src/pyflask/app.py | 30 ++-- src/pyflask/namespaces/__init__.py | 6 + src/pyflask/{apis => namespaces}/dandi.py | 6 +- src/pyflask/{apis => namespaces}/data.py | 20 +-- src/pyflask/{apis => namespaces}/neuroconv.py | 144 +++++++++--------- src/pyflask/{apis => namespaces}/neurosift.py | 14 +- src/pyflask/{apis => namespaces}/startup.py | 14 +- src/pyflask/{apis => namespaces}/system.py | 6 +- 9 files changed, 122 insertions(+), 124 deletions(-) delete mode 100644 src/pyflask/apis/__init__.py create mode 100644 src/pyflask/namespaces/__init__.py rename src/pyflask/{apis => namespaces}/dandi.py (82%) rename src/pyflask/{apis => namespaces}/data.py (67%) rename src/pyflask/{apis => namespaces}/neuroconv.py (52%) rename src/pyflask/{apis => namespaces}/neurosift.py (90%) rename src/pyflask/{apis => namespaces}/startup.py (68%) rename src/pyflask/{apis => namespaces}/system.py (72%) diff --git a/src/pyflask/apis/__init__.py b/src/pyflask/apis/__init__.py deleted file mode 100644 index 714e08c4b..000000000 --- a/src/pyflask/apis/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .dandi import dandi_api -from .data import data_api -from .neuroconv import neuroconv_api -from .neurosift import neurosift_api -from .startup import startup_api -from .system import system_api diff --git a/src/pyflask/app.py b/src/pyflask/app.py index d0a655ff8..ab13f8dc5 100644 --- a/src/pyflask/app.py +++ b/src/pyflask/app.py @@ -16,14 +16,6 @@ multiprocessing.freeze_support() -from apis import ( - dandi_api, - data_api, - neuroconv_api, - neurosift_api, - startup_api, - system_api, -) from flask import Flask, request, send_file, send_from_directory from flask_cors import CORS from flask_restx import Api, Resource @@ -34,6 +26,14 @@ is_packaged, resource_path, ) +from namespaces import ( + dandi_namespace, + data_namespace, + neuroconv_namespace, + neurosift_namespace, + startup_namespace, + system_namespace, +) app = Flask(__name__) @@ -57,16 +57,14 @@ title="NWB GUIDE API", description="The REST API for the NWB GUIDE provided by the Python Flask Server.", ) -api.add_namespace(startup_api) -api.add_namespace(neuroconv_api) -api.add_namespace(data_api) -api.add_namespace(system_api) -api.add_namespace(dandi_api) -api.add_namespace(neurosift_api) +api.add_namespace(startup_namespace) +api.add_namespace(neuroconv_namespace) +api.add_namespace(data_namespace) +api.add_namespace(system_namespace) +api.add_namespace(dandi_namespace) +api.add_namespace(neurosift_namespace) api.init_app(app) -registered = {} - @api.route("/log") class Log(Resource): diff --git a/src/pyflask/namespaces/__init__.py b/src/pyflask/namespaces/__init__.py new file mode 100644 index 000000000..0f1edb274 --- /dev/null +++ b/src/pyflask/namespaces/__init__.py @@ -0,0 +1,6 @@ +from .dandi import dandi_namespace +from .data import data_namespace +from .neuroconv import neuroconv_namespace +from .neurosift import neurosift_namespace +from .startup import startup_namespace +from .system import system_namespace diff --git a/src/pyflask/apis/dandi.py b/src/pyflask/namespaces/dandi.py similarity index 82% rename from src/pyflask/apis/dandi.py rename to src/pyflask/namespaces/dandi.py index bdc01208d..11e070c35 100644 --- a/src/pyflask/apis/dandi.py +++ b/src/pyflask/namespaces/dandi.py @@ -4,15 +4,15 @@ import flask_restx -dandi_api = flask_restx.Namespace( +dandi_namespace = flask_restx.Namespace( name="dandi", description="Request various static listings from the DANDI Python API." ) -@dandi_api.route(rule="/get-recommended-species") +@dandi_namespace.route(rule="/get-recommended-species") class SupportedSpecies(flask_restx.Resource): - @dandi_api.doc( + @dandi_namespace.doc( description="Request the list of currently supported species (by Latin Binomial name) for DANDI. Note that any " "explicit NCBI taxonomy link is also supported.", ) diff --git a/src/pyflask/apis/data.py b/src/pyflask/namespaces/data.py similarity index 67% rename from src/pyflask/apis/data.py rename to src/pyflask/namespaces/data.py index 7cdafdb57..8b05339e9 100644 --- a/src/pyflask/apis/data.py +++ b/src/pyflask/namespaces/data.py @@ -5,10 +5,10 @@ from flask_restx import Namespace, Resource, reqparse from manageNeuroconv import generate_dataset, generate_test_data -data_api = Namespace("data", description="API route for dataset generation in the NWB GUIDE.") +data_namespace = Namespace("data", description="API route for dataset generation in the NWB GUIDE.") -@data_api.errorhandler(Exception) +@data_namespace.errorhandler(Exception) def exception_handler(error): exceptiondata = traceback.format_exception(type(error), error, error.__traceback__) return {"message": exceptiondata[-1], "traceback": "".join(exceptiondata)} @@ -18,16 +18,16 @@ def exception_handler(error): generate_test_data_parser.add_argument("output_path", type=str, required=True) -@data_api.route("/generate") -@data_api.expect(generate_test_data_parser) +@data_namespace.route("/generate") +@data_namespace.expect(generate_test_data_parser) class GeneratetestData(Resource): - @data_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @data_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: arguments = generate_test_data_parser.parse_args() generate_test_data(output_path=arguments["output_path"]) except Exception as exception: - data_api.abort(500, str(exception)) + data_namespace.abort(500, str(exception)) raise exception @@ -36,14 +36,14 @@ def post(self): generate_test_dataset_parser.add_argument("input_path", type=str, required=True) -@data_api.route("/generate/dataset") -@data_api.expect(generate_test_data_parser) +@data_namespace.route("/generate/dataset") +@data_namespace.expect(generate_test_data_parser) class GenerateDataset(Resource): - @data_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @data_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: arguments = generate_test_dataset_parser.parse_args() return generate_dataset(input_path=arguments["input_path"], output_path=arguments["output_path"]) except Exception as exception: - data_api.abort(500, str(exception)) + data_namespace.abort(500, str(exception)) diff --git a/src/pyflask/apis/neuroconv.py b/src/pyflask/namespaces/neuroconv.py similarity index 52% rename from src/pyflask/apis/neuroconv.py rename to src/pyflask/namespaces/neuroconv.py index 47a2af031..79d4473bd 100644 --- a/src/pyflask/apis/neuroconv.py +++ b/src/pyflask/namespaces/neuroconv.py @@ -24,21 +24,21 @@ ) from manageNeuroconv.info import announcer -neuroconv_api = Namespace("neuroconv", description="Neuroconv neuroconv_api for the NWB GUIDE.") +neuroconv_namespace = Namespace("neuroconv", description="Neuroconv neuroconv_namespace for the NWB GUIDE.") parser = reqparse.RequestParser() parser.add_argument("interfaces", type=str, action="split", help="Interfaces cannot be converted") -@neuroconv_api.errorhandler(Exception) +@neuroconv_namespace.errorhandler(Exception) def exception_handler(error): exceptiondata = traceback.format_exception(type(error), error, error.__traceback__) return {"message": exceptiondata[-1], "traceback": "".join(exceptiondata)} -@neuroconv_api.route("/") +@neuroconv_namespace.route("/") class AllInterfaces(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def get(self): try: # return get_all_interface_info() @@ -49,75 +49,75 @@ def get(self): **get_all_converter_info(), } except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) raise exception -@neuroconv_api.route("/schema") +@neuroconv_namespace.route("/schema") class Schemas(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: - return get_source_schema(neuroconv_api.payload) + return get_source_schema(neuroconv_namespace.payload) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/locate") +@neuroconv_namespace.route("/locate") class LocateData(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: - return locate_data(neuroconv_api.payload) + return locate_data(neuroconv_namespace.payload) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/locate/autocomplete") +@neuroconv_namespace.route("/locate/autocomplete") class AutoCompleteFormatString(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: - return autocomplete_format_string(neuroconv_api.payload) + return autocomplete_format_string(neuroconv_namespace.payload) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/metadata") +@neuroconv_namespace.route("/metadata") class Metadata(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: return get_metadata_schema( - neuroconv_api.payload.get("source_data"), neuroconv_api.payload.get("interfaces") + neuroconv_namespace.payload.get("source_data"), neuroconv_namespace.payload.get("interfaces") ) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/convert") +@neuroconv_namespace.route("/convert") class Convert(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: - return convert_to_nwb(neuroconv_api.payload) + return convert_to_nwb(neuroconv_namespace.payload) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/alignment") +@neuroconv_namespace.route("/alignment") class Alignment(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: - return get_interface_alignment(neuroconv_api.payload) + return get_interface_alignment(neuroconv_namespace.payload) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -validate_parser = neuroconv_api.parser() +validate_parser = neuroconv_namespace.parser() validate_parser.add_argument("parent", type=dict, required=True) validate_parser.add_argument("function_name", type=str, required=True) @@ -125,27 +125,27 @@ def post(self): # await fetch('neuroconv/validate', {method:"POST", body: JSON.stringify({nwb_file_object: {related_publications: ['name']}, function: 'check_doi_publications'}), headers: { # "Content-Type": "application/json", # }}).then(res => res.text()) -@neuroconv_api.route("/validate") -@neuroconv_api.expect(validate_parser) +@neuroconv_namespace.route("/validate") +@neuroconv_namespace.expect(validate_parser) class Validate(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: args = validate_parser.parse_args() return validate_metadata(args.get("parent"), args.get("function_name")) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/upload/project") +@neuroconv_namespace.route("/upload/project") class UploadProject(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: import psutil - upload_options = neuroconv_api.payload + upload_options = neuroconv_namespace.payload if "number_of_jobs" not in upload_options: upload_options.update(number_of_jobs=1) if "number_of_threads" not in upload_options: @@ -154,17 +154,17 @@ def post(self): return upload_project_to_dandi(**upload_options) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/upload/folder") +@neuroconv_namespace.route("/upload/folder") class UploadFolder(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: import psutil - upload_options = neuroconv_api.payload + upload_options = neuroconv_namespace.payload if "number_of_jobs" not in upload_options: upload_options.update(number_of_jobs=1) if "number_of_threads" not in upload_options: @@ -173,77 +173,77 @@ def post(self): return upload_folder_to_dandi(**upload_options) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/upload") +@neuroconv_namespace.route("/upload") class Upload(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): from os.path import isdir try: - paths = neuroconv_api.payload["filesystem_paths"] + paths = neuroconv_namespace.payload["filesystem_paths"] if len(paths) == 1 and isdir(paths[0]): - kwargs = {**neuroconv_api.payload} + kwargs = {**neuroconv_namespace.payload} del kwargs["filesystem_paths"] kwargs["nwb_folder_path"] = paths[0] return upload_folder_to_dandi(**kwargs) else: - return upload_multiple_filesystem_objects_to_dandi(**neuroconv_api.payload) + return upload_multiple_filesystem_objects_to_dandi(**neuroconv_namespace.payload) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/inspect_file") +@neuroconv_namespace.route("/inspect_file") class InspectNWBFile(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: - return inspect_nwb_file(neuroconv_api.payload) + return inspect_nwb_file(neuroconv_namespace.payload) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/inspect_folder") +@neuroconv_namespace.route("/inspect_folder") class InspectNWBFolder(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: url = f"{request.url_root}neuroconv/announce" - return inspect_nwb_folder(url, neuroconv_api.payload) + return inspect_nwb_folder(url, neuroconv_namespace.payload) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/announce") +@neuroconv_namespace.route("/announce") class InspectNWBFolder(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: - data = neuroconv_api.payload + data = neuroconv_namespace.payload announcer.announce(data) return True except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/inspect") +@neuroconv_namespace.route("/inspect") class InspectNWBFolder(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): from os.path import isfile url = f"{request.url_root}neuroconv/announce" try: - paths = neuroconv_api.payload["paths"] + paths = neuroconv_namespace.payload["paths"] - kwargs = {**neuroconv_api.payload} + kwargs = {**neuroconv_namespace.payload} del kwargs["paths"] if len(paths) == 1: @@ -256,32 +256,32 @@ def post(self): return inspect_multiple_filesystem_objects(url, paths, **kwargs) except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) -@neuroconv_api.route("/html") +@neuroconv_namespace.route("/html") class NWBToHTML(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def post(self): try: from pynwb import NWBHDF5IO - with NWBHDF5IO(neuroconv_api.payload.nwbfile_path, mode="r") as io: + with NWBHDF5IO(neuroconv_namespace.payload.nwbfile_path, mode="r") as io: html = io.read()._repr_html_() return html except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) # Create an events endpoint # announcer.announce('test', 'publish') -@neuroconv_api.route("/events", methods=["GET"]) +@neuroconv_namespace.route("/events", methods=["GET"]) class Events(Resource): - @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @neuroconv_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def get(self): try: return Response(listen_to_neuroconv_events(), mimetype="text/event-stream") except Exception as exception: - neuroconv_api.abort(500, str(exception)) + neuroconv_namespace.abort(500, str(exception)) diff --git a/src/pyflask/apis/neurosift.py b/src/pyflask/namespaces/neurosift.py similarity index 90% rename from src/pyflask/apis/neurosift.py rename to src/pyflask/namespaces/neurosift.py index e4260ec85..c08a47481 100644 --- a/src/pyflask/apis/neurosift.py +++ b/src/pyflask/namespaces/neurosift.py @@ -6,7 +6,7 @@ import flask import flask_restx -neurosift_api = flask_restx.Namespace( +neurosift_namespace = flask_restx.Namespace( name="neurosift", description="Handle file system communication with the " "standalone Neurosift preview page." ) @@ -15,18 +15,18 @@ neurosift_file_registry = collections.defaultdict(bool) -@neurosift_api.route(rule="/files/") -@neurosift_api.doc( +@neurosift_namespace.route(rule="/files/") +@neurosift_namespace.doc( description="Handle adding and fetching NWB files from the global file registry.", ) class NeurosiftFileManager(flask_restx.Resource): - @neurosift_api.doc( + @neurosift_namespace.doc( description="If the file path has been added to the registry (and therefore sent its base " "URL), return the absolute file path. This is implicitly called by Neurosift.", ) def get(self, file_path: str) -> Union[flask.Response, None]: - abort_if_not_nwb_file(file_path=file_path, api=neurosift_api) + abort_if_not_nwb_file(file_path=file_path, api=neurosift_namespace) if neurosift_file_registry[file_path]: code = 404 base_message = server_error_responses(codes=[code])[code] @@ -45,13 +45,13 @@ def get(self, file_path: str) -> Union[flask.Response, None]: return flask.send_file(path_or_file=parsed_file_path) - @neurosift_api.doc( + @neurosift_namespace.doc( description="Add the file to a global in-memory registry (refreshes on App restart) and return " "the base URL of the newly " "added file", ) def post(self, file_path: str) -> Union[str, None]: - abort_if_not_nwb_file(file_path=file_path, api=neurosift_api) + abort_if_not_nwb_file(file_path=file_path, api=neurosift_namespace) neurosift_file_registry[file_path] = True diff --git a/src/pyflask/apis/startup.py b/src/pyflask/namespaces/startup.py similarity index 68% rename from src/pyflask/apis/startup.py rename to src/pyflask/namespaces/startup.py index 823dbee00..927a938f1 100644 --- a/src/pyflask/apis/startup.py +++ b/src/pyflask/namespaces/startup.py @@ -2,9 +2,9 @@ from flask_restx import Namespace, Resource -startup_api = Namespace("startup", description="API for startup commands related to the NWB GUIDE.") +startup_namespace = Namespace("startup", description="API for startup commands related to the NWB GUIDE.") -parser = startup_api.parser() +parser = startup_namespace.parser() parser.add_argument( "arg", type=str, @@ -14,15 +14,15 @@ ) -@startup_api.route("/echo") +@startup_namespace.route("/echo") class Echo(Resource): - @startup_api.expect(parser) + @startup_namespace.expect(parser) def get(self): args = parser.parse_args() return args["arg"] -@startup_api.route("/preload-imports") +@startup_namespace.route("/preload-imports") class PreloadImports(Resource): """ Preload various imports on startup instead of waiting for them later on. @@ -32,12 +32,12 @@ class PreloadImports(Resource): simply expose the cached namespaces to their scope instead of retriggering the entire import. """ - @startup_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) + @startup_namespace.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) def get(self): try: import neuroconv return True except Exception as exception: - startup_api.abort(500, str(exception)) + startup_namespace.abort(500, str(exception)) raise exception diff --git a/src/pyflask/apis/system.py b/src/pyflask/namespaces/system.py similarity index 72% rename from src/pyflask/apis/system.py rename to src/pyflask/namespaces/system.py index fd19bf811..5e0b9f104 100644 --- a/src/pyflask/apis/system.py +++ b/src/pyflask/namespaces/system.py @@ -4,13 +4,13 @@ import flask_restx -system_api = flask_restx.Namespace(name="system", description="Request various system specific information.") +system_namespace = flask_restx.Namespace(name="system", description="Request various system specific information.") -@system_api.route("/cpus") +@system_namespace.route("/cpus") class SupportedSpecies(flask_restx.Resource): - @system_api.doc( + @system_namespace.doc( description="Request the number of physical and logical cores on the system.", ) def get(self) -> Union[Dict[str, int], None]: