Skip to content

A value column referenced by {braces} is never validated on its own #1418

Description

@VisLab

When a sidecar annotation references a value column with curly braces
("ball": "{response_time}, Green"), the column mapper removes that column from the per-column
assembly and folds it into the referencing annotation. Rows whose annotation does not reference it
(here the face rows) then never have their response_time value validated at all. An invalid value
in such a row, for example 7,3 substituted into Parameter-value/#, passes silently. Without the
brace reference the same data reports TAG_INVALID.

Where it shows. hed-tests validation_tests.json, record sidecar-braces-self-reference,
combo_tests.passes[0]: the last events row has response_time = "7,3" with event_code = "face",
and face does not reference {response_time}. The case passes only because of this gap. (The test
data is being changed to 7.3; the validator gap remains.)

import io, json
import pandas as pd
from hed.errors import ErrorHandler, get_printable_issue_string
from hed.models import Sidecar, TabularInput
from hed.schema import load_schema_version

schema = load_schema_version("8.4.0")
events = pd.DataFrame({
    "onset": ["4.5", "5.0", "5.5"],
    "response_time": ["3.4", "6.8", "7,3"],
    "event_code": ["face", "ball", "face"],
})

def run(sidecar_dict, label):
    sidecar = Sidecar(io.StringIO(json.dumps(sidecar_dict)), name="events.json")
    tabular = TabularInput(file=events, sidecar=sidecar, name="events.tsv")
    print(f"--- {label}")
    print("assembled per column:", tabular.dataframe_a.values.tolist())
    issues = tabular.validate(schema, error_handler=ErrorHandler(check_for_warnings=False))
    print("issues:", [(i["code"], i.get("ec_row")) for i in issues])
    if issues:
        print(get_printable_issue_string(issues))

run({"event_code": {"HED": {"face": "(Red, Blue)", "ball": "{response_time}, Green"}},
     "response_time": {"HED": "Parameter-value/#"}},
    "response_time referenced by {response_time} in the 'ball' annotation")
run({"event_code": {"HED": {"face": "(Red, Blue)", "ball": "Green"}},
     "response_time": {"HED": "Parameter-value/#"}},
    "same data, no brace reference")

Output:

--- response_time referenced by {response_time} in the 'ball' annotation
assembled per column: [['(Red, Blue)'], ['Parameter-value/6.8, Green'], ['(Red, Blue)']]
issues: []
--- same data, no brace reference
assembled per column: [['(Red, Blue)', 'Parameter-value/3.4'], ['Green', 'Parameter-value/6.8'], ['(Red, Blue)', 'Parameter-value/7,3']]
issues: [('TAG_INVALID', 4)]
Issues in row 4:
	Issues in column response_time:
		hed string: Parameter-value/7,3
			TAG_INVALID: '3' in 3 is not a valid base HED tag.  Problem spans string indexes: 18, 19

In the first run the assembled dataframe has one column: response_time has been consumed by the
reference and appears only in the ball row. Its value in the two face rows (3.4 and 7,3) is
never substituted into Parameter-value/# and never validated.

Expected. Every non-n/a value of a value column is substituted into its template and validated,
whether or not the row's other annotations reference the column. A reference changes where the
expansion is placed in the assembled string, not whether the value is checked. At minimum the value
should satisfy the value class of the placeholder tag (Parameter-value/# is textClass, which
forbids a comma) in every row.

Why it matters beyond this case. A dataset that references a value column from one category
({response_time} only for response events) is the normal use of the brace syntax. Every row of the
other categories carries a value that is never checked, so a malformed value there is invisible to
hed-validator and to BIDS validation.

Where to look. The column-reference handling in the column mapper / df_util that removes a
referenced column from the standalone expansion (dataframe_a above shows the removal). One fix:
keep the per-column expansion of a referenced column for rows whose referencing annotation does not
apply, or validate the substituted value for every row before the reference is resolved.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions