1515
1616import cgi
1717import io
18+ import re
1819
1920import distutils .log
2021from distutils .command .check import check as _check
22+ import six
2123
2224from ..rst import render
2325
2426
27+ # Regular expression used to capture and reformat doctuils warnings into
28+ # something that a human can understand. This is loosely borrowed from
29+ # Sphinx: https://github.com/sphinx-doc/sphinx/blob
30+ # /c35eb6fade7a3b4a6de4183d1dd4196f04a5edaf/sphinx/util/docutils.py#L199
31+ _REPORT_RE = re .compile (
32+ r'^<string>:(?P<line>(?:\d+)?): '
33+ r'\((?P<level>DEBUG|INFO|WARNING|ERROR|SEVERE)/(\d+)?\) '
34+ r'(?P<message>.*)' , re .DOTALL | re .MULTILINE )
35+
36+
37+ @six .python_2_unicode_compatible
38+ class _WarningStream (object ):
39+ def __init__ (self ):
40+ self .output = io .StringIO ()
41+
42+ def write (self , text ):
43+ matched = _REPORT_RE .search (text )
44+
45+ if not matched :
46+ self .output .write (text )
47+ return
48+
49+ self .output .write (
50+ u"line {line}: {level_text}: {message}\n " .format (
51+ level_text = matched .group ('level' ).capitalize (),
52+ line = matched .group ('line' ),
53+ message = matched .group ('message' ).rstrip ('\r \n ' )))
54+
55+ def __str__ (self ):
56+ return self .output .getvalue ()
57+
58+
2559class Check (_check ):
2660 def check_restructuredtext (self ):
2761 """
@@ -45,18 +79,14 @@ def check_restructuredtext(self):
4579 "The project's long_description is either missing or empty." )
4680 return
4781
48- stream = io . StringIO ()
82+ stream = _WarningStream ()
4983 markup = render (data , stream = stream )
5084
51- for line in stream .getvalue ().splitlines ():
52- if line .startswith ("<string>" ):
53- line = line [8 :]
54- self .warn (line )
55-
5685 if markup is None :
5786 self .warn (
5887 "The project's long_description has invalid markup which will "
59- "not be rendered on PyPI." )
88+ "not be rendered on PyPI. The following syntax errors were "
89+ "detected:\n %s" % stream )
6090 return
6191
6292 self .announce (
0 commit comments