diff --git a/pyflask/apis/neuroconv.py b/pyflask/apis/neuroconv.py index 6f279c06d..62028e365 100644 --- a/pyflask/apis/neuroconv.py +++ b/pyflask/apis/neuroconv.py @@ -77,6 +77,7 @@ def post(self): if notBadRequestException(exception): neuroconv_api.abort(500, str(exception)) + @neuroconv_api.route("/locate/autocomplete") class Locate(Resource): @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) @@ -86,7 +87,8 @@ def post(self): except Exception as exception: if notBadRequestException(exception): neuroconv_api.abort(500, str(exception)) - + + @neuroconv_api.route("/metadata") class Metadata(Resource): @neuroconv_api.doc(responses={200: "Success", 400: "Bad Request", 500: "Internal server error"}) diff --git a/pyflask/manageNeuroconv/manage_neuroconv.py b/pyflask/manageNeuroconv/manage_neuroconv.py index 0c38814fc..294feac31 100644 --- a/pyflask/manageNeuroconv/manage_neuroconv.py +++ b/pyflask/manageNeuroconv/manage_neuroconv.py @@ -17,10 +17,11 @@ announcer = MessageAnnouncer() + def is_path_contained(child, parent): parent = Path(parent).resolve() child = Path(child).resolve() - + # Attempt to construct a relative path from parent to child try: child.relative_to(parent) @@ -28,6 +29,7 @@ def is_path_contained(child, parent): except ValueError: return False + def replace_nan_with_none(data): if isinstance(data, dict): # If it's a dictionary, iterate over its items and replace NaN values with None @@ -118,6 +120,7 @@ def coerce_schema_compliance_recursive(obj, schema): copy.deepcopy(json_object), resolve_references(copy.deepcopy(json_schema)) ) + def autocomplete_format_string(info: dict) -> str: from neuroconv.tools.path_expansion import construct_path_template @@ -126,9 +129,14 @@ def autocomplete_format_string(info: dict) -> str: if not is_path_contained(filesystem_entry_path, base_directory): raise "Path is not contained in the provided base directory." - - full_format_string = construct_path_template(filesystem_entry_path, subject_id=info["subject_id"], session_id=info["session_id"], **info["additional_metadata"]) - + + full_format_string = construct_path_template( + filesystem_entry_path, + subject_id=info["subject_id"], + session_id=info["session_id"], + **info["additional_metadata"], + ) + parent = Path(base_directory).resolve() child = Path(full_format_string).resolve() @@ -136,20 +144,15 @@ def autocomplete_format_string(info: dict) -> str: to_locate_info = dict(base_directory=base_directory) - if (Path(filesystem_entry_path).is_dir()): + if Path(filesystem_entry_path).is_dir(): to_locate_info["folder_path"] = format_string else: to_locate_info["file_path"] = format_string + all_matched = locate_data(dict(autocomplete=to_locate_info)) - all_matched = locate_data(dict( - autocomplete = to_locate_info - )) + return dict(matched=all_matched, format_string=format_string) - return dict( - matched=all_matched, - format_string=format_string - ) def locate_data(info: dict) -> dict: """Locate data from the specifies directories using fstrings.""" diff --git a/src/renderer/src/stories/pages/guided-mode/data/GuidedPathExpansion.js b/src/renderer/src/stories/pages/guided-mode/data/GuidedPathExpansion.js index 112047d2a..9103d5be6 100644 --- a/src/renderer/src/stories/pages/guided-mode/data/GuidedPathExpansion.js +++ b/src/renderer/src/stories/pages/guided-mode/data/GuidedPathExpansion.js @@ -18,13 +18,12 @@ import { Button } from "../../../Button.js"; import { Modal } from "../../../Modal"; import { header } from "../../../forms/utils"; -import autocompleteIcon from '../../../assets/inspect.svg?raw' +import autocompleteIcon from "../../../assets/inspect.svg?raw"; - -export async function autocompleteFormatString( path ) { +export async function autocompleteFormatString(path) { let notification; - const { base_directory } = path.reduce((acc, key) => acc[key] ?? {}, this.form.resolved) + const { base_directory } = path.reduce((acc, key) => acc[key] ?? {}, this.form.resolved); const notify = (message, type) => { if (notification) this.dismiss(notification); @@ -32,9 +31,9 @@ export async function autocompleteFormatString( path ) { }; if (!base_directory) { - const message = `Please fill out the base directory for ${header(path[0])} before attempting auto-completion.` - notify(message, 'error') - throw new Error(message) + const message = `Please fill out the base directory for ${header(path[0])} before attempting auto-completion.`; + notify(message, "error"); + throw new Error(message); } const modal = new Modal({ @@ -47,7 +46,7 @@ export async function autocompleteFormatString( path ) { paddingBottom: "0px", }); - const propOrder = ["path", "subject_id", "session_id"] + const propOrder = ["path", "subject_id", "session_id"]; const form = new JSONSchemaForm({ schema: { type: "object", @@ -55,45 +54,44 @@ export async function autocompleteFormatString( path ) { path: { type: "string", title: "Example Filesystem Entry", - format: [ "file", "directory" ], - description: "Provide an example filesystem entry for the selected interface" + format: ["file", "directory"], + description: "Provide an example filesystem entry for the selected interface", }, subject_id: { type: "string", - description: "The subject ID in the above entry" + description: "The subject ID in the above entry", }, session_id: { type: "string", - description: "The session ID in the above entry" + description: "The session ID in the above entry", }, }, required: propOrder, - order: propOrder + order: propOrder, }, validateOnChange: async (name, parent) => { const value = parent[name]; - if (name === 'path') { - const errors = [] + if (name === "path") { + const errors = []; for (let key in parent) { if (key === name) continue; - if (!value.includes(parent[key])) errors.push( { - type: "error", - message: `${header(name)} not found in the updated path.`, - }) + if (!value.includes(parent[key])) + errors.push({ + type: "error", + message: `${header(name)} not found in the updated path.`, + }); } + } else { + if (!parent.path || !parent.path.includes(value)) + return [ + { + type: "error", + message: `${header(name)} not found in the provided path.`, + }, + ]; } - - else { - if (!parent.path || !parent.path.includes(value)) return [ - { - type: "error", - message: `${header(name)} not found in the provided path.`, - }, - ]; - } - - } + }, }); content.append(form); @@ -111,8 +109,12 @@ export async function autocompleteFormatString( path ) { throw e; }); - const results = await run('locate/autocomplete', { base_directory, additional_metadata: {}, ...form.results }) - const input = this.form.getFormElement([ ...path, 'format_string_path' ]); + const results = await run("locate/autocomplete", { + base_directory, + additional_metadata: {}, + ...form.results, + }); + const input = this.form.getFormElement([...path, "format_string_path"]); input.updateData(results.format_string); this.save(); resolve(results.format_string); @@ -385,7 +387,7 @@ export class GuidedPathExpansionPage extends Page { // Require properties for all sources const generatedSchema = { type: "object", properties: {}, additionalProperties: false }; - const controls = {} + const controls = {}; for (let key in this.info.globalState.interfaces) { generatedSchema.properties[key] = { type: "object", ...pathExpansionSchema }; @@ -397,12 +399,10 @@ export class GuidedPathExpansionPage extends Page { buttonStyles: { width: "max-content", }, - onClick: async () => autocompleteFormatString.call(this, [key]) + onClick: async () => autocompleteFormatString.call(this, [key]), }), - ] - } - - + ], + }; } structureState.schema = generatedSchema;