Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix number inputs #579

Merged
merged 7 commits into from
Jan 30, 2024
Merged
12 changes: 10 additions & 2 deletions pyflask/manageNeuroconv/manage_neuroconv.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,11 @@ def get_metadata_schema(source_data: Dict[str, dict], interfaces: dict) -> Dict[
"""Function used to fetch the metadata schema from a CustomNWBConverter instantiated from the source_data."""
from neuroconv.utils import NWBMetaDataEncoder

converter = instantiate_custom_converter(source_data, interfaces)
resolved_source_data = replace_none_with_nan(
source_data, resolve_references(get_custom_converter(interfaces).get_source_schema())
)

converter = instantiate_custom_converter(resolved_source_data, interfaces)
schema = converter.get_metadata_schema()
metadata = converter.get_metadata()

Expand Down Expand Up @@ -423,7 +427,11 @@ def convert_to_nwb(info: dict) -> str:

resolved_output_path.parent.mkdir(exist_ok=True, parents=True) # Ensure all parent directories exist

converter = instantiate_custom_converter(info["source_data"], info["interfaces"])
resolved_source_data = replace_none_with_nan(
info["source_data"], resolve_references(get_custom_converter(info["interfaces"]).get_source_schema())
)

converter = instantiate_custom_converter(resolved_source_data, info["interfaces"])

def update_conversion_progress(**kwargs):
announcer.announce(dict(**kwargs, nwbfile_path=nwbfile_path), "conversion_progress")
Expand Down
23 changes: 15 additions & 8 deletions src/renderer/src/stories/JSONSchemaForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const encode = (str) => {

const additionalPropPattern = "additional";

const provideNaNMessage = `<br/><small>Type <b>NaN</b> to represent an unknown value.</small>`;
const templateNaNMessage = `<br/><small>Type <b>NaN</b> to represent an unknown value.</small>`;

import { Validator } from "jsonschema";
import { successHue, warningHue, errorHue } from "./globals";
Expand Down Expand Up @@ -378,8 +378,8 @@ export class JSONSchemaForm extends LitElement {
throw new Error(message);
};

validateSchema = async (resolved, schema, name) => {
return await validator
validateSchema = (resolved, schema, name) => {
return validator
.validate(resolved, schema)
.errors.map((e) => {
const propName = e.path.slice(-1)[0] ?? name ?? e.property;
Expand All @@ -399,8 +399,8 @@ export class JSONSchemaForm extends LitElement {

// Allow referring to floats as null (i.e. JSON NaN representation)
if (e.message === "is not of a type(s) number") {
if (resolvedValue === "NaN") return;
else e.message = `${e.message}. ${provideNaNMessage}`;
if ((resolvedValue === "NaN") | (resolvedValue === null)) return;
else if (isRow) e.message = `${e.message}. ${templateNaNMessage}`;
}

const prevHeader = name ? header(name) : "Row";
Expand All @@ -422,7 +422,7 @@ export class JSONSchemaForm extends LitElement {
const copy = structuredClone(resolved);
delete copy.__disabled;

const result = await this.validateSchema(copy, this.schema);
const result = this.validateSchema(copy, this.schema);

const resolvedErrors = this.#resolveErrors(result, this.base, resolved);

Expand Down Expand Up @@ -815,7 +815,7 @@ export class JSONSchemaForm extends LitElement {
const skipValidation = !this.validateEmptyValues && value === undefined;
const validateArgs = input.pattern || skipValidation ? [] : [value, schema];

const jsonSchemaErrors = validateArgs.length === 2 ? await this.validateSchema(...validateArgs, name) : [];
const jsonSchemaErrors = validateArgs.length === 2 ? this.validateSchema(...validateArgs, name) : [];

const valid = skipValidation ? true : await this.validateOnChange(name, parent, pathToValidate, value);

Expand Down Expand Up @@ -860,9 +860,16 @@ export class JSONSchemaForm extends LitElement {
// Throw at least a basic warning if a non-linked property is required and missing
if (!hasLinks && isRequired) {
if (this.validateEmptyValues) {
const rowName = pathToValidate.slice(-1)[0];
const isRow = typeof rowName === "number";

errors.push({
message: `${schema.title ?? header(name)} ${this.#isARequiredPropertyString}. ${
schema.type === "number" ? provideNaNMessage : ""
schema.type === "number"
? isRow
? templateNaNMessage
: "<br><small>Use the 'I Don't Know' checkbox if unsure.</small>"
: ""
}`,
type: "error",
missing: true,
Expand Down
17 changes: 10 additions & 7 deletions src/renderer/src/stories/JSONSchemaInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ export class JSONSchemaInput extends LitElement {
white-space: nowrap;
}

.nan-handler label {
.nan-handler span {
margin-left: 5px;
font-size: 12px;
}
Expand Down Expand Up @@ -1074,12 +1074,14 @@ export class JSONSchemaInput extends LitElement {

// const isBlank = value === '';

if (isInteger) newValue = parseInt(value);
else if (isNumber) newValue = parseFloat(value);
if (isInteger) value = newValue = parseInt(value);
else if (isNumber) value = newValue = parseFloat(value);

if (isNumber) {
if ("min" in schema && newValue < schema.min) newValue = schema.min;
else if ("max" in schema && newValue > schema.max) newValue = schema.max;

if (isNaN(newValue)) newValue = undefined;
}

if (schema.transform) newValue = schema.transform(newValue, this.value, schema);
Expand All @@ -1090,7 +1092,7 @@ export class JSONSchemaInput extends LitElement {
// if (!regex.test(isNaN(newValue) ? value : newValue)) newValue = this.value // revert to last value
// }

if (!isNaN(newValue) && newValue !== value) {
if (isNumber && newValue !== value) {
ev.target.value = newValue;
value = newValue;
}
Expand All @@ -1108,19 +1110,20 @@ export class JSONSchemaInput extends LitElement {
${isRequiredNumber
? html`<div class="nan-handler"><input
type="checkbox"
?checked=${this.value && Number.isNaN(this.value)}
?checked=${this.value === null}
@change=${(ev) => {
const siblingInput = ev.target.parentNode.previousElementSibling;
if (ev.target.checked) {
this.#updateData(fullPath, NaN);
this.#updateData(fullPath, null);
siblingInput.setAttribute("disabled", true);
} else {
siblingInput.removeAttribute("disabled");
const ev = new Event("input");
siblingInput.dispatchEvent(ev);
}
this.#triggerValidation(name, path);
}}
></input><label>I Don't Know</label></div>`
></input><span>I Don't Know</span></div>`
: ""}
`;
}
Expand Down
Loading