Skip to content

Commit e968ef6

Browse files
committed
Run corpus tests after regression test
1 parent e69e6ee commit e968ef6

File tree

4 files changed

+103
-21
lines changed

4 files changed

+103
-21
lines changed

.github/workflows/test_corpus.yaml

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,31 @@ on:
1818
description: 'Regenerate results'
1919
required: true
2020
default: true
21+
workflow_call:
22+
inputs:
23+
ref:
24+
description: 'Git ref to test'
25+
required: true
26+
type: string
27+
base-ref:
28+
type: string
29+
description: 'Git ref to compare against'
30+
required: true
31+
regenerate-results:
32+
type: boolean
33+
description: 'Regenerate results'
34+
required: false
35+
default: false
2136

2237
jobs:
2338
generate_results:
2439
name: Minify Corpus
2540
runs-on: self-hosted
26-
if: ${{ inputs.regenerate-results }}
2741
strategy:
2842
fail-fast: false
2943
matrix:
3044
python: ["python2.7", "python3.3", "python3.4", "python3.5", "python3.6", "python3.7", "python3.8", "python3.9", "python3.10", "python3.11"]
45+
ref: ["${{ inputs.ref }}", "${{ inputs.base-ref }}"]
3146
container:
3247
image: danielflook/python-minifier-build:${{ matrix.python }}-2022-10-25
3348
volumes:
@@ -45,7 +60,7 @@ jobs:
4560
- name: Checkout ref
4661
uses: actions/checkout@v3
4762
with:
48-
ref: ${{ inputs.ref }}
63+
ref: ${{ matrix.ref }}
4964
path: python-minifier
5065

5166
- name: Install ref
@@ -59,7 +74,7 @@ jobs:
5974
6075
- name: Run tests
6176
run: |
62-
${{matrix.python}} workflow/corpus_test/generate_results.py /corpus /corpus-results $(<sha.txt)
77+
${{matrix.python}} workflow/corpus_test/generate_results.py /corpus /corpus-results $(<sha.txt) ${{ inputs.regenerate-results }}
6378
6479
generate_report:
6580
name: Generate Report

.github/workflows/xtest.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,11 @@ jobs:
3636
fi
3737
3838
tox -r -e $(echo "${{ matrix.python }}" | tr -d .) xtest
39+
40+
test-corpus:
41+
needs: test
42+
name: Minify Corpus
43+
uses: ./.github/workflows/test_corpus.yaml
44+
with:
45+
ref: ${{ github.ref }}
46+
base-ref: ${{ github.base_ref }}

corpus_test/generate_report.py

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@
66

77
from result import Result, ResultReader
88

9-
ENHANCED_REPORT = False
9+
ENHANCED_REPORT = True
10+
1011

1112
@dataclass
1213
class ResultSet:
14+
"""
15+
A set of results from minifying a corpus using a specific version of Python and a specific version of python-minifier
16+
"""
17+
1318
python_version: str
1419
sha: str
1520

@@ -106,7 +111,16 @@ def compare_size_decrease(self, base: 'ResultSet') -> Iterable[Result]:
106111
if result.minified_size < base_result.minified_size:
107112
yield result
108113

114+
109115
def result_summary(results_dir: str, python_version: str, sha: str) -> ResultSet:
116+
"""
117+
Return a summary of the results for a specific version of Python and a specific version of python-minifier
118+
119+
:param results_dir: The directory containing the results
120+
:param python_version: The version of Python
121+
:param sha: The git sha of the version of python-minifier
122+
"""
123+
110124
summary = ResultSet(python_version, sha)
111125

112126
results_file_path = os.path.join(results_dir, 'results_' + python_version + '_' + sha + '.csv')
@@ -118,7 +132,20 @@ def result_summary(results_dir: str, python_version: str, sha: str) -> ResultSet
118132

119133
return summary
120134

135+
121136
def format_difference(compare: Iterable[Result], base: Iterable[Result]) -> str:
137+
"""
138+
Return a string representing the difference between two sets of results
139+
140+
The returned string will include:
141+
- the size of the compare set
142+
- the number of new entries in the compare set that are not in the base set
143+
- and the number of entries that are in the base set but not in the compare set.
144+
145+
:param compare: The results we are interested in
146+
:param base: The results to compare against
147+
"""
148+
122149
compare_set = set(result.corpus_entry for result in compare)
123150
base_set = set(result.corpus_entry for result in base)
124151

@@ -139,6 +166,18 @@ def format_difference(compare: Iterable[Result], base: Iterable[Result]) -> str:
139166

140167

