2828
2929from . import config
3030from . import languages
31- from . import formatversion
3231from . import metadata
3332from . import problem2html
3433from . import problem2pdf
3534from . import run
3635from . import statement_util
36+ from .formatversion import FormatVersion , get_format_version
3737
3838from abc import ABC
3939from typing import Any , Callable , ClassVar , Literal , Pattern , Match , ParamSpec , Type , TypeVar
@@ -819,16 +819,12 @@ def setup(self):
819819 error_str = '\n ' .join ([f' { "->" .join ((str (loc ) for loc in err ["loc" ]))} : { err ["msg" ]} ' for err in e .errors ()])
820820 self .error (f'Failed parsing problem.yaml. Found { len (e .errors ())} errors:\n { error_str } ' )
821821 # For now, set metadata to an empty legacy config to avoid crashing.
822- self .problem .setMetadata (
823- metadata .parse_metadata (formatversion .get_format_data_by_name (formatversion .VERSION_LEGACY ), {})
824- )
822+ self .problem .setMetadata (metadata .parse_metadata (FormatVersion .LEGACY , {}))
825823 except Exception as e :
826824 # This should likely be a fatal error, but I'm not sure there's a clean way to fail from setup
827825 self .error (f'Failed loading problem configuration: { e } ' )
828826 # For now, set metadata to an empty legacy config to avoid crashing.
829- self .problem .setMetadata (
830- metadata .parse_metadata (formatversion .get_format_data_by_name (formatversion .VERSION_LEGACY ), {})
831- )
827+ self .problem .setMetadata (metadata .parse_metadata (FormatVersion .LEGACY , {}))
832828 return {}
833829
834830 def __str__ (self ) -> str :
@@ -853,7 +849,7 @@ def check(self, context: Context) -> bool:
853849
854850 if self ._metadata .uuid is None :
855851 uuid_msg = f'Missing uuid from problem.yaml. Add "uuid: { uuid .uuid4 ()} " to problem.yaml.'
856- if self .problem .format . name == formatversion . VERSION_LEGACY :
852+ if self .problem .format is FormatVersion . LEGACY :
857853 self .warning (uuid_msg )
858854 else :
859855 self .error (uuid_msg )
@@ -864,7 +860,7 @@ def check(self, context: Context) -> bool:
864860 not self ._metadata .is_pass_fail ()
865861 and self .problem .get (ProblemTestCases )['root_group' ].has_custom_groups ()
866862 and 'show_test_data_groups' not in self ._origdata .get ('grading' , {})
867- and self .problem .format . name == formatversion . VERSION_LEGACY
863+ and self .problem .format is FormatVersion . LEGACY
868864 ):
869865 self .warning (
870866 'Problem has custom testcase groups, but does not specify a value for grading.show_test_data_groups; defaulting to false'
@@ -1217,10 +1213,7 @@ class OutputValidators(ProblemPart):
12171213 PART_NAME = 'output_validator'
12181214
12191215 def setup (self ):
1220- if (
1221- self .problem .format .name != formatversion .VERSION_LEGACY
1222- and (Path (self .problem .probdir ) / 'output_validators' ).exists ()
1223- ):
1216+ if self .problem .format is FormatVersion .LEGACY and (Path (self .problem .probdir ) / 'output_validators' ).exists ():
12241217 self .error ('output_validators is not supported after Legacy; please use output_validator instead' )
12251218
12261219 self ._validators = run .find_programs (
@@ -1351,7 +1344,7 @@ def _parse_validator_results(self, val, status: int, feedbackdir, testcase: Test
13511344 def _actual_validators (self ) -> list :
13521345 vals = self ._validators
13531346 if self .problem .getMetadata ().legacy_validation == 'default' or (
1354- self .problem .format . name == formatversion . VERSION_2023_07 and not vals
1347+ self .problem .format is FormatVersion . V_2023_07 and not vals
13551348 ):
13561349 vals = [self ._default_validator ]
13571350 return [val for val in vals if val is not None ]
@@ -1739,16 +1732,16 @@ def check(self, context: Context) -> bool:
17391732 return self ._check_res
17401733
17411734
1742- PROBLEM_FORMATS : dict [str , dict [str , list [Type [ProblemPart ]]]] = {
1743- formatversion . VERSION_LEGACY : {
1735+ PROBLEM_FORMATS : dict [FormatVersion , dict [str , list [Type [ProblemPart ]]]] = {
1736+ FormatVersion . LEGACY : {
17441737 'config' : [ProblemConfig ],
17451738 'statement' : [ProblemStatement , Attachments ],
17461739 'validators' : [InputValidators , OutputValidators ],
17471740 'graders' : [Graders ],
17481741 'data' : [ProblemTestCases ],
17491742 'submissions' : [Submissions ],
17501743 },
1751- formatversion . VERSION_2023_07 : { # TODO: Add all the parts
1744+ FormatVersion . V_2023_07 : { # TODO: Add all the parts
17521745 'config' : [ProblemConfig ],
17531746 'statement' : [ProblemStatement , Attachments ],
17541747 'validators' : [InputValidators , OutputValidators ],
@@ -1773,14 +1766,14 @@ class Problem(ProblemAspect):
17731766 of category -> part-types. You could for example have 'validators' -> [InputValidators, OutputValidators].
17741767 """
17751768
1776- def __init__ (self , probdir : str , parts : dict [str , list [type ]] = PROBLEM_FORMATS [formatversion . VERSION_LEGACY ]):
1769+ def __init__ (self , probdir : str , parts : dict [str , list [type ]] = PROBLEM_FORMATS [FormatVersion . LEGACY ]):
17771770 self .part_mapping : dict [str , list [Type [ProblemPart ]]] = parts
17781771 self .aspects : set [type ] = {v for s in parts .values () for v in s }
17791772 self .probdir = os .path .realpath (probdir )
17801773 self .shortname : str | None = os .path .basename (self .probdir )
17811774 super ().__init__ (self .shortname )
17821775 self .language_config = languages .load_language_config ()
1783- self .format = formatversion . get_format_data ( self .probdir )
1776+ self .format = get_format_version ( Path ( self .probdir ) )
17841777 self ._data : dict [str , dict ] = {}
17851778 self ._metadata : metadata .Metadata | None = None
17861779 self .debug (f'Problem-format: { parts } ' )
@@ -1860,8 +1853,8 @@ def check(self, args: argparse.Namespace) -> tuple[int, int]:
18601853 try :
18611854 if not re .match ('^[a-z0-9]+$' , self .shortname ):
18621855 self .error (f"Invalid shortname '{ self .shortname } ' (must be [a-z0-9]+)" )
1863- if self .format . name == formatversion . VERSION_2023_07 :
1864- self .warning (f'Support for version { self .format . name } is very incomplete. Verification may not work as expected.' )
1856+ if self .format is FormatVersion . V_2023_07 :
1857+ self .warning (f'Support for version { self .format } is very incomplete. Verification may not work as expected.' )
18651858
18661859 self ._check_symlinks ()
18671860
@@ -2007,17 +2000,16 @@ def main() -> None:
20072000 for problemdir in args .problemdir :
20082001 try :
20092002 if args .problem_format == 'automatic' :
2010- version_data = formatversion . get_format_data ( problemdir )
2003+ formatversion = get_format_version ( Path ( problemdir ) )
20112004 else :
2012- version_data = formatversion . get_format_data_by_name (args .problem_format )
2013- except formatversion . VersionError as e :
2005+ formatversion = FormatVersion (args .problem_format )
2006+ except Exception as e :
20142007 total_errors += 1
20152008 print (f'ERROR: problem version could not be decided for { os .path .basename (os .path .realpath (problemdir ))} : { e } ' )
20162009 continue
20172010
2018- print (f'Loading problem { os .path .basename (os .path .realpath (problemdir ))} with format version { version_data .name } ' )
2019- format = PROBLEM_FORMATS [version_data .name ]
2020- with Problem (problemdir , format ) as prob :
2011+ print (f'Loading problem { os .path .basename (os .path .realpath (problemdir ))} with format version { formatversion } ' )
2012+ with Problem (problemdir , PROBLEM_FORMATS [formatversion ]) as prob :
20212013 errors , warnings = prob .check (args )
20222014
20232015 def p (x : int ) -> str :
0 commit comments