@@ -268,9 +268,6 @@ def __init__(
268
268
if "name" in yaml_data and isinstance (yaml_data ["name" ], str ):
269
269
yaml_data ["name" ] = {"en" : yaml_data ["name" ]}
270
270
271
- if "validator_flags" in yaml_data and isinstance (yaml_data ["validator_flags" ], str ):
272
- yaml_data ["validator_flags" ] = shlex .split (yaml_data ["validator_flags" ])
273
-
274
271
# Known keys:
275
272
# (defaults from https://icpc.io/problem-package-format/spec/2023-07-draft.html#problem-metadata)
276
273
self .problem_format_version : str = parse_setting (
@@ -328,8 +325,21 @@ def __init__(
328
325
# Not implemented in BAPCtools. Should be a date, but we don't do anything with this anyway.
329
326
self .embargo_until : str = parse_setting (yaml_data , "embargo-until" , "" )
330
327
self .limits = ProblemLimits (parse_setting (yaml_data , "limits" , {}), problem , self )
331
- # TODO: move to testdata.yaml
332
- self .validator_flags : list [str ] = parse_setting (yaml_data , "validator_flags" , [])
328
+
329
+ # If problem.yaml uses 2023-07-draft, disallow `validator_flags`.
330
+ if self .is_legacy ():
331
+ if "validator_flags" in yaml_data and isinstance (yaml_data ["validator_flags" ], str ):
332
+ yaml_data ["validator_flags" ] = shlex .split (yaml_data ["validator_flags" ])
333
+ # This field should not be used anywhere except the default result of Problem.get_testdata_yaml().
334
+ self ._validator_flags : list [str ] = parse_setting (yaml_data , "validator_flags" , [])
335
+ else :
336
+ self ._validator_flags = []
337
+ if "validator_flags" in yaml_data :
338
+ warn (
339
+ "problem.yaml: 'validator_flags' is removed in 2023-07-draft, please use 'output_validator_args' in 'testdata.yaml' instead. SKIPPED."
340
+ )
341
+ yaml_data .pop ("validator_flags" )
342
+
333
343
self .keywords : str = parse_setting (yaml_data , "keywords" , "" )
334
344
# Not implemented in BAPCtools. We always test all languges in langauges.yaml.
335
345
self .languages : list [str ] = parse_optional_list_setting (yaml_data , "languages" , str )
@@ -481,6 +491,7 @@ def _read_settings(self):
481
491
self .multi_pass : bool = self .settings .multi_pass
482
492
self .custom_output : bool = self .settings .custom_output
483
493
494
+ # TODO #102 move to TestData class
484
495
def _parse_testdata_yaml (p , path , bar ):
485
496
assert path .is_relative_to (p .path / "data" )
486
497
for dir in [path ] + list (path .parents ):
@@ -495,20 +506,36 @@ def _parse_testdata_yaml(p, path, bar):
495
506
if f not in p ._testdata_yamls :
496
507
p ._testdata_yamls [f ] = flags = read_yaml (f , plain = True )
497
508
498
- # verify testdata.yaml
509
+ if p .settings .is_legacy ():
510
+ # For legacy problems, support both _flags and _args, but move to _args.
511
+ if (
512
+ "output_validator_flags" in flags
513
+ and "output_validator_args" not in flags
514
+ ):
515
+ flags ["output_validator_args" ] = flags .pop ("output_validator_flags" )
516
+ if "input_validator_flags" in flags and "input_validator_args" not in flags :
517
+ flags ["input_validator_args" ] = flags .pop ("input_validator_flags" )
518
+ else :
519
+ # For 2023-07-draft problems, skip the old name and warn to use the new one.
520
+ if "input_validator_flags" in flags :
521
+ bar .warn (
522
+ "input_validator_flags is removed in 2023-07-draft, use ..._args instead. SKIPPED."
523
+ )
524
+ if "output_validator_flags" in flags :
525
+ bar .warn (
526
+ "output_validator_flags is removed in 2023-07-draft, use ..._args instead. SKIPPED."
527
+ )
528
+
529
+ # Verify testdata.yaml
499
530
for k in flags :
500
531
match k :
501
- case "output_validator_flags " :
532
+ case "output_validator_args " :
502
533
if not isinstance (flags [k ], str ):
503
- bar .error (
504
- "ouput_validator_flags must be string" ,
505
- resume = True ,
506
- print_item = False ,
507
- )
508
- case "input_validator_flags" :
534
+ bar .error (f"{ k } must be string" , resume = True , print_item = False )
535
+ case "input_validator_args" :
509
536
if not isinstance (flags [k ], (str , dict )):
510
537
bar .error (
511
- "input_validator_flags must be string or map" ,
538
+ f" { k } must be string or map" ,
512
539
resume = True ,
513
540
print_item = False ,
514
541
)
@@ -521,16 +548,32 @@ def _parse_testdata_yaml(p, path, bar):
521
548
f"Unknown input validator { name } ; expected { input_validator_names } " ,
522
549
print_item = False ,
523
550
)
524
- case "grading" | "run_samples" :
525
- bar .warn (f"{ k } not implemented in BAPCtools" , print_item = False )
551
+ case (
552
+ "args"
553
+ | "description"
554
+ | "full_feedback"
555
+ | "hint"
556
+ | "scoring"
557
+ | "static_validation"
558
+ ):
559
+ bar .warn (
560
+ f"{ k } in testdata.yaml not implemented in BAPCtools" ,
561
+ print_item = False ,
562
+ )
526
563
case _:
527
564
path = f .relative_to (p .path / "data" )
528
565
bar .warn (f'Unknown key "{ k } " in { path } ' , print_item = False )
529
566
# Do not go above the data directory.
530
567
if dir == p .path / "data" :
531
568
break
532
569
533
- def get_testdata_yaml (p , path , key , bar , name = None ) -> str | None :
570
+ def get_testdata_yaml (
571
+ p ,
572
+ path : Path ,
573
+ key : Literal ["input_validator_args" ] | Literal ["output_validator_args" ],
574
+ bar : ProgressBar | PrintBar ,
575
+ name : Optional [str ] = None ,
576
+ ) -> list [str ]:
534
577
"""
535
578
Find the testdata flags applying at the given path for the given key.
536
579
If necessary, walk up from `path` looking for the first testdata.yaml file that applies,
@@ -540,50 +583,55 @@ def get_testdata_yaml(p, path, key, bar, name=None) -> str | None:
540
583
Arguments
541
584
---------
542
585
path: absolute path (a file or a directory)
543
- key: The testdata.yaml key to look for, either of 'input_validator_flags ', 'output_validator_flags ', or 'grading'.
544
- 'grading' is not implemented
545
- name: If key == 'input_validator_flags ', optionally the name of the input validator
586
+ key: The testdata.yaml key to look for, either of 'input_validator_args ', 'output_validator_args ', or 'grading'.
587
+ TODO: 'grading' is not yet implemented.
588
+ name: If key == 'input_validator_args ', optionally the name of the input validator.
546
589
547
590
Returns:
548
591
--------
549
- string or None if no testdata.yaml is found.
592
+ A list of string arguments, which is empty if no testdata.yaml is found.
550
593
TODO: when 'grading' is supported, it also can return dict
551
594
"""
552
- if key not in ["input_validator_flags " , "output_validator_flags " ]:
595
+ if key not in ["input_validator_args " , "output_validator_args " ]:
553
596
raise NotImplementedError (key )
554
- if key != "input_validator_flags " and name is not None :
597
+ if key != "input_validator_args " and name is not None :
555
598
raise ValueError (
556
599
f"Only input validators support flags by validator name, got { key } and { name } "
557
600
)
558
601
559
602
# parse and cache testdata.yaml
560
603
p ._parse_testdata_yaml (path , bar )
561
604
605
+ # For legacy problems, default to validator_flags from problem.yaml
606
+ default_result = []
607
+ if p .settings .is_legacy () and p .settings ._validator_flags :
608
+ default_result = p .settings ._validator_flags
609
+
562
610
# extract the flags
563
611
for dir in [path ] + list (path .parents ):
564
612
# Do not go above the data directory.
565
613
if dir == p .path :
566
- return None
614
+ return default_result
567
615
568
616
f = dir / "testdata.yaml"
569
617
if f not in p ._testdata_yamls :
570
618
continue
571
619
flags = p ._testdata_yamls [f ]
572
620
if key in flags :
573
- if key == "output_validator_flags " :
621
+ if key == "output_validator_args " :
574
622
if not isinstance (flags [key ], str ):
575
- bar .error ("ouput_validator_flags must be string" )
576
- return flags [key ]
623
+ bar .error ("ouput_validator_args must be string" )
624
+ return flags [key ]. split ()
577
625
578
- if key == "input_validator_flags " :
626
+ if key == "input_validator_args " :
579
627
if not isinstance (flags [key ], (str , dict )):
580
- bar .error ("input_validator_flags must be string or map" )
628
+ bar .error ("input_validator_args must be string or map" )
581
629
if isinstance (flags [key ], str ):
582
- return flags [key ]
630
+ return flags [key ]. split ()
583
631
elif name in flags [key ]:
584
- return flags [key ][name ]
632
+ return flags [key ][name ]. split ()
585
633
586
- return None
634
+ return default_result
587
635
588
636
def testcases (
589
637
p ,
@@ -1210,14 +1258,11 @@ def validate_valid_extra_data(p) -> bool:
1210
1258
if not p .validators (validate .OutputValidator , strict = True , print_warn = False ):
1211
1259
return True
1212
1260
1213
- args = (
1214
- p .get_testdata_yaml (
1215
- p .path / "data" / "valid_output" ,
1216
- "output_validator_flags" ,
1217
- PrintBar ("Generic Output Validation" ),
1218
- )
1219
- or ""
1220
- ).split ()
1261
+ args = p .get_testdata_yaml (
1262
+ p .path / "data" / "valid_output" ,
1263
+ "output_validator_args" ,
1264
+ PrintBar ("Generic Output Validation" ),
1265
+ )
1221
1266
is_space_sensitive = "space_change_sensitive" in args
1222
1267
is_case_sensitive = "case_sensitive" in args
1223
1268
@@ -1313,7 +1358,7 @@ def _validate_data(
1313
1358
# validate the testcases
1314
1359
bar = ProgressBar (action , items = [t .name for t in testcases ])
1315
1360
1316
- def process_testcase (testcase ):
1361
+ def process_testcase (testcase : testcase . Testcase ):
1317
1362
nonlocal success
1318
1363
1319
1364
localbar = bar .start (testcase .name )
0 commit comments