Skip to content

Commit 8dc779e

Browse files
authored
Update table (#24)
* Refactor * Refactor * Typing * Typing * Typing * Typing * .venv * Typing * Functional tests * Functional tests * Functional tests * Update section * Update section * Update section * Update section * Update section
1 parent 74d9b3b commit 8dc779e

File tree

11 files changed

+227
-145
lines changed

11 files changed

+227
-145
lines changed

.github/workflows/functional_tests.yaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ jobs:
1616
uses: actions/checkout@v4
1717
with:
1818
ref: ${{ github.event.pull_request.head.ref }}
19+
- name: Set up README
20+
shell: bash
21+
run: cp tests/README_TEMPLATE.md tests/README.md
1922
- name: Run our action
2023
uses: ./
2124
with:
@@ -29,6 +32,7 @@ jobs:
2932
echo "..."
3033
cat tests/EXPECTED_README.md
3134
echo "..."
32-
sed -i -E 's/[0-9]+\.[0-9]+ sec/x sec/' tests/README.md
33-
sed -i -E 's/[0-9]+ KB/y KB/' tests/README.md
35+
sed -i -E 's/[0-9]+\.[0-9]+/x/' tests/README.md
36+
sed -i -E 's/[0-9]+/y/' tests/README.md
37+
sed -i -E 's/[0-9]+/z/' tests/README.md
3438
diff --ignore-all-space --ignore-blank-lines tests/README.md tests/EXPECTED_README.md

.github/workflows/lint.yaml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,6 @@ jobs:
2020
python-version: '3.13'
2121
- name: Install poetry
2222
uses: abatilo/actions-poetry@v3
23-
- name: Configure poetry
24-
shell: bash
25-
run: poetry config virtualenvs.in-project true
26-
- name: Set up cache
27-
uses: actions/cache@v4
28-
id: cache
29-
with:
30-
path: .venv
31-
key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
3223
- name: Check poetry.lock consistency
3324
shell: bash
3425
run: poetry check --lock

.pyre_configuration

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{
22
"site_package_search_strategy": "pep561",
33
"source_directories": [
4-
"advent_of_action",
5-
"tests"
4+
"."
65
]
76
}

advent_of_action/main.py

Lines changed: 48 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,21 @@
11
"""Run every solution."""
22

33
import subprocess
4-
from collections.abc import Callable, Mapping, MutableMapping
4+
from collections.abc import Mapping, MutableMapping
55
from pathlib import Path
66
from typing import Final
77

8-
type Triple = tuple[int, float, str]
9-
type RunnerFunc = Callable[[Path], Triple]
10-
11-
12-
def execute_command(command: list[str | Path]) -> Triple:
13-
# Here rather than globally as it's easier to patch.
14-
print("Running", command)
15-
result = subprocess.run(
16-
["/usr/bin/time", "-f", "%M,%S,%U"] + command, capture_output=True, timeout=60, text=True, check=True
17-
)
18-
# todo
19-
# kilobytes, sys_seconds, user_seconds = result.stderr.split("\n")[-1].split(",")
20-
kilobytes, sys_seconds, user_seconds = result.stderr.split(",")
21-
return int(kilobytes), float(sys_seconds) + float(user_seconds), result.stdout
22-
23-
24-
def run_python(dirpath: Path) -> Triple:
25-
"""Run a Python solution."""
26-
return execute_command(["python", dirpath / "solution.py"])
27-
28-
29-
def run_racket(dirpath: Path) -> Triple:
30-
"""Run a Racket solution."""
31-
return execute_command(["racket", dirpath / "solution.rkt"])
32-
33-
34-
def run_rust(dirpath: Path) -> Triple:
35-
return execute_command(["cargo", "run", "--quiet", "--manifest-path", dirpath / "Cargo.toml"])
36-
37-
38-
def run_fsharp(dirpath: Path) -> Triple:
39-
return execute_command(["dotnet", "fsi", dirpath / "solution.fsx"])
40-
41-
42-
def run_ocaml(dirpath: Path) -> Triple:
43-
return execute_command(["ocaml", dirpath / "solution.ml"])
44-
45-
46-
def run_jupyter(dirpath: Path) -> Triple:
47-
return execute_command(["ipython", "-c", f"%run {dirpath / 'solution.ipynb'}"])
48-
8+
from advent_of_action import runners
9+
from advent_of_action.runners import RunnerFunc
4910

5011
# Languages and their commands
5112
RUNTIMES: Final[dict[str, RunnerFunc]] = {
52-
"python": run_python,
53-
"racket": run_racket,
54-
"rust": run_rust,
55-
"fsharp": run_fsharp,
56-
"ocaml": run_ocaml,
57-
"jupyter": run_jupyter,
13+
"python": runners.python,
14+
"racket": runners.racket,
15+
"rust": runners.rust,
16+
"fsharp": runners.fsharp,
17+
"ocaml": runners.ocaml,
18+
"jupyter": runners.jupyter,
5819
}
5920

6021
type Day = str
@@ -74,27 +35,48 @@ def measure_execution_time(dirpath: Path, ext: RunnerFunc) -> Stats:
7435
return "", "", "Different answer"
7536
except subprocess.CalledProcessError as e:
7637
return "", "", f"Error ({e.returncode})"
77-
return f"{seconds:.2f} sec", f"{kilobytes} KB", ""
38+
return f"{seconds:.2f}", f"{kilobytes}", ""
39+
40+
41+
def from_table(table: str) -> dict[Run, Stats]:
42+
results: dict[Run, Stats] = {}
43+
for line in table.split("\n")[6:]:
44+
if not line:
45+
break
46+
day, lang, person, seconds, kb, notes = line[1:-1].split(" | ")
47+
results[(day.strip(), lang.strip(), person.strip())] = (
48+
seconds.strip(),
49+
kb.strip(),
50+
notes.strip(),
51+
)
52+
return results
53+
54+
55+
def to_table(results: Mapping[Run, Stats]) -> str:
56+
table = "\n\n## Stats\n\n"
57+
table += "| day | language | who | time (s) | mem (KB) | notes |\n"
58+
table += "| --- | --- | --- | --- | --- | --- |\n"
59+
for (day, language, person), (seconds, kilobytes, notes) in results.items():
60+
table += f"| {day} | {language} | {person} | {seconds} | {kilobytes} | {notes} |\n"
61+
return table
7862

7963

8064
def write_results(the_results: Mapping[Run, Stats]) -> None:
81-
readme_path = "README.md"
82-
new_content = "\n## Results\n\n"
83-
new_content += "| day | language | who | time | mem | notes |\n"
84-
new_content += "| --- | --- | --- | --- | --- | --- |\n"
85-
for (day, language, person), (seconds, kilobytes, notes) in the_results.items():
86-
new_content += f"| {day} | {language} | {person} | {seconds} | {kilobytes} | {notes} |\n"
87-
88-
old_content = ""
89-
if Path(readme_path).exists():
90-
with open(readme_path) as f:
91-
lines = f.readlines()
92-
for line in lines:
93-
if line.strip() == "## Results":
94-
break
95-
old_content += line
96-
with open(readme_path, "w") as f:
97-
f.write(old_content + new_content)
65+
readme = Path("README.md")
66+
old_content = readme.read_text()
67+
section_begins = old_content.find("\n\n## Stats")
68+
if section_begins > -1:
69+
section_ends = old_content.find("\n\n##", section_begins + 1)
70+
section = old_content[section_begins:section_ends] if section_ends else old_content[section_begins:]
71+
old_dict = from_table(section)
72+
the_results = {**old_dict, **the_results}
73+
if section_ends > -1:
74+
new_content = old_content[:section_begins] + to_table(the_results) + old_content[section_ends:]
75+
else:
76+
new_content = old_content[:section_begins] + to_table(the_results)
77+
else:
78+
new_content = old_content + to_table(the_results)
79+
readme.write_text(new_content)
9880

9981

10082
def main() -> None:

advent_of_action/runners.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import subprocess
2+
from collections.abc import Callable
3+
from pathlib import Path
4+
5+
type Triple = tuple[int, float, str]
6+
type RunnerFunc = Callable[[Path], Triple]
7+
8+
9+
def execute_command(command: list[str | Path]) -> Triple:
10+
"""Execute a command and return the memory usage, time and stdout."""
11+
print("Running", command)
12+
result = subprocess.run(
13+
["/usr/bin/time", "-f", "%M,%S,%U"] + command, capture_output=True, timeout=60, text=True, check=True
14+
)
15+
# todo
16+
# kilobytes, sys_seconds, user_seconds = result.stderr.split("\n")[-1].split(",")
17+
kilobytes, sys_seconds, user_seconds = result.stderr.split(",")
18+
return int(kilobytes), float(sys_seconds) + float(user_seconds), result.stdout
19+
20+
21+
def python(dirpath: Path) -> Triple:
22+
"""Run a Python solution."""
23+
return execute_command(["python", dirpath / "solution.py"])
24+
25+
26+
def racket(dirpath: Path) -> Triple:
27+
"""Run a Racket solution."""
28+
return execute_command(["racket", dirpath / "solution.rkt"])
29+
30+
31+
def rust(dirpath: Path) -> Triple:
32+
"""Run a Rust solution."""
33+
return execute_command(["cargo", "run", "--quiet", "--manifest-path", dirpath / "Cargo.toml"])
34+
35+
36+
def fsharp(dirpath: Path) -> Triple:
37+
"""Run an F# solution"""
38+
return execute_command(["dotnet", "fsi", dirpath / "solution.fsx"])
39+
40+
41+
def ocaml(dirpath: Path) -> Triple:
42+
"""Run an OCaml solution."""
43+
return execute_command(["ocaml", dirpath / "solution.ml"])
44+
45+
46+
def jupyter(dirpath: Path) -> Triple:
47+
"""Run a Jupyter notebook."""
48+
return execute_command(["ipython", "-c", f"%run {dirpath / 'solution.ipynb'}"])

tests/EXPECTED_README.md

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1+
# Title
12

2-
## Results
3+
A sentence.
34

4-
| day | language | who | time | mem | notes |
5+
## Stats
6+
7+
| day | language | who | time (s) | mem (KB) | notes |
58
| --- | --- | --- | --- | --- | --- |
6-
| 99 | fsharp | iain | x sec | y KB | |
7-
| 99 | jupyter | iain | x sec | y KB | |
8-
| 99 | ocaml | iain | x sec | y KB | |
9-
| 99 | python | iain | x sec | y KB | |
10-
| 99 | python | nain | | | Different answer |
11-
| 99 | python | zain | | | Error(1) |
12-
| 99 | racket | iain | x sec | y KB | |
13-
| 99 | rust | iain | x sec | y KB | |
9+
| y | python | iain | x | z | |
10+
| y | fsharp | iain | x | z | |
11+
| y | jupyter | iain | x | z | |
12+
| y | ocaml | iain | x | z | |
13+
| y | python | iain | x | z | |
14+
| y | python | nain | | | Different answer |
15+
| y | python | zain | | | Error(z) |
16+
| y | racket | iain | x | z | |
17+
| y | rust | iain | x | z | |
18+
19+
20+
## Section
21+
22+
Another sentence.

tests/EXPECTED_README_2.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Title
2+
3+
A sentence.
4+
5+
## Stats
6+
7+
| day | language | who | time (s) | mem (KB) | notes |
8+
| --- | --- | --- | --- | --- | --- |
9+
| 00 | python | iain | 2.34 | 1999 | |
10+
| 01 | python | iain | 0.01 | 1792 | |
11+
12+
13+
## Section
14+
15+
Another sentence.

tests/EXPECTED_README_3.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Title
2+
3+
A sentence.
4+
5+
6+
## Stats
7+
8+
| day | language | who | time (s) | mem (KB) | notes |
9+
| --- | --- | --- | --- | --- | --- |
10+
| 01 | python | iain | 0.01 | 1792 | |

tests/README_TEMPLATE.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Title
2+
3+
A sentence.
4+
5+
## Stats
6+
7+
| day | language | who | time | mem | notes |
8+
| --- | --- | --- | --- | --- | --- |
9+
| 00 | python | iain | 2.34 | 1999 | |
10+
11+
## Section
12+
13+
Another sentence.

tests/README_TEMPLATE_2.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Title
2+
3+
A sentence.

0 commit comments

Comments
 (0)