[Python-checkins] python/nondist/peps pep2html.py,1.39,1.40

bwarsaw@users.sourceforge.net bwarsaw@users.sourceforge.net
Mon, 26 Aug 2002 09:54:56 -0700


Update of /cvsroot/python/python/nondist/peps
In directory usw-pr-cvs1:/tmp/cvs-serv28188

Modified Files:
	pep2html.py 
Log Message:
David Goodger writes:

* Refactored the file I/O model throughout, to support multiple
  processing paths.  PEP source text is now read into a list of lines.

* In ``fixfile()``:

  - Updated its parameters for the new I/O model.
  - Changed ``fo`` to ``outfile``, ``fi`` to ``inpath`` and
    ``input_lines``.
  - Input is read in by iterating over the list of input lines, rather
    than using "readlines()".
  - Opening and closing of files is done by the caller, "make_html()".
  - Added PEP number processing in Requires header.
  - Linked "Content-Type: text/plain" to PEP 9.

* Added ``fix_rst_pep()``, which imports and calls Docutils code.

* Added ``get_pep_type()``, which checks for a Content-Type header and
  returns the value, defaulting to "text/plain".  If no PEP header is
  found, ``None`` is returned: input is not a PEP.

* Added ``get_input_lines()`` to read input file into a list.

* Expanded ``make_html()`` to catch errors and process the different
  PEP formats via the new ``PEP_TYPE_DISPATCH`` dict.

* Added ``check_requirements()`` to check both Python and Docutils
  requirements.  ``pep_type_error()`` is called if the required
  software is not available.

* In ``main()``:

  - Added an ``argv`` parameter, so that pep2html.py can be imported
    and command-line options passed in.  Yes, I use this functionality
    in the Docutils "buildhtml.py" front end.
  - Files skipped (due to an error) are not pushed onto the server.


Index: pep2html.py
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep2html.py,v
retrieving revision 1.39
retrieving revision 1.40
diff -C2 -d -r1.39 -r1.40
*** pep2html.py	30 Jul 2002 16:25:17 -0000	1.39
--- pep2html.py	26 Aug 2002 16:54:54 -0000	1.40
***************
*** 1,5 ****
  #!/usr/bin/env python
! """
! convert PEP's to (X)HTML - courtesy of /F
  
  Usage: %(PROGRAM)s [options] [peps]
--- 1,4 ----
  #!/usr/bin/env python
! """Convert PEPs to (X)HTML - courtesy of /F
  
  Usage: %(PROGRAM)s [options] [peps]
***************
*** 18,25 ****
  
      -i/--install
!         After generating the HTML, install it and the plain text source file
!         (.txt) SourceForge.  In that case the user's name is used in the scp
!         and ssh commands, unless -u sf_username is given (in which case, it is
!         used instead).  Without -i, -u is ignored.
  
      -q/--quiet
--- 17,24 ----
  
      -i/--install
!         After generating the HTML, install it and the source file (.txt)
!         SourceForge.  In that case the user's name is used in the scp and ssh
!         commands, unless -u sf_username is given (in which case, that is used
!         instead).  Without -i, -u is ignored.
  
      -q/--quiet
