Skip to content

Commit ca0b1c4

Browse files
authored
Improve validate solutions script & fix pre-commit error (TheAlgorithms#3253)
* Trying to time every solution * Proposal 2 for timing PE solutions: - Use pytest fixture along with --capture=no flag to print out the top DURATIONS slowest solution at the end of the test sessions. - Remove the print part and try ... except ... block from the test function. * Proposal 3 for timing PE solutions: Completely changed the way I was performing the tests. Instead of parametrizing the problem numbers and expected output, I will parametrize the solution file path. Steps: - Collect all the solution file paths - Convert the paths into a Python module - Call solution on the module - Assert the answer with the expected results For assertion, it was needed to convert the JSON list object to Python dictionary object which required changing the JSON file itself. * Add type hints for variables * Fix whitespace in single_qubit_measure
1 parent 12f416c commit ca0b1c4

File tree

3 files changed

+42
-42
lines changed

3 files changed

+42
-42
lines changed

Diff for: .travis.yml

+1-3
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@ jobs:
1616
script:
1717
- pytest --doctest-modules --durations=10 --cov-report=term-missing:skip-covered --cov=project_euler/ project_euler/
1818
- name: Project Euler Solution
19-
install:
20-
- pip install pytest-subtests
2119
script:
22-
- pytest --tb=short project_euler/validate_solutions.py
20+
- pytest --tb=short --durations=10 project_euler/validate_solutions.py
2321
after_success:
2422
- scripts/build_directory_md.py 2>&1 | tee DIRECTORY.md
2523
notifications:

Diff for: project_euler/validate_solutions.py

+39-37
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import json
44
import pathlib
55
from types import ModuleType
6-
from typing import Generator
6+
from typing import Dict, List
77

88
import pytest
99

@@ -13,42 +13,44 @@
1313
)
1414

1515
with open(PROJECT_EULER_ANSWERS_PATH) as file_handle:
16-
PROBLEM_ANSWERS = json.load(file_handle)
16+
PROBLEM_ANSWERS: Dict[str, str] = json.load(file_handle)
1717

1818

19-
def generate_solution_modules(
20-
dir_path: pathlib.Path,
21-
) -> Generator[ModuleType, None, None]:
22-
# Iterating over every file or directory
23-
for file_path in dir_path.iterdir():
24-
if file_path.suffix != ".py" or file_path.name.startswith(("_", "test")):
19+
def convert_path_to_module(file_path: pathlib.Path) -> ModuleType:
20+
"""Converts a file path to a Python module"""
21+
spec = importlib.util.spec_from_file_location(file_path.name, str(file_path))
22+
module = importlib.util.module_from_spec(spec)
23+
spec.loader.exec_module(module)
24+
return module
25+
26+
27+
def collect_solution_file_paths() -> List[pathlib.Path]:
28+
"""Collects all the solution file path in the Project Euler directory"""
29+
solution_file_paths = []
30+
for problem_dir_path in PROJECT_EULER_DIR_PATH.iterdir():
31+
if problem_dir_path.is_file() or problem_dir_path.name.startswith("_"):
2532
continue
26-
# Importing the source file through the given path
27-
# https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
28-
spec = importlib.util.spec_from_file_location(file_path.name, str(file_path))
29-
module = importlib.util.module_from_spec(spec)
30-
spec.loader.exec_module(module)
31-
yield module
32-
33-
34-
@pytest.mark.parametrize("problem_number, expected", PROBLEM_ANSWERS)
35-
def test_project_euler(subtests, problem_number: int, expected: str):
36-
problem_dir = PROJECT_EULER_DIR_PATH.joinpath(f"problem_{problem_number:02}")
37-
# Check if the problem directory exist. If not, then skip.
38-
if problem_dir.is_dir():
39-
for solution_module in generate_solution_modules(problem_dir):
40-
# All the tests in a loop is considered as one test by pytest so, use
41-
# subtests to make sure all the subtests are considered as different.
42-
with subtests.test(
43-
msg=f"Problem {problem_number} tests", solution_module=solution_module
44-
):
45-
try:
46-
answer = str(solution_module.solution())
47-
assert answer == expected, f"Expected {expected} but got {answer}"
48-
except (AssertionError, AttributeError, TypeError) as err:
49-
print(
50-
f"problem_{problem_number:02}/{solution_module.__name__}: {err}"
51-
)
52-
raise
53-
else:
54-
pytest.skip(f"Solution {problem_number} does not exist yet.")
33+
for file_path in problem_dir_path.iterdir():
34+
if file_path.suffix != ".py" or file_path.name.startswith(("_", "test")):
35+
continue
36+
solution_file_paths.append(file_path)
37+
return solution_file_paths
38+
39+
40+
def expand_parameters(param: pathlib.Path) -> str:
41+
"""Expand parameters in pytest parametrize"""
42+
project_dirname = param.parent.name
43+
solution_filename = param.name
44+
return f"{project_dirname}/{solution_filename}"
45+
46+
47+
@pytest.mark.parametrize(
48+
"solution_path", collect_solution_file_paths(), ids=expand_parameters
49+
)
50+
def test_project_euler(solution_path: pathlib.Path):
51+
"""Testing for all Project Euler solutions"""
52+
problem_number: str = solution_path.parent.name[8:] # problem_[extract his part]
53+
expected: str = PROBLEM_ANSWERS[problem_number]
54+
solution_module = convert_path_to_module(solution_path)
55+
answer = str(solution_module.solution())
56+
assert answer == expected, f"Expected {expected} but got {answer}"

Diff for: quantum/single_qubit_measure.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env python3
22
"""
3-
Build a simple bare-minimum quantum circuit that starts with a single
4-
qubit (by default, in state 0), runs the experiment 1000 times, and
3+
Build a simple bare-minimum quantum circuit that starts with a single
4+
qubit (by default, in state 0), runs the experiment 1000 times, and
55
finally prints the total count of the states finally observed.
66
Qiskit Docs: https://qiskit.org/documentation/getting_started.html
77
"""

0 commit comments

Comments
 (0)