Patchwork [7,of,7,v2] import-checker: check docstrings in python

login
register
mail settings
Submitter timeless@mozdev.org
Date April 13, 2016, 5:21 p.m.
Message ID <7e891620eaded8f66262.1460568110@waste.org>
Download mbox | patch
Permalink /patch/14596/
State Rejected
Delegated to: Yuya Nishihara
Headers show

Comments

timeless@mozdev.org - April 13, 2016, 5:21 p.m.
# HG changeset patch
# User timeless <timeless@mozdev.org>
# Date 1460497442 0
#      Tue Apr 12 21:44:02 2016 +0000
# Node ID 7e891620eaded8f66262d7007307f1b986a1ba5f
# Parent  4fb9d603c45a64c98061abd264b3f691a6f336d0
import-checker: check docstrings in python
Simon Farnsworth - April 14, 2016, 10:15 a.m.
This version looks good to me.

Simon

On 13/04/2016 18:21, timeless wrote:
> # HG changeset patch
> # User timeless <timeless@mozdev.org>
> # Date 1460497442 0
> #      Tue Apr 12 21:44:02 2016 +0000
> # Node ID 7e891620eaded8f66262d7007307f1b986a1ba5f
> # Parent  4fb9d603c45a64c98061abd264b3f691a6f336d0
> import-checker: check docstrings in python
>
> diff --git a/contrib/import-checker.py b/contrib/import-checker.py
> --- a/contrib/import-checker.py
> +++ b/contrib/import-checker.py
> @@ -598,19 +598,41 @@
>       'from __future__ import print_function\\n'
>       example[11] doctest.py 11
>       'from __future__ import print_function\\\\\\n, absolute_import\\n'
> +
> +    >>> lines = [
> +    ... 'def x():',
> +    ... "    ''' # docstring",
> +    ... '    x()',
> +    ... '    >>> x() + 1',
> +    ... '    3',
> +    ... "    '''",
> +    ... '    return 2',
> +    ... ]
> +
> +    >>> test("example.py", lines)
> +    example[4] doctest.py 4
> +    'x() + 1\\n'
>       """
>       inlinepython = 0
>       shpython = 0
>       script = []
> -    prefix = 6
>       t = ''
> +    pystr = ''
>       n = 0
>       linecont = False
> +    if f.endswith('.t'):
> +        pyinlinestart = b'  >>> '
> +        pyinlinecont = b'  ... '
> +        prefix = 6
> +    else:
> +        pyinlinestart = b'>>> '
> +        pyinlinecont = b'... '
> +        prefix = 4
>       for l in src:
>           n += 1
>           if not l.endswith(b'\n'):
>               l += b'\n'
> -        if l.startswith(b'  >>> '): # python inlines
> +        if l.startswith(pyinlinestart): # python inlines
>               if shpython:
>                   print("Parse Error %s:%d\n" % (f, n))
>               if not inlinepython:
> @@ -620,7 +642,7 @@
>               script.append(l[prefix:])
>               linecont = l.strip('\n').endswith('\\')
>               continue
> -        if l.startswith(b'  ... '): # python inlines
> +        if l.startswith(pyinlinecont): # python inlines
>               script.append(l[prefix:])
>               linecont = l.strip('\n').endswith('\\')
>               continue
> @@ -652,6 +674,36 @@
>               inlinepython = 0
>               linecont = False
>               continue
> +        marker = l.lstrip()[:3]
> +        if pystr:
> +            if marker == pystr:
> +                pystr = ''
> +                if not inlinepython:
> +                    continue
> +                yield ''.join(script), ("%s[%d]" %
> +                       (modname, inlinepython)), t, inlinepython
> +                script = []
> +                inlinepython = 0
> +                linecont = False
> +                continue
> +            pydoc = re.search('^(\s*)>>> ', l)
> +            if pydoc:
> +                pyinlinestart = pydoc.group()
> +                pyinlinecont = pyinlinestart.replace('>>>', '...')
> +                prefix = len(pyinlinestart)
> +                inlinepython = n
> +                t = 'doctest.py'
> +                script.append(l[prefix:])
> +                linecont = l.strip('\n').endswith('\\')
> +                continue
> +            if pystr == l.strip()[-3:]:
> +                pystr = ''
> +                continue
> +        if marker in ("'''", '"""'):
> +            if l.lstrip()[3:].strip().endswith(marker):
> +                continue
> +            pystr = marker
> +            continue
>           if linecont:
>               script.append(l[prefix:])
>               linecont = l.strip('\n').endswith('\\')
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://urldefense.proofpoint.com/v2/url?u=https-3A__www.mercurial-2Dscm.org_mailman_listinfo_mercurial-2Ddevel&d=CwIGaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=mEgSWILcY4c4W3zjApBQLA&m=_iMB6_Kn6F7RPvUpC4aQG9kkUXvWvINbq15b3-cPwSo&s=IblBkPJ7r-CHk6sK4T65g6HtP8TPrtDowhFehqicbMM&e=
>
Yuya Nishihara - April 15, 2016, 2:51 p.m.
On Wed, 13 Apr 2016 12:21:50 -0500, timeless wrote:
> # HG changeset patch
> # User timeless <timeless@mozdev.org>
> # Date 1460497442 0
> #      Tue Apr 12 21:44:02 2016 +0000
> # Node ID 7e891620eaded8f66262d7007307f1b986a1ba5f
> # Parent  4fb9d603c45a64c98061abd264b3f691a6f336d0
> import-checker: check docstrings in python

