Skip to content

Commit b5238ec

Browse files
committed
chore: update README and validation script
1 parent b56bb8d commit b5238ec

File tree

2 files changed

+68
-85
lines changed

2 files changed

+68
-85
lines changed

simtools/README.md

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,28 @@ ignored. (It is a file with information that was gathered previously and is now
33
replaced by the individual files. As soon as all the information is
44
transferred, the file will be deleted.)
55

6-
The file for each simulator should have a name that is the same as the name of
7-
the simulator, avoiding spaces. Each file is a `YAML` file with the following
6+
The file for each simulator should have a name that is the same as the (short) name
7+
of the simulator, replacing spaces with hyphens. Each file is a `YAML` file with the following
88
structure (additional fields not mentioned below will be ignored; the values
9-
shown below are obviously example values):
9+
shown below are obviously example values) – the file shown here should be named `Simulator-Name.yaml`:
1010

1111
```yaml
12-
- name: Simulator Name
13-
- features: frontend, simulator
14-
- operating_system: Linux, MacOS
15-
- biological_level: Population Model, Single-Compartment (Simple) Model, Single-Compartment (Complex) Model, Multi-Compartment Model
16-
- processing_support: Single Machine, Cluster, Supercomputer, GPU
17-
- interface_language: Python
18-
- model_description_language: NeuroML/LEMS
19-
- summary: This simulator is very good.
20-
- urls:
21-
homepage: https://example.com
22-
email: contact@example.com
23-
- relations:
24-
- name: Another simulator
25-
description: exports to
26-
- name: Yet another simulator
27-
description: imports from
12+
name: Simulator Name
13+
features: frontend, simulator
14+
operating_system: Linux, MacOS
15+
biological_level: Population Model, Single-Compartment (Simple) Model, Single-Compartment (Complex) Model, Multi-Compartment Model
16+
processing_support: Single Machine, Cluster, Supercomputer, GPU
17+
interface_language: Python
18+
model_description_language: NeuroML/LEMS
19+
summary: This simulator is very good.
20+
urls:
21+
homepage: https://example.com
22+
email: contact@example.com
23+
relations:
24+
- name: Another simulator
25+
description: exports to
26+
- name: Yet another simulator
27+
description: imports from
2828
```
2929
The fields `features`, `operating_system`, `biological_level`,
3030
`processing_support`, `interface_language`, and `model_description_language`
@@ -33,14 +33,13 @@ are comma-separated strings (i.e. not yaml lists).
3333
The `features` fields should contain one or more of the following values: `frontend` (for
3434
interfaces to simulation engines), `simulator` (for simulation engines), `standard`
3535
(for interoperability standards, APIs, etc.), or `tool` (for a general tool).
36-
Only tools that are simulators should contain the `biological_level` and
37-
`processing_support` fields.
36+
Only tools that are simulators should contain the `biological_level` field.
3837

3938
The `urls` field contains entries that will be displayed as button labels. The
40-
following names are recognized: `documentation`, `installation`, `tutorial`,
39+
following names are recognized: `homepage`, `documentation`, `installation`, `tutorial`,
4140
`examples`, `email`, `chat`, `forum`, `issue tracker`, `source`, `download`.
4241
The `email` field should refer to an email address (which will be converted
43-
into a `mailto:` link), all other fields should give a full URL.
42+
into a `mailto:` link), all other fields should give a full URL.
4443

4544
Relations are a relationships between tools. The mentioned `name` needs to
4645
match the `name` of another simulator in the directory. The `description` of

tests/validate_data.py

Lines changed: 46 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -14,71 +14,55 @@
1414
import yaml
1515

1616

17-
def get_field(data, field):
18-
for item in data:
19-
if field in item:
20-
return item[field]
21-
return None
17+
class SimselectSchema(Schema):
18+
def validate(self, data, _is_simselect_schema=True):
19+
data = super().validate(data, _is_simselect_schema=False)
20+
if _is_simselect_schema and not "simulator" in data["features"]:
21+
if "biological_level" in data:
22+
raise SchemaError("biological_level is only valid for simulators")
23+
return data
2224

2325

24-
data_schema = Schema(
25-
[
26-
{
27-
"name": str,
28-
},
29-
{
30-
Optional("short_name"): str,
31-
},
32-
{
33-
"features": And(
34-
str,
35-
lambda s: all(
36-
ss.strip()
37-
in ["frontend", "simulator", "standard", "tool", "library", "API"]
38-
for ss in s.split(",")
39-
),
40-
error="features must be a comma-separated list of 'frontend', 'simulator', 'standard', 'tool', 'library', 'API'",
26+
data_schema = SimselectSchema(
27+
{
28+
"name": str,
29+
Optional("short_name"): str,
30+
"features": And(
31+
str,
32+
lambda s: all(
33+
ss.strip()
34+
in ["frontend", "simulator", "standard", "tool", "library", "API"]
35+
for ss in s.split(",")
4136
),
37+
error="features must be a comma-separated list of 'frontend', 'simulator', 'standard', 'tool', 'library', 'API'",
38+
),
39+
"operating_system": Or(str, None),
40+
Optional("biological_level"): Or(str, None),
41+
Optional("processing_support"): Or(str, None),
42+
"interface_language": Or(str, None),
43+
"summary": str,
44+
Optional("model_description_language"): Or(str, None),
45+
Optional("urls"): {
46+
Or(
47+
"homepage",
48+
"documentation",
49+
"installation",
50+
"tutorial",
51+
"examples",
52+
"email",
53+
"chat",
54+
"forum",
55+
"issue tracker",
56+
"source",
57+
"download",
58+
): (
59+
lambda url: isinstance(url, str)
60+
and url.startswith("http")
61+
or "@" in url
62+
)
4263
},
43-
{"operating_system": Or(str, None)},
44-
{
45-
"biological_level": Or(str, None),
46-
},
47-
{
48-
"processing_support": Or(str, None),
49-
},
50-
{
51-
"interface_language": Or(str, None),
52-
},
53-
{
54-
"summary": str,
55-
},
56-
{
57-
Optional("model_description_language"): Or(str, None),
58-
},
59-
{
60-
Optional("urls"): {
61-
Or(
62-
"homepage",
63-
"documentation",
64-
"installation",
65-
"tutorial",
66-
"examples",
67-
"email",
68-
"chat",
69-
"forum",
70-
"issue tracker",
71-
"source",
72-
"download",
73-
): (
74-
lambda url: isinstance(url, str)
75-
and url.startswith("http")
76-
or "@" in url
77-
)
78-
}
79-
},
80-
{Optional("relations"): [{"name": str, "description": str}]},
81-
]
64+
Optional("relations"): [{"name": str, "description": str}],
65+
}
8266
)
8367

8468
data_files = Path(Path(__file__).parent / ".." / "simtools")
@@ -99,7 +83,7 @@ def get_field(data, field):
9983
errors.append(datafile.name)
10084
print(f"!! {e}")
10185
print(f"!! {datafile} is invalid.")
102-
expected_name = get_field(text, "short_name") or get_field(text, "name")
86+
expected_name = text.get("short_name") or text.get("name")
10387
expected_name = expected_name.replace(" ", "-") + ".yaml"
10488
if datafile.name != expected_name:
10589
errors.append(datafile.name)

0 commit comments

Comments
 (0)