--- a/contrib/check-code.py Fri Mar 01 02:53:09 2019 +0900
+++ b/contrib/check-code.py Fri Mar 01 02:53:09 2019 +0900
@@ -40,6 +40,8 @@
except ImportError:
re2 = None
+import testparseutil
+
def compilere(pat, multiline=False):
if multiline:
pat = '(?m)' + pat
@@ -402,6 +404,15 @@
] + commonpypats[1]
]
+# patterns to check *.py for embedded ones in test script
+embeddedpypats = [
+ [
+ ] + commonpypats[0],
+ # warnings
+ [
+ ] + commonpypats[1]
+]
+
# common filters to convert *.py
commonpyfilters = [
(r"""(?msx)(?P<comment>\#.*?$)|
@@ -426,6 +437,10 @@
[],
]
+# filters to convert *.py for embedded ones in test script
+embeddedpyfilters = [
+] + commonpyfilters
+
# extension non-filter patterns
pyextnfpats = [
[(r'^"""\n?[A-Z]', "don't capitalize docstring title")],
@@ -560,6 +575,15 @@
allfilesfilters, allfilespats),
]
+# (desc,
+# func to pick up embedded code fragments,
+# list of patterns to convert target files
+# list of patterns to detect errors/warnings)
+embeddedchecks = [
+ ('embedded python',
+ testparseutil.pyembedded, embeddedpyfilters, embeddedpypats)
+]
+
def _preparepats():
def preparefailandwarn(failandwarn):
for pats in failandwarn:
@@ -580,7 +604,7 @@
for i, flt in enumerate(filters):
filters[i] = re.compile(flt[0]), flt[1]
- for cs in (checks,):
+ for cs in (checks, embeddedchecks):
for c in cs:
failandwarn = c[-1]
preparefailandwarn(failandwarn)
@@ -674,6 +698,30 @@
if fc:
result = False
+ if f.endswith('.t') and "no-" "check-code" not in pre:
+ if debug:
+ print("Checking embedded code in %s" % (f))
+
+ prelines = pre.splitlines()
+ embeddederros = []
+ for name, embedded, filters, pats in embeddedchecks:
+ # "reset curmax at each repetition" treats maxerr as "max
+ # nubmer of errors in an actual file per entry of
+ # (embedded)checks"
+ curmaxerr = maxerr
+
+ for found in embedded(f, prelines, embeddederros):
+ filename, starts, ends, code = found
+ fc = _checkfiledata(name, f, code, filters, pats, context,
+ logfunc, curmaxerr, warnings, blame, debug,
+ lineno, offset=starts - 1)
+ if fc:
+ result = False
+ if curmaxerr:
+ if fc >= curmaxerr:
+ break
+ curmaxerr -= fc
+
return result
def _checkfiledata(name, f, filedata, filters, pats, context,
--- a/tests/test-contrib-check-code.t Fri Mar 01 02:53:09 2019 +0900
+++ b/tests/test-contrib-check-code.t Fri Mar 01 02:53:09 2019 +0900
@@ -379,3 +379,51 @@
> class empty(object):
omit superfluous pass
[1]
+
+Check code fragments embedded in test script
+
+ $ cat > embedded-code.t <<NO_CHECK_EOF
+ > code fragment in doctest style
+ > >>> x = (1,2)
+ > ...
+ > ... x = (1,2)
+ >
+ > code fragment in heredoc style
+ > $ python <<EOF
+ > > x = (1,2)
+ > > EOF
+ >
+ > code fragment in file heredoc style
+ > $ python > file.py <<EOF
+ > > x = (1,2)
+ > > EOF
+ > NO_CHECK_EOF
+ $ "$check_code" embedded-code.t
+ embedded-code.t:2:
+ > x = (1,2)
+ missing whitespace after ,
+ embedded-code.t:4:
+ > x = (1,2)
+ missing whitespace after ,
+ embedded-code.t:8:
+ > x = (1,2)
+ missing whitespace after ,
+ embedded-code.t:13:
+ > x = (1,2)
+ missing whitespace after ,
+ [1]
+
+"max warnings per file" is shared by all embedded code fragments
+
+ $ "$check_code" --per-file=3 embedded-code.t
+ embedded-code.t:2:
+ > x = (1,2)
+ missing whitespace after ,
+ embedded-code.t:4:
+ > x = (1,2)
+ missing whitespace after ,
+ embedded-code.t:8:
+ > x = (1,2)
+ missing whitespace after ,
+ (too many errors, giving up)
+ [1]