Skip to content

Commit 9be9daa

Browse files
committed
[DLMED] update according to comments
Signed-off-by: Nic Ma <nma@nvidia.com>
1 parent 4fe728c commit 9be9daa

File tree

4 files changed

+275
-18
lines changed

4 files changed

+275
-18
lines changed

monai/bundle/scripts.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ def run(
123123

124124
def verify_metadata(
125125
meta_file: Optional[Union[str, Sequence[str]]] = None,
126-
schema_url: Optional[str] = None,
127126
filepath: Optional[PathLike] = None,
128127
result_path: Optional[PathLike] = None,
129128
create_dir: Optional[bool] = None,
@@ -133,12 +132,12 @@ def verify_metadata(
133132
):
134133
"""
135134
Verify the provided `metadata` file based on the predefined `schema`.
135+
`metadata` content must contain the `schema` field for the URL of shcema file to download.
136136
The schema standard follows: http://json-schema.org/.
137137
138138
Args:
139139
meta_file: filepath of the metadata file to verify, if `None`, must be provided in `args_file`.
140140
if it is a list of file paths, the content of them will be merged.
141-
schema_url: URL to download the expected schema file.
142141
filepath: file path to store the downloaded schema.
143142
result_path: if not None, save the validation error into the result file.
144143
create_dir: whether to create directories if not existing, default to `True`.
@@ -153,7 +152,6 @@ def verify_metadata(
153152
_args = _update_args(
154153
args=args_file,
155154
meta_file=meta_file,
156-
schema_url=schema_url,
157155
filepath=filepath,
158156
result_path=result_path,
159157
create_dir=create_dir,
@@ -165,12 +163,13 @@ def verify_metadata(
165163
filepath_ = _args.pop("filepath")
166164
create_dir_ = _args.pop("create_dir", True)
167165
verify_parent_dir(path=filepath_, create_dir=create_dir_)
168-
url_ = _args.pop("schema_url", None)
169-
download_url(url=url_, filepath=filepath_, hash_val=_args.pop("hash_val", None), hash_type="md5", progress=True)
170-
171-
schema = ConfigParser.load_config_file(filepath=filepath_)
172166

173167
metadata = ConfigParser.load_config_files(files=_args.pop("meta_file"))
168+
url = metadata.get("schema")
169+
if url is None:
170+
raise ValueError("must provide the `schema` field in the metadata for the URL of schema file.")
171+
download_url(url=url, filepath=filepath_, hash_val=_args.pop("hash_val", None), hash_type="md5", progress=True)
172+
schema = ConfigParser.load_config_file(filepath=filepath_)
174173
result_path_ = _args.pop("result_path", None)
175174

176175
try:
@@ -181,5 +180,5 @@ def verify_metadata(
181180
verify_parent_dir(result_path_, create_dir=create_dir_)
182181
with open(result_path_, "w") as f:
183182
f.write(str(e))
184-
raise ValueError(f"metadata failed to validate against schema `{url_}`.") from e
183+
raise ValueError(f"metadata failed to validate against schema `{url}`.") from e
185184
logger.info("metadata verification completed.")

tests/test_bundle_verify_metadata.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,26 @@
2121

2222
from monai.bundle import ConfigParser
2323

24-
TEST_CASE_1 = [os.path.join(os.path.dirname(__file__), "testing_data", "metadata.json")]
25-
26-
url = "https://github.com/Project-MONAI/MONAI-extra-test-data/releases/download/0.8.1/" "meta_schema_202202281232.json"
24+
TEST_CASE_1 = [
25+
os.path.join(os.path.dirname(__file__), "testing_data", "metadata.json"),
26+
os.path.join(os.path.dirname(__file__), "testing_data", "schema.json"),
27+
]
2728

2829

2930
class TestVerifyMetaData(unittest.TestCase):
3031
@parameterized.expand([TEST_CASE_1])
31-
def test_verify(self, metafile):
32+
def test_verify(self, meta_file, schema_file):
3233
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
3334
with tempfile.TemporaryDirectory() as tempdir:
3435
def_args = {"meta_file": "will be replaced by `meta_file` arg"}
3536
def_args_file = os.path.join(tempdir, "def_args.json")
3637
ConfigParser.export_config_file(config=def_args, filepath=def_args_file)
3738

38-
filepath = os.path.join(tempdir, "schema.json")
3939
resultfile = os.path.join(tempdir, "results.txt")
40-
hash_val = "486c581cca90293d1a7f41a57991ff35"
40+
hash_val = "b11acc946148c0186924f8234562b947"
4141

42-
cmd = [sys.executable, "-m", "monai.bundle", "verify_metadata", "--meta_file", metafile]
43-
cmd += ["--schema_url", url, "--filepath", filepath, "--result_path", resultfile]
42+
cmd = [sys.executable, "-m", "monai.bundle", "verify_metadata", "--meta_file", meta_file]
43+
cmd += ["--filepath", schema_file, "--result_path", resultfile]
4444
cmd += ["--hash_val", hash_val, "--args_file", def_args_file]
4545
ret = subprocess.check_call(cmd)
4646
self.assertEqual(ret, 0)
@@ -52,11 +52,18 @@ def test_verify_error(self):
5252
filepath = os.path.join(tempdir, "schema.json")
5353
metafile = os.path.join(tempdir, "metadata.json")
5454
with open(metafile, "w") as f:
55-
json.dump({"wrong_meta": "wrong content"}, f)
55+
json.dump(
56+
{
57+
"schema": "https://github.com/Project-MONAI/MONAI-extra-test-data/releases/"
58+
"download/0.8.1/meta_schema_202203130950.json",
59+
"wrong_meta": "wrong content",
60+
},
61+
f,
62+
)
5663
resultfile = os.path.join(tempdir, "results.txt")
5764

5865
cmd = [sys.executable, "-m", "monai.bundle", "verify_metadata", "--meta_file", metafile]
59-
cmd += ["--schema_url", url, "--filepath", filepath, "--result_path", resultfile]
66+
cmd += ["--filepath", filepath, "--result_path", resultfile]
6067
with self.assertRaises(subprocess.CalledProcessError):
6168
subprocess.check_call(cmd)
6269
self.assertTrue(os.path.exists(resultfile))

tests/testing_data/metadata.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"schema": "https://github.com/Project-MONAI/MONAI-extra-test-data/releases/download/0.8.1/meta_schema_202203130950.json",
23
"version": "0.1.0",
34
"changelog": {
45
"0.1.0": "complete the model package",

tests/testing_data/schema.json

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"type": "object",
4+
"properties": {
5+
"schema": {
6+
"description": "URL of the schema file.",
7+
"type": "string"
8+
},
9+
"version": {
10+
"description": "version number of the model package.",
11+
"type": "string"
12+
},
13+
"changelog": {
14+
"description": "dictionary relating previous version names to strings describing the version.",
15+
"type": "object"
16+
},
17+
"monai_version": {
18+
"description": "version of MONAI the model package was generated on.",
19+
"type": "string"
20+
},
21+
"pytorch_version": {
22+
"description": "version of PyTorch the model package was generated on.",
23+
"type": "string"
24+
},
25+
"numpy_version": {
26+
"description": "version of NumPy the model package was generated on.",
27+
"type": "string"
28+
},
29+
"optional_packages_version": {
30+
"description": "dictionary relating optional package names to their versions.",
31+
"type": "object"
32+
},
33+
"task": {
34+
"description": "plain-language description of what the model is meant to do.",
35+
"type": "string"
36+
},
37+
"description": {
38+
"description": "longer form plain-language description of what the model is, what it does, etc.",
39+
"type": "string"
40+
},
41+
"authorship": {
42+
"description": "state author(s) of the model package.",
43+
"type": "string"
44+
},
45+
"copyright": {
46+
"description": "state copyright of the model package.",
47+
"type": "string"
48+
},
49+
"data_source": {
50+
"description": "where to download or prepare the data used in this model package.",
51+
"type": "string"
52+
},
53+
"data_type": {
54+
"description": "type of the data, like: `dicom`, `nibabel`, etc.",
55+
"type": "string"
56+
},
57+
"dataset_dir": {
58+
"description": "state the expected path of data in file system.",
59+
"type": "string"
60+
},
61+
"image_classes": {
62+
"description": "description for every class of the input image.",
63+
"type": "string"
64+
},
65+
"label_classes": {
66+
"description": "description for every class of the input label.",
67+
"type": "string"
68+
},
69+
"pred_classes": {
70+
"description": "description for every class of the output prediction.",
71+
"type": "string"
72+
},
73+
"eval_metrics": {
74+
"description": "dictionary relating evaluation metrics to the achieved scores.",
75+
"type": "object"
76+
},
77+
"intended_use": {
78+
"description": "what the model package is to be used for, ie. what task it accomplishes.",
79+
"type": "string"
80+
},
81+
"references": {
82+
"description": "list of published referenced relating to the model package.",
83+
"type": "array"
84+
},
85+
"network_data_format": {
86+
"description": "defines the format, shape, and meaning of inputs and outputs to the model.",
87+
"type": "object",
88+
"properties": {
89+
"inputs": {
90+
"type": "object",
91+
"properties": {
92+
"image": {
93+
"type": "object",
94+
"properties": {
95+
"type": {
96+
"type": "string"
97+
},
98+
"format": {
99+
"type": "string"
100+
},
101+
"num_channels": {
102+
"type": "integer"
103+
},
104+
"spatial_shape": {
105+
"type": "array"
106+
},
107+
"dtype": {
108+
"type": "string"
109+
},
110+
"value_range": {
111+
"type": "array",
112+
"items": {
113+
"type": "number"
114+
}
115+
},
116+
"is_patch_data": {
117+
"type": "boolean"
118+
},
119+
"channel_def": {
120+
"type": "object"
121+
}
122+
},
123+
"required": [
124+
"type",
125+
"format",
126+
"num_channels",
127+
"spatial_shape",
128+
"dtype",
129+
"value_range"
130+
]
131+
},
132+
"label": {
133+
"type": "object",
134+
"properties": {
135+
"type": {
136+
"type": "string"
137+
},
138+
"format": {
139+
"type": "string"
140+
},
141+
"num_channels": {
142+
"type": "integer"
143+
},
144+
"spatial_shape": {
145+
"type": "array"
146+
},
147+
"dtype": {
148+
"type": "string"
149+
},
150+
"value_range": {
151+
"type": "array",
152+
"items": {
153+
"type": "number"
154+
}
155+
},
156+
"is_patch_data": {
157+
"type": "boolean"
158+
},
159+
"channel_def": {
160+
"type": "object"
161+
}
162+
},
163+
"required": [
164+
"type",
165+
"format",
166+
"num_channels",
167+
"spatial_shape",
168+
"dtype",
169+
"value_range"
170+
]
171+
}
172+
},
173+
"required": [
174+
"image"
175+
]
176+
},
177+
"outputs": {
178+
"type": "object",
179+
"properties": {
180+
"pred": {
181+
"type": "object",
182+
"properties": {
183+
"type": {
184+
"type": "string"
185+
},
186+
"format": {
187+
"type": "string"
188+
},
189+
"num_channels": {
190+
"type": "integer"
191+
},
192+
"spatial_shape": {
193+
"type": "array"
194+
},
195+
"dtype": {
196+
"type": "string"
197+
},
198+
"value_range": {
199+
"type": "array",
200+
"items": {
201+
"type": "number"
202+
}
203+
},
204+
"is_patch_data": {
205+
"type": "boolean"
206+
},
207+
"channel_def": {
208+
"type": "object"
209+
}
210+
},
211+
"required": [
212+
"type",
213+
"format",
214+
"num_channels",
215+
"spatial_shape",
216+
"dtype",
217+
"value_range"
218+
]
219+
}
220+
},
221+
"required": [
222+
"pred"
223+
]
224+
}
225+
},
226+
"required": [
227+
"inputs",
228+
"outputs"
229+
]
230+
}
231+
},
232+
"required": [
233+
"schema",
234+
"version",
235+
"monai_version",
236+
"pytorch_version",
237+
"numpy_version",
238+
"optional_packages_version",
239+
"task",
240+
"description",
241+
"authorship",
242+
"copyright",
243+
"dataset_dir",
244+
"image_classes",
245+
"label_classes",
246+
"pred_classes",
247+
"eval_metrics",
248+
"network_data_format"
249+
]
250+
}

0 commit comments

Comments
 (0)