Skip to content

Commit

Permalink
Merge branch 'main' into fix_linux_deployment_2
Browse files Browse the repository at this point in the history
  • Loading branch information
CodyCBakerPhD authored Aug 18, 2023
2 parents 43b0bbf + 172bbb7 commit 27d71e2
Show file tree
Hide file tree
Showing 27 changed files with 605 additions and 328 deletions.
97 changes: 97 additions & 0 deletions .github/workflows/pyflask-build-and-dist-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: PyFlask build and distributable tests
on:
schedule:
- cron: "0 16 * * *" # Daily at noon EST
pull_request:
workflow_dispatch:

# Cancel previous workflows on the same pull request
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
CACHE_NUMBER: 1 # increase to reset cache manually

jobs:
testing:
name: PyFlask build and distributable tests on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash -l {0}

strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- python-version: "3.9"
os: ubuntu-latest
label: tools/anaconda-env/environment-Linux.yml
prefix: /usr/share/miniconda3/envs/nwb-guide
shorthand: unix

- python-version: "3.10"
os: macos-latest
label: tools/anaconda-env/environment-Mac.yml
prefix: /Users/runner/miniconda3/envs/nwb-guide
shorthand: unix

- python-version: "3.9"
os: windows-latest
label: tools/anaconda-env/environment-Windows.yml
prefix: C:\Miniconda3\envs\nwb-guide
shorthand: win

steps:
- uses: actions/checkout@v3
- run: git fetch --prune --unshallow --tags

# see https://github.com/conda-incubator/setup-miniconda#caching-environments
- name: Setup Mambaforge
uses: conda-incubator/setup-miniconda@v2
with:
miniforge-variant: Mambaforge
miniforge-version: latest
activate-environment: nwb-guide
use-mamba: true

- name: Set cache date
id: get-date
run: echo "today=$(/bin/date -u '+%Y%m%d')" >> $GITHUB_OUTPUT
shell: bash

- name: Cache Mamba env
uses: actions/cache@v2
with:
path: ${{ env.CONDA }}/envs
key:
conda-${{ runner.os }}-${{ runner.arch }}-${{steps.get-date.outputs.today }}-${{ hashFiles(matrix.label) }}-${{ env.CACHE_NUMBER }}
env:
CACHE_NUMBER: ${{ env.CACHE_NUMBER }}
id: cache

- if: steps.cache.outputs.cache-hit != 'true'
name: Update environment
run: mamba env update -f ${{ matrix.label }}

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: "16"

- name: Build PyFlask distribution
run: npm run build:flask:${{ matrix.shorthand }}

# encountering parsing issue for second arg
#- if: matrix.os == 'windows-latest'
# name: Run test on build executable
# run: node tests/testPyinstallerExecutable.js ./build/nwb-guide/nwb-guide.exe

#- if: matrix.os != 'windows-latest'
# name: Run test on build executable
# run: node tests/testPyinstallerExecutable.js ./build/nwb-guide/nwb-guide

