Skip to content

Commit 5252b6c

Browse files
ankita240796adammichaelwood
authored andcommittedFeb 27, 2018
Literate programming (#515)
* add script to parse code blocks * add extra checks, remove current checks * add code-blocks to style-guide * ignore generated files * print only severe messages * fix newlines * fix comma regex, addresses getodk/docs#471 * custom check for but, addresses getodk/docs#467 * exclude inbuilt but and spelling checks, addresses getodk/docs#467 * add encoding * improve uk us check, addresses getodk/docs#471 (comment) * fix messages * separate checks for jargon * add comment for uk-us check * add extra latin abbr * add new adverbs * remove repeated phrase * fix message writing style * fix variable naming * add function to remove generated scripts * add show hide feature for style test code blocks * add python directive to ignore list * add math directive to ignore list
1 parent 5b60683 commit 5252b6c

18 files changed

+467
-319
lines changed
 

‎.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
style-checks.py
2+
extra.py
13
build/
24
__pycache__/
35
.DS_Store

‎src/_static/js/custom.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ $(function(){
77
"<div class='details'></div>"
88
)
99
});
10+
11+
// Wrap style-test code blocks with a details div.
12+
$(".style-checks, .extra-checks, .proselint-extra-checks").each(function(){
13+
$(this).wrap(
14+
"<div class='details'></div>"
15+
)
16+
});
1017
// Add a toggler to each details element.
1118
var id = 1000000
1219
$(".details").each(function(index){
@@ -16,13 +23,13 @@ $(function(){
1623
$(this).before(togl);
1724
$(this).addClass('hidden');
1825
$(this).has("img:only-child").addClass('screenshot-only');
26+
$(this).has(".style-checks, .extra-checks, .proselint-extra-checks").addClass('code-only');
1927
if ( $(this).is("img") ) {
2028
$(this).addClass("screenshot-only");
2129
}
2230
});
2331

2432
// Add class to list items that include togglers
25-
2633
$("li").has(".details").each(function(index){
2734
$(this).addClass("has-details");
2835
});
@@ -32,12 +39,16 @@ $(function(){
3239
showing_label = "[<span class='toggle-sign'>&minus;</span>] hide details";
3340
ss_hiding_label = "[<span class='toggle-sign'>&plus;</span>] show screenshot";
3441
ss_showing_label = "[<span class='toggle-sign'>&minus;</span>] hide screenshot";
42+
code_hiding_label = "[<span class='toggle-sign'>&plus;</span>] show code<br>";
43+
code_showing_label = "[<span class='toggle-sign'>&minus;</span>] hide code<br>";
3544

3645

3746
// Add labels and onclick function to togglers
3847
$(".toggler").each(function(index){
3948
if ($(this).siblings().hasClass('screenshot-only')) {
4049
$(this).html(ss_hiding_label);
50+
} else if ($(this).siblings().hasClass('code-only')) {
51+
$(this).html(code_hiding_label);
4152
} else {
4253
$(this).html(hiding_label);
4354
}
@@ -48,6 +59,8 @@ $(function(){
4859
toggle_image.removeClass("hidden");
4960
if ($(this).siblings().hasClass('screenshot-only')) {
5061
$(this).html(ss_showing_label);
62+
} else if ($(this).siblings().hasClass('code-only')) {
63+
$(this).html(code_showing_label);
5164
} else {
5265
$(this).html(showing_label);
5366
}
@@ -56,6 +69,8 @@ $(function(){
5669
toggle_image.addClass("hidden");
5770
if ($(this).siblings().hasClass('screenshot-only')) {
5871
$(this).html(ss_hiding_label);
72+
} else if ($(this).siblings().hasClass('code-only')) {
73+
$(this).html(code_hiding_label);
5974
} else {
6075
$(this).html(hiding_label);
6176
}

‎src/docs-style-guide.rst

+295-4
Large diffs are not rendered by default.

‎style-guide/check-howto.py

-15
This file was deleted.

‎style-guide/check-same.py

-16
This file was deleted.

‎style-guide/check-semicolon.py

-14
This file was deleted.

‎style-guide/check-space.py

-15
This file was deleted.

‎style-guide/extra.py

-88
This file was deleted.

‎style-guide/extrarun.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"""Utility module to run the extra checks on docs."""
2+
import importlib
3+
e = importlib.import_module('style-guide.extra', None)
4+
5+
def check(text):
6+
"""Run extra checks."""
7+
text = text.read()
8+
error = []
9+
errors = e.check_quotes(text) + e.check_curlyquotes(text)
10+
errors += e.check_label(text)
11+
errors = sorted(errors, key=lambda e: (e[2], e[3]))
12+
return errors

‎style-guide/filler-phrase.py

-21
This file was deleted.

‎style-guide/latin-abbr.py

-22
This file was deleted.

‎style-guide/personal-pronoun.py

-23
This file was deleted.

‎style-guide/uk-us.py ‎style-guide/proselint-extra.py

+24-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
# -*- coding: utf-8 -*-
22

3-
"""uk vs. us."""
4-
5-
from proselint.tools import memoize, preferred_forms_check
3+
"""Extra checks for proselint not generated by code parsing."""
64

5+
from proselint.tools import memoize, existence_check, preferred_forms_check
76

87
@memoize
98
def check_ukus(text):
10-
"""uk vs. us."""
9+
"""UK vs. US spelling usage."""
1110
err = "style-guide.uk-us"
1211
msg = "uk-vs-us-spell-check. '{}' is the preferred spelling."
1312

@@ -22,6 +21,7 @@ def check_ukus(text):
2221
["acclimatizes", ["acclimatises"]],
2322
["acclimatizing", ["acclimatising"]],
2423
["accouterments", ["accoutrements"]],
24+
["acknowledgment", ["acknowledgement"]],
2525
["eon", ["aeon"]],
2626
["eons", ["aeons"]],
2727
["aerogram", ["aerogramme"]],
@@ -1733,3 +1733,23 @@ def check_ukus(text):
17331733
]
17341734

17351735
return preferred_forms_check(text, preferences, err, msg)
1736+
1737+
@memoize
1738+
def check_space(text):
1739+
"""Use single space after sentence end."""
1740+
err = "style-guide.check-space"
1741+
msg = "Missing space after period."
1742+
regex = "[\.\?!][A-Z][a-z]"
1743+
1744+
return existence_check(text, [regex], err, msg, ignore_case=False,
1745+
require_padding=False)
1746+
1747+
@memoize
1748+
def check_but(text):
1749+
"""Don't start a paragraph with but."""
1750+
err = "style-guide.check-but"
1751+
msg = u"No paragraph should start with a 'But'."
1752+
regex = "\n[ ]*\n[ ]*But"
1753+
1754+
return existence_check(text, [regex], err, msg, ignore_case=False,
1755+
require_padding=False)

‎style-guide/serial-comma.py

-14
This file was deleted.

‎style-guide/spelling-odk.py

-30
This file was deleted.

‎style-guide/unneed-adverb.py

-22
This file was deleted.

‎style-test.py

+116-19
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@
1010
import importlib
1111
import proselint
1212
from blessings import Terminal
13+
from docutils.core import publish_doctree
1314

1415
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
1516

17+
# path of docs directory
18+
dir_path = os.path.dirname(os.path.realpath(__file__))
19+
1620
# variables to hold error and warning count
1721
err_cnt = 0
1822
warn_cnt = 0
@@ -25,10 +29,73 @@
2529
os.environ["TERMINFO"]= "/etc/terminfo"
2630
t = Terminal()
2731

32+
def parse_code():
33+
"""Parse python code-blocks."""
34+
global dir_path
35+
test_file = dir_path + '/style-guide/style-checks.py'
36+
extra_file = dir_path + '/style-guide/extra.py'
37+
38+
def is_style_code_block(node):
39+
"""Check for style-checks python code-blocks."""
40+
return (node.tagname == 'literal_block'
41+
and 'code' in node.attributes['classes']
42+
and 'python' in node.attributes['classes']
43+
and 'style-checks' in node.attributes['classes'])
44+
45+
def is_extra_code_block(node):
46+
"""Check for extra-checks python code-blocks."""
47+
return (node.tagname == 'literal_block'
48+
and 'code' in node.attributes['classes']
49+
and 'python' in node.attributes['classes']
50+
and 'extra-checks' in node.attributes['classes'])
51+
52+
style_guide = open(dir_path + "/src/docs-style-guide.rst", "r")
53+
54+
# publish doctree, report only severe errors
55+
doctree = publish_doctree(style_guide.read(),
56+
settings_overrides = {'report_level': 4})
57+
58+
# write source code into style-check file
59+
code_blocks = doctree.traverse(condition=is_style_code_block)
60+
source_code = [block.astext() for block in code_blocks]
61+
62+
f = open(test_file,"w+")
63+
f.write("# -*- coding: utf-8 -*-\n\n")
64+
f.write('"""Style Guide testing."""\n\n')
65+
66+
# modules to import from proselint
67+
modules = "memoize, existence_check, preferred_forms_check"
68+
f.write("from proselint.tools import %s\n" %modules)
69+
70+
for line in source_code:
71+
if not line.endswith('\n'):
72+
line = line + "\n"
73+
if "@memoize" in line:
74+
line = "\n" + line
75+
f.write(line)
76+
77+
# write source code into extra file
78+
code_blocks = doctree.traverse(condition=is_extra_code_block)
79+
source_code = [block.astext() for block in code_blocks]
80+
81+
f = open(extra_file,"w+")
82+
f.write("# -*- coding: utf-8 -*-\n\n")
83+
f.write('"""Style Guide testing."""\n\n')
84+
f.write("import re\n")
85+
f.write("from proselint.tools import line_and_column\n")
86+
87+
for line in source_code:
88+
if not line.endswith('\n'):
89+
line = line + "\n"
90+
if "def" in line:
91+
line = "\n" + line
92+
f.write(line)
93+
94+
2895
def add_checks():
2996
"""Add checks to proselint."""
30-
file_path = os.path.realpath(__file__)
31-
src = file_path[0:file_path.rfind('/')] + '/style-guide'
97+
global dir_path
98+
src = dir_path + '/style-guide'
3299
dest = os.path.dirname(proselint.__file__)
33100
dest_prc = dest + '/.proselintrc'
34101
dest = dest + '/checks/style-guide'
@@ -70,7 +137,8 @@ def add_checks():
70137
def remove_lines(text):
71138
"""Remove ignored lines and directive blocks from text."""
72139
directive_list = [".. image::", ".. figure::", ".. video::", ".. code::",
73-
".. code-block::", ".. csv-table::", ".. toctree::",]
140+
".. code-block::", ".. csv-table::", ".. toctree::",
141+
".. py:", ".. math::",]
74142

75143
index = 0
76144
length = len(text)
@@ -187,6 +255,7 @@ def exclude_checks():
187255
"""Removes the checks which are to be excluded."""
188256
list_exclude = [
189257
"typography.symbols", "weasel_words.very",
258+
"misc.but", "consistency.spelling",
190259
]
191260
dest = os.path.dirname(proselint.__file__)
192261
dest_prc = dest + '/.proselintrc'
@@ -206,10 +275,10 @@ def exclude_checks():
206275

207276
def get_paths(paths):
208277
"""Return a list of files to run the checks on."""
209-
file_path = os.path.realpath(__file__)
278+
global dir_path
210279

211280
# find path for all .rst files
212-
search_path = file_path[0:file_path.rfind('/')] + "/src"
281+
search_path = dir_path + "/src"
213282

214283
# Make a list of paths to check for
215284
path_list = []
@@ -235,13 +304,13 @@ def get_paths(paths):
235304

236305
def get_changed_files():
237306
"""Return currently modified rst files."""
238-
file_path = os.path.realpath(__file__)
239-
repo_path = file_path[0:file_path.rfind('/')]
307+
global dir_path
308+
repo_path = dir_path
240309
repo = git.Repo(repo_path)
241-
changedFiles = [item.a_path for item in repo.index.diff(None)]
242-
changedFiles += repo.untracked_files
243-
changedFiles = tuple(changedFiles)
244-
return changedFiles
310+
changed_files = [item.a_path for item in repo.index.diff(None)]
311+
changed_files += repo.untracked_files
312+
changed_files = tuple(changed_files)
313+
return changed_files
245314

246315

247316
def run_checks(paths, disp, fix):
@@ -266,7 +335,7 @@ def run_checks(paths, disp, fix):
266335
text = remove_lines(text)
267336

268337
# Import extra check module from style-guide
269-
extra = importlib.import_module('style-guide.extra', None)
338+
extra = importlib.import_module('style-guide.extrarun', None)
270339

271340
# run checks for quotes, curly quotes, section labels
272341
errors = extra.check(temp_file(text))
@@ -335,7 +404,7 @@ def disp_checks(errors, filename, shortname):
335404
# e[0]=check
336405
# Set warning or error severity
337406
# Don't set errors for style-guide as they might be examples
338-
if e[0] in list_errors and "style-guide.rst" not in shortname:
407+
if e[0] in list_errors and shortname != "docs-style-guide.rst":
339408
severity = "error"
340409
else:
341410
severity = "warning"
@@ -365,8 +434,20 @@ def disp_cnt():
365434
global warn_cnt
366435
global t
367436

368-
print(t.yellow("Found %d warnings" %warn_cnt))
369-
print(t.red("Found %d errors") %err_cnt)
437+
warn = "%d warnings." %warn_cnt
438+
err = "%d errors." %err_cnt
439+
440+
if warn_cnt == 0:
441+
warn = "no warnings!"
442+
elif warn_cnt == 1:
443+
warn = "1 warning."
444+
if err_cnt == 0:
445+
err = "no errors!"
446+
elif err_cnt == 1:
447+
err = "1 error."
448+
449+
print(t.yellow("Testing found %s" %warn))
450+
print(t.red("Testing found %s" %err))
370451
if err_cnt:
371452
raise Exception("Style-guide testing failed! Fix the errors")
372453

@@ -426,17 +507,30 @@ def gen_list(paths = None):
426507

427508
return err_list
428509

510+
def remove_file():
511+
"""Remove generated check files."""
512+
global dir_path
513+
test_file = dir_path + '/style-guide/style-checks.py'
514+
extra_file = dir_path + '/style-guide/extra.py'
515+
os.remove(test_file)
516+
os.remove(extra_file)
517+
429518

430519
@click.command(context_settings = CONTEXT_SETTINGS)
431520
@click.option('--diff', '-d', is_flag = True,
432521
help = "Run check on the modified files")
433522
@click.option('--fix', '-f', is_flag = True,
434-
help = "Removes the fixable errors")
523+
help = "Remove the fixable errors")
435524
@click.option('--out_path','-o', type = click.Path())
525+
@click.option('--store','-s',is_flag = True,
526+
help = "Store the generated test scripts")
436527
@click.argument('in_path', nargs = -1, type = click.Path())
437528
def style_test(in_path = None, out_path = None, diff = None,
438-
fix = None, output = None):
439-
"""A CLI for style guide testing"""
529+
fix = None, output = None, store = None):
530+
"""A CLI for style guide testing."""
531+
# generate source code for checks
532+
parse_code()
533+
440534
# add custom style-guide checks to proselint
441535
add_checks()
442536

@@ -456,7 +550,10 @@ def style_test(in_path = None, out_path = None, diff = None,
456550
# generate output
457551
if out_path:
458552
gen_out(out_path)
459-
553+
554+
# remove generated test scripts
555+
if not store:
556+
remove_file()
460557

461558
if __name__ == '__main__':
462559
style_test()

‎style-test.txt

+2-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,2 @@
1-
"style-guide.spelling-odk" : true,
2-
"style-guide.uk-us" : true,
3-
"style-guide.latin-abbr" : true,
4-
"style-guide.unneed-adverb" : true,
5-
"style-guide.filler-phrase" : true,
6-
"style-guide.personal-pronoun" : true,
7-
"style-guide.serial-comma" : true,
8-
"style-guide.check-same" : true,
9-
"style-guide.check-semicolon" : true,
10-
"style-guide.check-howto" : true,
11-
"style-guide.check-space" : true
1+
"style-guide.style-checks" : true,
2+
"style-guide.proselint-extra" : true

0 commit comments

Comments
 (0)
Please sign in to comment.