Skip to content

Commit 25e45f8

Browse files
committed
[problem] Fully parse 'source' in problem.yaml
1 parent 0b6c5dc commit 25e45f8

File tree

2 files changed

+59
-8
lines changed

2 files changed

+59
-8
lines changed

bin/problem.py

+54-2
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,59 @@ def __init__(
8888
warn(f"found unknown problem.yaml key: {key} in credits")
8989

9090

91+
class ProblemSource:
92+
def __init__(self, name: str, url: Optional[str] = None):
93+
self.name = name
94+
self.url = url
95+
96+
def __repr__(self) -> str:
97+
return self.name + (f" ({self.url})" if self.url else "")
98+
99+
100+
class ProblemSources(list[ProblemSource]):
101+
def __init__(
102+
self,
103+
yaml_data: dict[str, Any],
104+
problem_settings: "ProblemSettings",
105+
):
106+
# If problem.yaml uses the legacy version, do not support the new type of the `source` key.
107+
# If problem.yaml uses 2023-07-draft, prefer `source`, but also support `source_url` and warn for it.
108+
legacy_source_url = parse_optional_setting(yaml_data, "source_url", str)
109+
if problem_settings.is_legacy():
110+
source_name = parse_setting(yaml_data, "source", "")
111+
if legacy_source_url:
112+
self.append(ProblemSource(source_name, legacy_source_url))
113+
else:
114+
if legacy_source_url is not None:
115+
warn("problem.yaml: source_url is removed in 2023-07-draft, please use source.url")
116+
if "source" not in yaml_data:
117+
return
118+
if isinstance(yaml_data["source"], str):
119+
self.append(ProblemSource(parse_setting(yaml_data, "source", "")))
120+
return
121+
if isinstance(yaml_data["source"], dict):
122+
source = parse_setting(yaml_data, "source", dict[str, str]())
123+
self.append(
124+
ProblemSource(
125+
parse_setting(source, "name", ""),
126+
parse_optional_setting(source, "url", str),
127+
)
128+
)
129+
return
130+
if isinstance(yaml_data["source"], list):
131+
sources = parse_setting(yaml_data, "source", list[dict[str, str]]())
132+
for raw_source in sources:
133+
source = parse_setting(raw_source, "source", dict[str, str]())
134+
self.append(
135+
ProblemSource(
136+
parse_setting(source, "name", ""),
137+
parse_optional_setting(source, "url", str),
138+
)
139+
)
140+
return
141+
warn("problem.yaml key 'source' does not have the correct type")
142+
143+
91144
class ProblemLimits:
92145
def __init__(
93146
self,
@@ -237,8 +290,7 @@ def __init__(
237290
self.uuid: str = parse_setting(yaml_data, "uuid", "")
238291
self.version: str = parse_setting(yaml_data, "version", "")
239292
self.credits = ProblemCredits(yaml_data, self)
240-
self.source: str = parse_setting(yaml_data, "source", "")
241-
self.source_url: str = parse_setting(yaml_data, "source_url", "")
293+
self.source = ProblemSources(yaml_data, self)
242294
self.license: str = parse_setting(yaml_data, "license", "unknown")
243295
self.rights_owner: str = parse_setting(yaml_data, "rights_owner", "")
244296
# Not implemented in BAPCtools. Should be a date, but we don't do anything with this anyway.

skel/problem/problem.yaml

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
# Specification: https://icpc.io/problem-package-format/spec/2023-07-draft.html
22
problem_format_version: 2023-07-draft
3+
type: {%type%}
34
name:
45
#lang: name
56
{%problemname%}
67
# 'pass-fail', 'interactive', 'multi-pass', or 'interactive multi-pass'
7-
type: {%type%}
8-
credits: {%author%}
9-
# Contest name and year
10-
source: {%source%}
11-
# contest.region.eu
12-
source_url: {%source_url%}
138
uuid: {%uuid%}
9+
credits: {%author%}
10+
source:
11+
name: {%source%}
12+
url: {%source_url%}
1413
license: {%license%}
1514
rights_owner: {%rights_owner%}
1615

0 commit comments

Comments
 (0)