1
+ import datetime
1
2
import re
2
3
import sys
3
4
import threading
@@ -89,8 +90,16 @@ class ProblemSources(list[ProblemSource]):
89
90
def __init__ (
90
91
self ,
91
92
yaml_data : dict [str , Any ],
92
- problem_settings : "ProblemSettings" ,
93
93
):
94
+ def source_from_dict (source_dict : dict [str , str ]) -> ProblemSource :
95
+ name = parse_setting (source_dict , "name" , "" )
96
+ if not name :
97
+ warn ("problem.yaml: 'name' is required in source" )
98
+ return ProblemSource (
99
+ name ,
100
+ parse_optional_setting (source_dict , "url" , str ),
101
+ )
102
+
94
103
parse_deprecated_setting (yaml_data , "source_url" , "source.url" )
95
104
if "source" not in yaml_data :
96
105
return
@@ -99,23 +108,17 @@ def __init__(
99
108
return
100
109
if isinstance (yaml_data ["source" ], dict ):
101
110
source = parse_setting (yaml_data , "source" , dict [str , str ]())
102
- self .append (
103
- ProblemSource (
104
- parse_setting (source , "name" , "" ),
105
- parse_optional_setting (source , "url" , str ),
106
- )
107
- )
111
+ self .append (source_from_dict (source ))
108
112
return
109
113
if isinstance (yaml_data ["source" ], list ):
110
114
sources = parse_setting (yaml_data , "source" , list [dict [str , str ]]())
111
- for raw_source in sources :
112
- source = parse_setting (raw_source , "source" , dict [str , str ]())
113
- self .append (
114
- ProblemSource (
115
- parse_setting (source , "name" , "" ),
116
- parse_optional_setting (source , "url" , str ),
117
- )
118
- )
115
+ for i , source in enumerate (sources ):
116
+ if isinstance (source , str ):
117
+ self .append (ProblemSource (source ))
118
+ elif isinstance (source , dict ):
119
+ self .append (source_from_dict (source ))
120
+ else :
121
+ warn (f"problem.yaml key 'source[{ i } ]' does not have the correct type" )
119
122
return
120
123
warn ("problem.yaml key 'source' does not have the correct type" )
121
124
@@ -134,31 +137,48 @@ def __init__(
134
137
time_multipliers = parse_setting (yaml_data , "time_multipliers" , dict [str , Any ]())
135
138
136
139
parse_deprecated_setting (yaml_data , "time_multiplier" , "ac_to_time_limit" )
137
- self .ac_to_time_limit = parse_setting (time_multipliers , "ac_to_time_limit" , 2.0 )
140
+ self .ac_to_time_limit = parse_setting (time_multipliers , "ac_to_time_limit" , 2.0 , ">= 1" )
138
141
parse_deprecated_setting (yaml_data , "time_safety_margin" , "time_limit_to_tle" )
139
- self .time_limit_to_tle = parse_setting (time_multipliers , "time_limit_to_tle" , 1.5 )
142
+ self .time_limit_to_tle = parse_setting (time_multipliers , "time_limit_to_tle" , 1.5 , ">= 1" )
140
143
141
144
check_unknown_keys (time_multipliers , "limits.time_multipliers" )
142
145
143
- time_limit = parse_optional_setting (yaml_data , "time_limit" , float ) # in seconds
144
- self .time_resolution : float = parse_setting (yaml_data , "time_resolution" , 1.0 )
145
- self .memory : int = parse_setting (yaml_data , "memory" , 2048 ) # in MiB
146
- self .output : int = parse_setting (yaml_data , "output" , 8 ) # in MiB
147
- self .code : int = parse_setting (yaml_data , "code" , 128 ) # in KiB
148
- self .compilation_time : int = parse_setting (yaml_data , "compilation_time" , 60 ) # in seconds
146
+ self .time_limit_is_default : bool = "time_limit" not in yaml_data
147
+ self .time_limit : float = parse_setting (yaml_data , "time_limit" , 1.0 , "> 0" ) # in seconds
148
+ self .time_resolution : float = parse_setting (yaml_data , "time_resolution" , 1.0 , "> 0" )
149
+ self .memory : int = parse_setting (yaml_data , "memory" , 2048 , "> 0" ) # in MiB
150
+ self .output : int = parse_setting (yaml_data , "output" , 8 , "> 0" ) # in MiB
151
+ self .code : int = parse_setting (yaml_data , "code" , 128 , "> 0" ) # in KiB
152
+ self .compilation_time : int = parse_setting (
153
+ yaml_data , "compilation_time" , 60 , "> 0"
154
+ ) # in seconds
149
155
self .compilation_memory : int = parse_setting (
150
- yaml_data , "compilation_memory" , 2048
156
+ yaml_data , "compilation_memory" , 2048 , "> 0"
151
157
) # in MiB
152
- self .validation_time : int = parse_setting (yaml_data , "validation_time" , 60 ) # in seconds
153
- self .validation_memory : int = parse_setting (yaml_data , "validation_memory" , 2048 ) # in MiB
154
- self .validation_output : int = parse_setting (yaml_data , "validation_output" , 8 ) # in MiB
155
- self .validation_passes : Optional [int ] = parse_optional_setting (
156
- yaml_data , "validation_passes" , int
157
- )
158
+ self .validation_time : int = parse_setting (
159
+ yaml_data , "validation_time" , 60 , "> 0"
160
+ ) # in seconds
161
+ self .validation_memory : int = parse_setting (
162
+ yaml_data , "validation_memory" , 2048 , "> 0"
163
+ ) # in MiB
164
+ self .validation_output : int = parse_setting (
165
+ yaml_data , "validation_output" , 8 , "> 0"
166
+ ) # in MiB
167
+ if problem_settings .multi_pass :
168
+ self .validation_passes : Optional [int ] = parse_setting (
169
+ yaml_data , "validation_passes" , 2 , ">= 2"
170
+ )
171
+ elif "validation_passes" in yaml_data :
172
+ yaml_data .pop ("validation_passes" )
173
+ warn ("limit: validation_passes is only used for multi-pass problems. SKIPPED." )
158
174
159
175
# BAPCtools extensions:
160
- self .generator_time : int = parse_setting (yaml_data , "generator_time" , 60 ) # in seconds
161
- self .visualizer_time : int = parse_setting (yaml_data , "visualizer_time" , 60 ) # in seconds
176
+ self .generator_time : int = parse_setting (
177
+ yaml_data , "generator_time" , 60 , "> 0"
178
+ ) # in seconds
179
+ self .visualizer_time : int = parse_setting (
180
+ yaml_data , "visualizer_time" , 60 , "> 0"
181
+ ) # in seconds
162
182
163
183
# warn for deprecated timelimit files
164
184
if (problem .path / ".timelimit" ).is_file ():
@@ -168,9 +188,6 @@ def __init__(
168
188
"domjudge-problem.ini is DEPRECATED. Use limits.time_limit if you want to set a timelimit."
169
189
)
170
190
171
- self .time_limit : float = time_limit or 1.0
172
- self .time_limit_is_default : bool = time_limit is None
173
-
174
191
check_unknown_keys (yaml_data , "limits" )
175
192
176
193
# Override limmits by command line arguments.
@@ -233,18 +250,23 @@ def __init__(
233
250
self .uuid : str = parse_setting (yaml_data , "uuid" , "" )
234
251
self .version : str = parse_setting (yaml_data , "version" , "" )
235
252
self .credits : ProblemCredits = ProblemCredits (yaml_data , self )
236
- self .source : ProblemSources = ProblemSources (yaml_data , self )
253
+ self .source : ProblemSources = ProblemSources (yaml_data )
237
254
self .license : str = parse_setting (yaml_data , "license" , "unknown" )
238
- self .rights_owner : str = parse_setting (yaml_data , "rights_owner" , "" )
255
+ self .rights_owner : Optional [ str ] = parse_optional_setting (yaml_data , "rights_owner" , str )
239
256
# Not implemented in BAPCtools. Should be a date, but we don't do anything with this anyway.
240
- self .embargo_until : str = parse_setting (yaml_data , "embargo-until" , "" )
257
+ self .embargo_until : Optional [datetime .date ] = parse_optional_setting (
258
+ yaml_data ,
259
+ "embargo_until" ,
260
+ # Note that datetime.datetime is also valid, as subclass of datetime.date
261
+ datetime .date ,
262
+ )
241
263
self .limits = ProblemLimits (parse_setting (yaml_data , "limits" , {}), problem , self )
242
264
243
265
parse_deprecated_setting (
244
266
yaml_data , "validator_flags" , "output_validator_args' in 'testdata.yaml"
245
267
)
246
268
247
- self .keywords : str = parse_setting (yaml_data , "keywords" , "" )
269
+ self .keywords : list [ str ] = parse_optional_list_setting (yaml_data , "keywords" , str )
248
270
# Not implemented in BAPCtools. We always test all languges in langauges.yaml.
249
271
self .languages : list [str ] = parse_optional_list_setting (yaml_data , "languages" , str )
250
272
@@ -271,13 +293,6 @@ def __init__(
271
293
warn (f"invalid license: { self .license } " )
272
294
self .license = "unknown"
273
295
274
- # Check that limits.validation_passes exists if and only if the problem is multi-pass
275
- has_validation_passes = self .limits .validation_passes is not None
276
- if self .multi_pass and not has_validation_passes :
277
- self .limits .validation_passes = 2
278
- if not self .multi_pass and has_validation_passes :
279
- warn ("limit: validation_passes is only used for multi_pass problems. SKIPPED." )
280
-
281
296
282
297
# A problem.
283
298
class Problem :
0 commit comments