Skip to content

Commit 4415987

Browse files
committed
ProblemYaml & ProblemsYamlEntry: show more paths in warnings
1 parent 9de6cdd commit 4415987

File tree

3 files changed

+40
-13
lines changed

3 files changed

+40
-13
lines changed

bin/contest.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,25 @@ def dict(self) -> dict[str, object]:
5959

6060

6161
class ProblemsYamlEntry:
62-
def __init__(self, yaml_data: dict[object, object]) -> None:
62+
def __init__(self, yaml_data: dict[object, object], index: int) -> None:
6363
self.ok = False
6464
parser = YamlParser("problems.yaml", yaml_data)
6565

6666
def get_hex(rgb: Optional[str]) -> Optional[str]:
6767
if rgb is None:
6868
return None
6969
if not rgb.startswith("#"):
70-
error(f"invalid rgb value {rgb} in problems.yaml. SKIPPED")
70+
error(
71+
f"invalid rgb value '{rgb}' for problem {index} (id: {self.id}) in problems.yaml. SKIPPED"
72+
)
7173
return None
7274
hex_part = rgb[1:].lower()
7375
if len(hex_part) == 3:
7476
hex_part = "".join(c * 2 for c in hex_part)
7577
if len(hex_part) != 6 or any(c not in string.hexdigits for c in hex_part):
76-
error(f"invalid rgb value {rgb} in problems.yaml. SKIPPED")
78+
error(
79+
f"invalid rgb value '{rgb}' for problem {index} (id: {self.id}) in problems.yaml. SKIPPED"
80+
)
7781
return None
7882
return hex_part
7983

@@ -89,23 +93,27 @@ def get_hex(rgb: Optional[str]) -> Optional[str]:
8993
self.name: dict[str, str] = {}
9094
for lang, name in names.items():
9195
if not isinstance(lang, str):
92-
warn(f"invalid language '{lang}' in problems.yaml. SKIPPED.")
96+
warn(
97+
f"invalid language '{lang}' for problem {index} (id: {self.id}) in problems.yaml. SKIPPED."
98+
)
9399
elif not isinstance(name, str):
94-
warn(f"incompatible value for language '{lang}' in problems.yaml. SKIPPED.")
100+
warn(
101+
f"incompatible value for language '{lang}' for problem {index} (id: {self.id}) in problems.yaml. SKIPPED."
102+
)
95103
else:
96104
self.name[lang] = name
97105
self.time_limit: Optional[float] = parser.extract_optional("time_limit", float)
98106
if self.time_limit is not None and not self.time_limit > 0:
99107
error(
100-
f"value for 'time_limit' in problems.yaml should be > 0 but is {self.time_limit}. SKIPPED"
108+
f"value for 'time_limit' for problem {index} (id: {self.id}) in problems.yaml should be > 0 but is {self.time_limit}. SKIPPED"
101109
)
102110
self.time_limit = None
103111

104112
# contains remaining proper keys
105113
self._yaml = {k: v for k, v in parser.yaml.items() if isinstance(k, str) and v is not None}
106114
for key in parser.yaml:
107115
if key not in self._yaml:
108-
warn(f"invalid problems.yaml key: {key} in {self.id}")
116+
warn(f"invalid problems.yaml key: {key} for problem {index} (id: {self.id})")
109117

110118
self.ok = parser.errors == 0
111119

@@ -145,15 +153,15 @@ def problems_yaml() -> Sequence[ProblemsYamlEntry]:
145153

146154
problems = []
147155
labels: dict[str, str] = {}
148-
for yaml_data in raw_yaml:
156+
for i, yaml_data in enumerate(raw_yaml):
149157
if not isinstance(yaml_data, dict):
150158
error("entries in problems.yaml must be dicts.")
151159
continue
152-
problem = ProblemsYamlEntry(yaml_data)
160+
problem = ProblemsYamlEntry(yaml_data, i)
153161
if not problem.ok:
154162
continue
155163
if problem.label in labels:
156-
error(f"lebal {problem.label} found twice in problems.yaml")
164+
error(f"label {problem.label} found twice in problems.yaml")
157165
continue
158166
labels[problem.label] = problem.id
159167
if not Path(problem.id).is_dir():

bin/problem.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ def extract_optional_persons(source: YamlParser, key: str) -> list[Person]:
119119
self.translators = {}
120120
for lang in list(translators.yaml.keys()):
121121
if not isinstance(lang, str):
122-
warn(f"invalid language '{lang}' in problem.yaml. SKIPPED.")
122+
warn(
123+
f"invalid language `{lang}` for {translators.parent_str} in problem.yaml. SKIPPED."
124+
)
123125
else:
124126
self.translators[lang] = extract_optional_persons(translators, lang)
125127

@@ -322,9 +324,9 @@ def __init__(
322324
self.constants: dict[str, str] = {}
323325
for key, value in constants.items():
324326
if not isinstance(key, str) or not config.COMPILED_CONSTANT_NAME_REGEX.fullmatch(key):
325-
warn(f"invalid constant name: {key}. SKIPPED.")
327+
warn(f"invalid constant name `{key}` for `constants` in problem.yaml. SKIPPED.")
326328
elif not isinstance(value, (str, int, float)):
327-
warn(f"invalid constant type for: {key}. SKIPPED.")
329+
warn(f"invalid constant type for `constants.{key}` in problem.yaml. SKIPPED.")
328330
else:
329331
self.constants[key] = str(value)
330332

test/yaml/problem/invalid.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,23 @@ yaml:
217217
authors:
218218
- foo: "bar"
219219
warn: "found unknown problem.yaml key: foo in `credits.authors[0]`"
220+
---
221+
yaml:
222+
problem_format_version: 2025-09
223+
name: Invalid key type in credits.authors list
224+
credits:
225+
authors:
226+
- 42: "bar"
227+
warn: "invalid problem.yaml key: 42 in `credits.authors[0]`"
228+
---
229+
yaml:
230+
problem_format_version: 2025-09
231+
name: Invalid key type in credits.translators list
232+
credits:
233+
translators:
234+
en:
235+
- 42: "bar"
236+
warn: "invalid problem.yaml key: 42 in `credits.translators.en[0]`"
220237

221238
---
222239
# Source

0 commit comments

Comments
 (0)