- Notifications
You must be signed in to change notification settings - Fork 46.7k
/
Copy pathvalidate_solutions.py
executable file
·99 lines (83 loc) · 3.45 KB
/
validate_solutions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#!/usr/bin/env python3
importhashlib
importimportlib.util
importjson
importos
importpathlib
fromtypesimportModuleType
importpytest
importrequests
PROJECT_EULER_DIR_PATH=pathlib.Path.cwd().joinpath("project_euler")
PROJECT_EULER_ANSWERS_PATH=pathlib.Path.cwd().joinpath(
"scripts", "project_euler_answers.json"
)
withopen(PROJECT_EULER_ANSWERS_PATH) asfile_handle:
PROBLEM_ANSWERS: dict[str, str] =json.load(file_handle)
defconvert_path_to_module(file_path: pathlib.Path) ->ModuleType:
"""Converts a file path to a Python module"""
spec=importlib.util.spec_from_file_location(file_path.name, str(file_path))
module=importlib.util.module_from_spec(spec) # type: ignore[arg-type]
spec.loader.exec_module(module) # type: ignore[union-attr]
returnmodule
defall_solution_file_paths() ->list[pathlib.Path]:
"""Collects all the solution file path in the Project Euler directory"""
solution_file_paths= []
forproblem_dir_pathinPROJECT_EULER_DIR_PATH.iterdir():
ifproblem_dir_path.is_file() orproblem_dir_path.name.startswith("_"):
continue
forfile_pathinproblem_dir_path.iterdir():
iffile_path.suffix!=".py"orfile_path.name.startswith(("_", "test")):
continue
solution_file_paths.append(file_path)
returnsolution_file_paths
defget_files_url() ->str:
"""Return the pull request number which triggered this action."""
withopen(os.environ["GITHUB_EVENT_PATH"]) asfile:
event=json.load(file)
returnevent["pull_request"]["url"] +"/files"
defadded_solution_file_path() ->list[pathlib.Path]:
"""Collects only the solution file path which got added in the current
pull request.
This will only be triggered if the script is ran from GitHub Actions.
"""
solution_file_paths= []
headers= {
"Accept": "application/vnd.github.v3+json",
"Authorization": "token "+os.environ["GITHUB_TOKEN"],
}
files=requests.get(get_files_url(), headers=headers, timeout=10).json()
forfileinfiles:
filepath=pathlib.Path.cwd().joinpath(file["filename"])
if (
filepath.suffix!=".py"
orfilepath.name.startswith(("_", "test"))
ornotfilepath.name.startswith("sol")
):
continue
solution_file_paths.append(filepath)
returnsolution_file_paths
defcollect_solution_file_paths() ->list[pathlib.Path]:
# Return only if there are any, otherwise default to all solutions
if (
os.environ.get("CI")
andos.environ.get("GITHUB_EVENT_NAME") =="pull_request"
and (filepaths:=added_solution_file_path())
):
returnfilepaths
returnall_solution_file_paths()
@pytest.mark.parametrize(
"solution_path",
collect_solution_file_paths(),
ids=lambdapath: f"{path.parent.name}/{path.name}",
)
deftest_project_euler(solution_path: pathlib.Path) ->None:
"""Testing for all Project Euler solutions"""
# problem_[extract this part] and pad it with zeroes for width 3
problem_number: str=solution_path.parent.name[8:].zfill(3)
expected: str=PROBLEM_ANSWERS[problem_number]
solution_module=convert_path_to_module(solution_path)
answer=str(solution_module.solution())
answer=hashlib.sha256(answer.encode()).hexdigest()
assertanswer==expected, (
f"Expected solution to {problem_number} to have hash {expected}, got {answer}"
)