141168
def report(results_dir: str, minifier_ref: str, minifier_sha: str, base_ref: str, base_sha: str) -> Iterable[str]:
169+
"""
170+
Generate a report comparing the results of two versions of python-minifier
171+
172+
The report is generated as a markdown string.
173+
174+
:param results_dir: The directory containing the results
175+
:param minifier_ref: The git ref of the version of python-minifier
176+
:param minifier_sha: The git sha of the version of python-minifier
177+
:param base_ref: The git ref of the base version of python-minifier we are comparing against
178+
:param base_sha: The git sha of the base version of python-minifier we are comparing against
179+
"""
180+
142181
yield f'''
143182
# Python Minifier Test Report
144183
@@ -186,14 +225,14 @@ def format_size_change_detail() -> str:
186225
return s
187226

188227
yield (
189-
f'| {python_version} ' +
190-
f'| {summary.valid_count} ' +
191-
f'| {summary.mean_time:.3f} ({mean_time_change:+.3f}) ' +
192-
f'| {format_size_change_detail()} ' +
193-
f'| {format_difference(summary.larger_than_original(), base_summary.larger_than_original())} ' +
194-
f'| {format_difference(summary.recursion_error(), base_summary.recursion_error())} ' +
195-
f'| {format_difference(summary.unstable_minification(), base_summary.unstable_minification())} ' +
196-
f'| {format_difference(summary.exception(), base_summary.exception())} '
228+
f'| {python_version} ' +
229+
f'| {summary.valid_count} ' +
230+
f'| {summary.mean_time:.3f} ({mean_time_change:+.3f}) ' +
231+
f'| {format_size_change_detail()} ' +
232+
f'| {format_difference(summary.larger_than_original(), base_summary.larger_than_original())} ' +
233+
f'| {format_difference(summary.recursion_error(), base_summary.recursion_error())} ' +
234+
f'| {format_difference(summary.unstable_minification(), base_summary.unstable_minification())} ' +
235+
f'| {format_difference(summary.exception(), base_summary.exception())} '
197236
)
198237

199238
if ENHANCED_REPORT:
@@ -242,6 +281,7 @@ def format_size_change_detail() -> str:
242281
for entry in sorted(summary.entries.values(), key=lambda entry: entry.time, reverse=True)[:10]:
243282
yield f'| {entry.corpus_entry} | {entry.original_size} | {entry.minified_size} | {entry.time:.3f} |'
244283

284+
245285
def main():
246286
parser = argparse.ArgumentParser(description='Generate a test report for a given python-minifier ref')
247287
parser.add_argument('results_dir', type=str, help='Path to results directory', default='results')

corpus_test/generate_results.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
import argparse
2-
import logging
32
import os
43
import sys
54
import time
65

76
import python_minifier
87
from result import Result, ResultWriter
98

10-
logger = logging.getLogger()
11-
logger.setLevel(logging.INFO)
12-
139
try:
1410
RE = RecursionError
1511
except NameError:
1612
# Python 2
17-
class RE(Exception): pass
13+
class RE(Exception):
14+
pass
15+
1816

19-
def minify_test(corpus_path, corpus_entry):
17+
def minify_corpus_entry(corpus_path, corpus_entry):
2018
"""
19+
Minify a single entry in the corpus and return the result
20+
2121
:param str corpus_path: Path to the corpus
2222
:param str corpus_entry: A file in the corpus
23+
:rtype: Result
2324
"""
25+
2426
with open(os.path.join(corpus_path, corpus_entry), 'rb') as f:
2527
source = f.read()
2628

@@ -56,32 +58,49 @@ def minify_test(corpus_path, corpus_entry):
5658
return result
5759

5860

59-
def corpus_test(corpus_path, results_path, sha):
61+
def corpus_test(corpus_path, results_path, sha, regenerate_results):
6062
"""
63+
Test the minifier on the entire corpus
64+
65+
The results are written to a csv file in the results directory.
66+
The name of the file is results_<python_version>_<sha>.csv
67+
68+
If the file already exists and regenerate_results is False, the test is skipped.
69+
6170
:param str corpus_path: Path to the corpus
6271
:param str results_path: Path to the results directory
6372
:param str sha: The python-minifier sha we are testing
73+
:param bool regenerate_results: Regenerate results even if they are present
6474
"""
6575
corpus_entries = os.listdir(corpus_path)
6676

6777
python_version = '.'.join([str(s) for s in sys.version_info[:2]])
6878
results_file_path = os.path.join(results_path, 'results_' + python_version + '_' + sha + '.csv')
6979

80+
if os.path.isfile(results_file_path) and not regenerate_results:
81+
print('Results file already exists: %s', results_file_path)
82+
return
83+
7084
with ResultWriter(results_file_path) as result_writer:
7185
for entry in corpus_entries:
7286
print(entry)
73-
result = minify_test(corpus_path, entry)
87+
result = minify_corpus_entry(corpus_path, entry)
7488
result_writer.write(result)
7589

7690

91+
def bool_parse(value):
92+
return value == 'true'
93+
94+
7795
def main():
7896
parser = argparse.ArgumentParser(description='Test python-minifier on a corpus of Python files.')
7997
parser.add_argument('corpus_dir', type=str, help='Path to corpus directory', default='corpus')
8098
parser.add_argument('results_dir', type=str, help='Path to results directory', default='results')
8199
parser.add_argument('minifier_sha', type=str, help='The python-minifier sha we are testing')
100+
parser.add_argument('regenerate_results', type=bool_parse, help='Regenerate results even if they are present', default='false')
82101
args = parser.parse_args()
83102

84-
corpus_test(args.corpus_dir, args.results_dir, args.minifier_sha)
103+
corpus_test(args.corpus_dir, args.results_dir, args.minifier_sha, args.regenerate_results)
85104

86105

87106
if __name__ == '__main__':

0 commit comments

Comments
 (0)