- name: Run test on distributed executable
run: node tests/testPyinstallerExecutable.js
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"description": "",
"main": "./build/main/main.js",
"scripts": {
"start": "electron-vite dev",
"start": "electron-vite dev --outDir build",
"postinstall": "electron-builder install-app-deps",
"dev": "concurrently -n BE,FE --kill-others \"npm run dev:server\" \"npm run dev:app\"",
"dev:app": "vite src/renderer",
"dev:server": "cd pyflask && python -m flask run --port 4242",
Expand All @@ -32,8 +33,6 @@
"deploy:electron:win": "electron-builder build --win --publish always",
"deploy:electron:mac": "electron-builder build --mac --publish always",
"deploy:electron:linux": "electron-builder build --linux --publish always",
"format": "prettier --ignore-path .gitignore --ignore-path .prettierignore \"./**/*.+(html|css|js|md|yml)\" --write",
"postinstall": "electron-builder install-app-deps",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"chromatic": "npx chromatic"
Expand Down
4 changes: 2 additions & 2 deletions pyflask/apis/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from .apiStartup import api as startup_resource
from .apiNeuroConv import api as neuroconv_resource
from .startup import startup_api
from .neuroconv import neuroconv_api
84 changes: 42 additions & 42 deletions pyflask/apis/apiNeuroConv.py → pyflask/apis/neuroconv.py
Original file line number Diff line number Diff line change
@@ -1,148 +1,148 @@
"""API endpoint definitions for interacting with NeuroConv."""
import traceback

from flask_restx import Namespace, Resource, reqparse
from flask import Response
import traceback

from namespaces import get_namespace, NamespaceEnum
from manageNeuroconv import (
get_all_interface_info,
locate_data,
get_source_schema,
get_metadata_schema,
convert_to_nwb,
validate_metadata,
upload_to_dandi,
listen_to_neuroconv_events,
generate_dataset,
)

from errorHandlers import notBadRequestException

api = Namespace("neuroconv", description="Neuroconv API for NWB GUIDE")
api = get_namespace(NamespaceEnum.NEUROCONV)
neuroconv_api = Namespace("neuroconv", description="Neuroconv neuroconv_api for the NWB GUIDE.")

parser = reqparse.RequestParser()
parser.add_argument("interfaces", type=str, action="split", help="Interfaces cannot be converted")


@api.errorhandler(Exception)
@neuroconv_api.errorhandler(Exception)
def exception_handler(error):
exceptiondata = traceback.format_exception(type(error), error, error.__traceback__)
return {"message": exceptiondata[-1], "traceback": "".join(exceptiondata)}


@api.route("/")
@neuroconv_api.route("/")
class AllInterfaces(Resource):
@api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
@neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
def get(self):
try:
return get_all_interface_info()
except Exception as e:
if notBadRequestException(e):
api.abort(500, str(e))
neuroconv_api.abort(500, str(e))
raise e


@api.route("/schema")
@neuroconv_api.route("/schema")
class Schemas(Resource):
@api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
@neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
def post(self):
try:
return get_source_schema(api.payload)
return get_source_schema(neuroconv_api.payload)
except Exception as e:
if notBadRequestException(e):
api.abort(500, str(e))
neuroconv_api.abort(500, str(e))


@api.route("/locate")
@neuroconv_api.route("/locate")
class Locate(Resource):
@api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
@neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
def post(self):
try:
return locate_data(api.payload)
return locate_data(neuroconv_api.payload)
except Exception as e:
if notBadRequestException(e):
api.abort(500, str(e))
neuroconv_api.abort(500, str(e))


@api.route("/metadata")
@neuroconv_api.route("/metadata")
class Metadata(Resource):
@api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
@neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
def post(self):
# try:
return get_metadata_schema(api.payload.get("source_data"), api.payload.get("interfaces"))
return get_metadata_schema(neuroconv_api.payload.get("source_data"), neuroconv_api.payload.get("interfaces"))

# except Exception as e:
# if notBadRequestException(e):
# api.abort(500, str(e))
# neuroconv_api.abort(500, str(e))


@api.route("/convert")
@neuroconv_api.route("/convert")
class Convert(Resource):
@api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
@neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
def post(self):
try:
return convert_to_nwb(api.payload)
return convert_to_nwb(neuroconv_api.payload)

except Exception as e:
if notBadRequestException(e):
api.abort(500, str(e))
neuroconv_api.abort(500, str(e))


validate_parser = api.parser()
validate_parser = neuroconv_api.parser()
validate_parser.add_argument("parent", type=dict, required=True)
validate_parser.add_argument("function_name", type=str, required=True)


# 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())
@api.route("/validate")
@api.expect(validate_parser)
@neuroconv_api.route("/validate")
@neuroconv_api.expect(validate_parser)
class Validate(Resource):
@api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
@neuroconv_api.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 e:
if notBadRequestException(e):
api.abort(500, str(e))
neuroconv_api.abort(500, str(e))


@api.route("/upload")
@neuroconv_api.route("/upload")
class Upload(Resource):
@api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
@neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
def post(self):
try:
return upload_to_dandi(**api.payload)
from manageNeuroconv import upload_to_dandi

return upload_to_dandi(**neuroconv_api.payload)

except Exception as e:
if notBadRequestException(e):
api.abort(500, str(e))
neuroconv_api.abort(500, str(e))


@api.route("/generate_dataset")
@neuroconv_api.route("/generate_dataset")
class GenerateDataset(Resource):
@api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
@neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
def post(self):
try:
return generate_dataset(**api.payload)
return generate_dataset(**neuroconv_api.payload)

except Exception as e:
if notBadRequestException(e):
api.abort(500, str(e))
neuroconv_api.abort(500, str(e))


# Create an events endpoint
# announcer.announce('test', 'publish')
@api.route("/events", methods=["GET"])
@neuroconv_api.route("/events", methods=["GET"])
class Events(Resource):
@api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"})
@neuroconv_api.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 e:
if notBadRequestException(e):
api.abort(500, str(e))
neuroconv_api.abort(500, str(e))
14 changes: 7 additions & 7 deletions pyflask/apis/apiStartup.py → pyflask/apis/startup.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""API endpoint definitions for startup operations."""
from startup import get_api_version
from flask_restx import Resource
from namespaces import get_namespace, NamespaceEnum
from flask_restx import Namespace, Resource

api = get_namespace(NamespaceEnum.STARTUP)
startup_api = Namespace("startup", description="API for startup commands related to the NWB GUIDE.")

parser = api.parser()
parser = startup_api.parser()
parser.add_argument(
"arg",
type=str,
Expand All @@ -14,15 +14,15 @@
)


@api.route("/echo")
@startup_api.route("/echo")
class Echo(Resource):
@api.expect(parser)
@startup_api.expect(parser)
def get(self):
args = parser.parse_args()
return args["arg"]


@api.route("/minimum_api_version")
@startup_api.route("/minimum_api_version")
class MinimumApiVersion(Resource):
def get(self):
return get_api_version()
Loading

0 comments on commit 27d71e2

Please sign in to comment.