***************
*** 32,37 ****
  """
  
- # Requires Python 2.2
- 
  import sys
  import os
--- 31,34 ----
***************
*** 43,52 ****
  import random
  import time
- from email.Utils import parseaddr
  
  PROGRAM = sys.argv[0]
  RFCURL = 'http://www.faqs.org/rfcs/rfc%d.html'
  PEPURL = 'pep-%04d.html'
! PEPCVSURL = 'http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/python/python/nondist/peps/pep-%04d.txt'
  PEPDIRRUL = 'http://www.python.org/peps/'
  
--- 40,51 ----
  import random
  import time
  
+ REQUIRES = {'python': '2.2',
+             'docutils': '0.2.1'}
  PROGRAM = sys.argv[0]
  RFCURL = 'http://www.faqs.org/rfcs/rfc%d.html'
  PEPURL = 'pep-%04d.html'
! PEPCVSURL = ('http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/python/python'
!              '/nondist/peps/pep-%04d.txt')
  PEPDIRRUL = 'http://www.python.org/peps/'
  
***************
*** 129,151 ****
  
  
! def fixfile(infile, outfile):
!     basename = os.path.basename(infile)
      # convert plain text pep to minimal XHTML markup
!     try:
!         fi = open(infile)
!     except IOError, e:
!         if e.errno <> errno.ENOENT: raise
!         print >> sys.stderr, 'Error: Skipping missing PEP file:', e.filename
!         return
!     fo = open(outfile, "w")
!     print >> fo, DTD
!     print >> fo, '<html>'
!     print >> fo, '<head>'
      # head
      header = []
      pep = ""
      title = ""
!     while 1:
!         line = fi.readline()
          if not line.strip():
              break
--- 128,144 ----
  
  
! def fixfile(inpath, input_lines, outfile):
!     from email.Utils import parseaddr
!     basename = os.path.basename(inpath)
!     infile = iter(input_lines)
      # convert plain text pep to minimal XHTML markup
!     print >> outfile, DTD
!     print >> outfile, '<html>'
!     print >> outfile, '<head>'
      # head
      header = []
      pep = ""
      title = ""
!     for line in infile:
          if not line.strip():
              break
***************
*** 168,192 ****
          title = "PEP " + pep + " -- " + title
      if title:
!         print >> fo, '  <title>%s</title>' % cgi.escape(title)
!     print >> fo, '  <link rel="STYLESHEET" href="style.css" type="text/css">'
!     print >> fo, '</head>'
!     # body
!     print >> fo, '<body bgcolor="white" marginwidth="0" marginheight="0">'
!     print >> fo, '<table class="navigation" cellpadding="0" cellspacing="0"'
!     print >> fo, '       width="100%" border="0">'
!     print >> fo, '<tr><td class="navicon" width="150" height="35">'
      r = random.choice(range(64))
!     print >> fo, '<a href="../" title="Python Home Page">'
!     print >> fo, '<img src="../pics/PyBanner%03d.gif" alt="[Python]"' % r
!     print >> fo, ' border="0" width="150" height="35" /></a></td>'
!     print >> fo, '<td class="textlinks" align="left">'
!     print >> fo, '[<b><a href="../">Python Home</a></b>]'
      if basename <> 'pep-0000.txt':
!         print >> fo, '[<b><a href=".">PEP Index</a></b>]'
      if pep:
!         print >> fo, '[<b><a href="pep-%04d.txt">PEP Source</a></b>]' \
                % int(pep)
!     print >> fo, '</td></tr></table>'
!     print >> fo, '<div class="header">\n<table border="0">'
      for k, v in header:
          if k.lower() in ('author', 'discussions-to'):
--- 161,185 ----
          title = "PEP " + pep + " -- " + title
      if title:
!         print >> outfile, '  <title>%s</title>' % cgi.escape(title)
      r = random.choice(range(64))
!     print >> outfile, (
!         '  <link rel="STYLESHEET" href="style.css" type="text/css">\n'
!         '</head>\n'
!         '<body bgcolor="white" marginwidth="0" marginheight="0">\n'
!         '<table class="navigation" cellpadding="0" cellspacing="0"\n'
!         '       width="100%%" border="0">\n'
!         '<tr><td class="navicon" width="150" height="35">\n'
!         '<a href="../" title="Python Home Page">\n'
!         '<img src="../pics/PyBanner%03d.gif" alt="[Python]"\n'
!         ' border="0" width="150" height="35" /></a></td>\n'
!         '<td class="textlinks" align="left">\n'
!         '[<b><a href="../">Python Home</a></b>]' % r)
      if basename <> 'pep-0000.txt':
!         print >> outfile, '[<b><a href=".">PEP Index</a></b>]'
      if pep:
!         print >> outfile, '[<b><a href="pep-%04d.txt">PEP Source</a></b>]' \
                % int(pep)
!     print >> outfile, '</td></tr></table>'
!     print >> outfile, '<div class="header">\n<table border="0">'
      for k, v in header:
          if k.lower() in ('author', 'discussions-to'):
***************
*** 206,214 ****
                      mailtos.append(part)
              v = COMMASPACE.join(mailtos)
!         elif k.lower() in ('replaces', 'replaced-by'):
              otherpeps = ''
!             for otherpep in v.split():
                  otherpep = int(otherpep)
!                 otherpeps += '<a href="pep-%04d.html">%i</a> ' % (otherpep, 
                                                                    otherpep)
              v = otherpeps
--- 199,207 ----
                      mailtos.append(part)
              v = COMMASPACE.join(mailtos)
!         elif k.lower() in ('replaces', 'replaced-by', 'requires'):
              otherpeps = ''
!             for otherpep in re.split(',?\s+', v):
                  otherpep = int(otherpep)
!                 otherpeps += '<a href="pep-%04d.html">%i</a> ' % (otherpep,
                                                                    otherpep)
              v = otherpeps
***************
*** 216,234 ****
              url = PEPCVSURL % int(pep)
              date = v or time.strftime('%d-%b-%Y',
!                                       time.localtime(os.stat(infile)[8]))
              v = '<a href="%s">%s</a> ' % (url, cgi.escape(date))
          else:
              v = cgi.escape(v)
!         print >> fo, '  <tr><th>%s:&nbsp;</th><td>%s</td></tr>' \
                % (cgi.escape(k), v)
!     print >> fo, '</table>'
!     print >> fo, '</div>'
!     print >> fo, '<hr />'
!     print >> fo, '<div class="content">'
      need_pre = 1
!     while 1:
!         line = fi.readline()
!         if not line:
!             break
          if line[0] == '\f':
              continue
--- 209,228 ----
              url = PEPCVSURL % int(pep)
              date = v or time.strftime('%d-%b-%Y',
!                                       time.localtime(os.stat(inpath)[8]))
              v = '<a href="%s">%s</a> ' % (url, cgi.escape(date))
+         elif k.lower() in ('content-type',):
+             url = PEPURL % 9
+             pep_type = v or 'text/plain'
+             v = '<a href="%s">%s</a> ' % (url, cgi.escape(pep_type))
          else:
              v = cgi.escape(v)
!         print >> outfile, '  <tr><th>%s:&nbsp;</th><td>%s</td></tr>' \
                % (cgi.escape(k), v)
!     print >> outfile, '</table>'
!     print >> outfile, '</div>'
!     print >> outfile, '<hr />'
!     print >> outfile, '<div class="content">'
      need_pre = 1
!     for line in infile:
          if line[0] == '\f':
              continue
***************
*** 239,244 ****
                  break
              if not need_pre:
!                 print >> fo, '</pre>'
!             print >> fo, '<h3>%s</h3>' % line.strip()
              need_pre = 1
          elif not line.strip() and need_pre:
--- 233,238 ----
                  break
              if not need_pre:
!                 print >> outfile, '</pre>'
!             print >> outfile, '<h3>%s</h3>' % line.strip()
              need_pre = 1
          elif not line.strip() and need_pre:
***************
*** 252,258 ****
                      url = PEPURL % int(parts[1])
                      if need_pre:
!                         print >> fo, '<pre>'
                          need_pre = 0
!                     print >> fo, re.sub(
                          parts[1],
                          '<a href="%s">%s</a>' % (url, parts[1]),
--- 246,252 ----
                      url = PEPURL % int(parts[1])
                      if need_pre:
!                         print >> outfile, '<pre>'
                          need_pre = 0
!                     print >> outfile, re.sub(
                          parts[1],
                          '<a href="%s">%s</a>' % (url, parts[1]),
***************
*** 263,284 ****
                      url = fixemail(parts[-1], pep)
                      if need_pre:
!                         print >> fo, '<pre>'
                          need_pre = 0
!                     print >> fo, re.sub(
                          parts[-1], url, line, 1),
                      continue
!             line = fixpat.sub(lambda x, c=infile: fixanchor(c, x), line)
              if need_pre:
!                 print >> fo, '<pre>'
                  need_pre = 0
!             fo.write(line)
      if not need_pre:
!         print >> fo, '</pre>'
!     print >> fo, '</div>'
!     print >> fo, '</body>'
!     print >> fo, '</html>'
!     fo.close()
!     os.chmod(outfile, 0664)
  
  
  
--- 257,333 ----
                      url = fixemail(parts[-1], pep)
                      if need_pre:
!                         print >> outfile, '<pre>'
                          need_pre = 0
!                     print >> outfile, re.sub(
                          parts[-1], url, line, 1),
                      continue
!             line = fixpat.sub(lambda x, c=inpath: fixanchor(c, x), line)
              if need_pre:
!                 print >> outfile, '<pre>'
                  need_pre = 0
!             outfile.write(line)
      if not need_pre:
!         print >> outfile, '</pre>'
!     print >> outfile, '</div>'
!     print >> outfile, '</body>'
!     print >> outfile, '</html>'
  
+ 
+ docutils_options = None
+ """Option value object used by Docutils.  Can be set by the client application
+ when this module is imported."""
+ 
+ def fix_rst_pep(inpath, input_lines, outfile):
+     from docutils import core, io
+     pub = core.Publisher()
+     pub.set_reader(reader_name='pep', parser_name='restructuredtext',
+                    parser=None)
+     pub.set_writer(writer_name='pep_html')
+     if docutils_options:
+         options = docutils_options
+         pub.options = options
+     else:
+         options = pub.set_options()
+     options._source = inpath
+     options._destination = outfile.name
+     pub.source = io.StringInput(
+         options, source=''.join(input_lines), source_path=inpath)
+     pub.destination = io.FileOutput(
+         options, destination=outfile, destination_path=outfile.name,
+         autoclose=0)
+     pub.publish()
+ 
+ 
+ def get_pep_type(input_lines):
+     """
+     Return the Content-Type of the input.  "text/plain" is the default.
+     Return ``None`` if the input is not a PEP.
+     """
+     pep_type = None
+     for line in input_lines:
+         line = line.rstrip().lower()
+         if not line:
+             # End of the RFC 2822 header (first blank line).
+             break
+         elif line.startswith('content-type: '):
+             pep_type = line.split()[1] or 'text/plain'
+             break
+         elif line.startswith('pep: '):
+             # Default PEP type, used if no explicit content-type specified:
+             pep_type = 'text/plain'
+     return pep_type
+ 
+ 
+ def get_input_lines(inpath):
+     try:
+         infile = open(inpath)
+     except IOError, e:
+         if e.errno <> errno.ENOENT: raise
+         print >> sys.stderr, 'Error: Skipping missing PEP file:', e.filename
+         sys.stderr.flush()
+         return None, None
+     lines = infile.read().splitlines(1) # handles x-platform line endings
+     infile.close()
+     return lines
  
  
***************
*** 290,299 ****
      return "pep-%04d.txt" % num
  
! def make_html(file, verbose=0):
!     newfile = os.path.splitext(file)[0] + ".html"
      if verbose:
!         print file, "->", newfile
!     fixfile(file, newfile)
!     return newfile
  
  def push_pep(htmlfiles, txtfiles, username, verbose):
--- 339,366 ----
      return "pep-%04d.txt" % num
  
! def make_html(inpath, verbose=0):
!     input_lines = get_input_lines(inpath)
!     pep_type = get_pep_type(input_lines)
!     if pep_type is None:
!         print >> sys.stderr, 'Error: Input file %s is not a PEP.' % inpath
!         sys.stdout.flush()
!         return None
!     elif not PEP_TYPE_DISPATCH.has_key(pep_type):
!         print >> sys.stderr, ('Error: Unknown PEP type for input file %s: %s'
!                               % (inpath, pep_type))
!         sys.stdout.flush()
!         return None
!     elif PEP_TYPE_DISPATCH[pep_type] == None:
!         pep_type_error(inpath, pep_type)
!         return None
!     outpath = os.path.splitext(inpath)[0] + ".html"
      if verbose:
!         print inpath, "(%s)" % pep_type, "->", outpath
!         sys.stdout.flush()
!     outfile = open(outpath, "w")
!     PEP_TYPE_DISPATCH[pep_type](inpath, input_lines, outfile)
!     outfile.close()
!     os.chmod(outfile.name, 0664)
!     return outpath
  
  def push_pep(htmlfiles, txtfiles, username, verbose):
***************
*** 317,320 ****
--- 384,423 ----
  
  
+ PEP_TYPE_DISPATCH = {'text/plain': fixfile,
+                      'text/x-rst': fix_rst_pep}
+ PEP_TYPE_MESSAGES = {}
+ 
+ def check_requirements():
+     # Check Python:
+     try:
+         from email.Utils import parseaddr
+     except ImportError:
+         PEP_TYPE_DISPATCH['text/plain'] = None
+         PEP_TYPE_MESSAGES['text/plain'] = (
+             'Python %s or better required for "%%(pep_type)s" PEP '
+             'processing; %s present (%%(inpath)s).'
+             % (REQUIRES['python'], sys.version.split()[0]))
+     # Check Docutils:
+     try:
+         import docutils
+     except ImportError:
+         PEP_TYPE_DISPATCH['text/x-rst'] = None
+         PEP_TYPE_MESSAGES['text/x-rst'] = (
+             'Docutils not present for "%(pep_type)s" PEP file %(inpath)s.  '
+             'See README.txt for installation.')
+     else:
+         if docutils.__version__ < REQUIRES['docutils']:
+             PEP_TYPE_DISPATCH['text/x-rst'] = None
+             PEP_TYPE_MESSAGES['text/x-rst'] = (
+                 'Docutils must be reinstalled for "%%(pep_type)s" PEP '
+                 'processing (%%(inpath)s).  Version %s or better required; '
+                 '%s present.  See README.txt for installation.'
+                 % (REQUIRES['docutils'], docutils.__version__))
+ 
+ def pep_type_error(inpath, pep_type):
+     print >> sys.stderr, 'Error: ' + PEP_TYPE_MESSAGES[pep_type] % locals()
+     sys.stdout.flush()
+ 
+ 
  def browse_file(pep):
      import webbrowser
***************
*** 335,339 ****
  
  
! def main():
      # defaults
      update = 0
--- 438,442 ----
  
  
! def main(argv=None):
      # defaults
      update = 0
***************
*** 342,348 ****
      browse = 0
  
      try:
          opts, args = getopt.getopt(
!             sys.argv[1:], 'bihqu:',
              ['browse', 'install', 'help', 'quiet', 'user='])
      except getopt.error, msg:
--- 445,456 ----
      browse = 0
  
+     check_requirements()
+ 
+     if argv is None:
+         argv = sys.argv[1:]
+ 
      try:
          opts, args = getopt.getopt(
!             argv, 'bihqu:',
              ['browse', 'install', 'help', 'quiet', 'user='])
      except getopt.error, msg:
***************
*** 368,372 ****
              peptxt.append(file)
              newfile = make_html(file, verbose=verbose)
!             html.append(newfile)
              if browse and not update:
                  browse_file(pep)
--- 476,481 ----
              peptxt.append(file)
              newfile = make_html(file, verbose=verbose)
!             if newfile:
!                 html.append(newfile)
              if browse and not update:
                  browse_file(pep)
***************
*** 374,383 ****
          # do them all
          peptxt = []
          files = glob.glob("pep-*.txt")
          files.sort()
          for file in files:
              peptxt.append(file)
!             make_html(file, verbose=verbose)
!         html = ["pep-*.html"]
          if browse and not update:
              browse_file("0")
--- 483,494 ----
          # do them all
          peptxt = []
+         html = []
          files = glob.glob("pep-*.txt")
          files.sort()
          for file in files:
              peptxt.append(file)
!             newfile = make_html(file, verbose=verbose)
!             if newfile:
!                 html.append(newfile)
          if browse and not update:
              browse_file("0")