I don't think it's worth running import-checker against doctests because
doctests inherit globals from the surrounding module. So we would never
write future imports in doctests, and would rarely have to add imports.

Patch

diff --git a/contrib/import-checker.py b/contrib/import-checker.py
--- a/contrib/import-checker.py
+++ b/contrib/import-checker.py
@@ -598,19 +598,41 @@ 
     'from __future__ import print_function\\n'
     example[11] doctest.py 11
     'from __future__ import print_function\\\\\\n, absolute_import\\n'
+
+    >>> lines = [
+    ... 'def x():',
+    ... "    ''' # docstring",
+    ... '    x()',
+    ... '    >>> x() + 1',
+    ... '    3',
+    ... "    '''",
+    ... '    return 2',
+    ... ]
+
+    >>> test("example.py", lines)
+    example[4] doctest.py 4
+    'x() + 1\\n'
     """
     inlinepython = 0
     shpython = 0
     script = []
-    prefix = 6
     t = ''
+    pystr = ''
     n = 0
     linecont = False
+    if f.endswith('.t'):
+        pyinlinestart = b'  >>> '
+        pyinlinecont = b'  ... '
+        prefix = 6
+    else:
+        pyinlinestart = b'>>> '
+        pyinlinecont = b'... '
+        prefix = 4
     for l in src:
         n += 1
         if not l.endswith(b'\n'):
             l += b'\n'
-        if l.startswith(b'  >>> '): # python inlines
+        if l.startswith(pyinlinestart): # python inlines
             if shpython:
                 print("Parse Error %s:%d\n" % (f, n))
             if not inlinepython:
@@ -620,7 +642,7 @@ 
             script.append(l[prefix:])
             linecont = l.strip('\n').endswith('\\')
             continue
-        if l.startswith(b'  ... '): # python inlines
+        if l.startswith(pyinlinecont): # python inlines
             script.append(l[prefix:])
             linecont = l.strip('\n').endswith('\\')
             continue
@@ -652,6 +674,36 @@ 
             inlinepython = 0
             linecont = False
             continue
+        marker = l.lstrip()[:3]
+        if pystr:
+            if marker == pystr:
+                pystr = ''
+                if not inlinepython:
+                    continue
+                yield ''.join(script), ("%s[%d]" %
+                       (modname, inlinepython)), t, inlinepython
+                script = []
+                inlinepython = 0
+                linecont = False
+                continue
+            pydoc = re.search('^(\s*)>>> ', l)
+            if pydoc:
+                pyinlinestart = pydoc.group()
+                pyinlinecont = pyinlinestart.replace('>>>', '...')
+                prefix = len(pyinlinestart)
+                inlinepython = n
+                t = 'doctest.py'
+                script.append(l[prefix:])
+                linecont = l.strip('\n').endswith('\\')
+                continue
+            if pystr == l.strip()[-3:]:
+                pystr = ''
+                continue
+        if marker in ("'''", '"""'):
+            if l.lstrip()[3:].strip().endswith(marker):
+                continue
+            pystr = marker
+            continue
         if linecont:
             script.append(l[prefix:])
             linecont = l.strip('\n').endswith('\\')