-
Notifications
You must be signed in to change notification settings - Fork 24
/
cmd_validate.py
144 lines (124 loc) · 4.16 KB
/
cmd_validate.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import logging
import os
import click
from .base import devel_debug_option, devel_option, lgr, map_to_click_exceptions
@click.command()
@click.option(
"--schema", help="Validate against new BIDS schema version", metavar="VERSION"
)
@click.option(
"--report-path",
help="Write report under path, this option implies `--report/-r`.",
)
@click.option(
"--report",
"-r",
is_flag=True,
help="Whether to write a report under a unique path in the DANDI log directory.",
)
@click.argument("paths", nargs=-1, type=click.Path(exists=True, dir_okay=True))
@map_to_click_exceptions
def validate_bids(
paths,
schema,
report,
report_path,
):
"""Validate BIDS paths.
Notes
-----
Used from bash, eg:
dandi validate-bids /my/path
"""
from ..bids_utils import is_valid, report_errors
from ..validate import validate_bids as validate_bids_
validator_result = validate_bids_(
*paths,
report=report,
report_path=report_path,
schema_version=schema,
)
valid = is_valid(validator_result)
report_errors(validator_result)
if not valid:
raise SystemExit(1)
@click.command()
@devel_option("--schema", help="Validate against new schema version", metavar="VERSION")
@devel_option(
"--allow-any-path",
help="For development: allow DANDI 'unsupported' file types/paths",
default=False,
is_flag=True,
)
@click.argument("paths", nargs=-1, type=click.Path(exists=True, dir_okay=True))
@devel_debug_option()
@map_to_click_exceptions
def validate(paths, schema=None, devel_debug=False, allow_any_path=False):
"""Validate files for NWB and DANDI compliance.
Exits with non-0 exit code if any file is not compliant.
"""
from ..pynwb_utils import ignore_benign_pynwb_warnings
from ..validate import validate as validate_
# Don't log validation warnings, as this command reports them to the user
# anyway:
root = logging.getLogger()
for h in root.handlers:
h.addFilter(lambda r: not getattr(r, "validating", False))
if not paths:
paths = [os.curdir]
# below we are using load_namespaces but it causes HDMF to whine if there
# is no cached name spaces in the file. It is benign but not really useful
# at this point, so we ignore it although ideally there should be a formal
# way to get relevant warnings (not errors) from PyNWB
ignore_benign_pynwb_warnings()
view = "one-at-a-time" # TODO: rename, add groupped
all_files_errors = {}
nfiles = 0
for path, errors in validate_(
*paths,
schema_version=schema,
devel_debug=devel_debug,
allow_any_path=allow_any_path,
):
nfiles += 1
if view == "one-at-a-time":
display_errors(path, errors)
all_files_errors[path] = errors
if view == "groupped":
# TODO: Most likely we want to summarize errors across files since they
# are likely to be similar
# TODO: add our own criteria for validation (i.e. having needed metadata)
# # can't be done since fails to compare different types of errors
# all_errors = sum(errors.values(), [])
# all_error_types = []
# errors_unique = sorted(set(all_errors))
# from collections import Counter
# # Let's make it
# print(
# "{} unique errors in {} files".format(
# len(errors_unique), len(errors))
# )
raise NotImplementedError("TODO")
files_with_errors = [f for f, errors in all_files_errors.items() if errors]
if files_with_errors:
click.secho(
"Summary: Validation errors in {} out of {} files".format(
len(files_with_errors), nfiles
),
bold=True,
fg="red",
)
raise SystemExit(1)
else:
click.secho(
"Summary: No validation errors among {} file(s)".format(nfiles),
bold=True,
fg="green",
)
def display_errors(path, errors):
if not errors:
lgr.info("%s: ok", path)
else:
lgr.error("%s: %d error(s)", path, len(errors))
for error in errors:
lgr.error(" %s", error)