From e28fb326a30556d76b4878516a1fa3b849ee4cde Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Wed, 2 Mar 2022 01:06:07 +0000 Subject: [PATCH] PRS: Remove text/plain, upload, and browse logic from pep2html.py --- pep2html.py | 452 +--------------------------------------------------- 1 file changed, 7 insertions(+), 445 deletions(-) diff --git a/pep2html.py b/pep2html.py index ba0ec100ba9..9997c79ef08 100755 --- a/pep2html.py +++ b/pep2html.py @@ -5,26 +5,6 @@ Options: --u, --user - python.org username - --b, --browse - After generating the HTML, direct your web browser to view it - (using the Python webbrowser module). If both -i and -b are - given, this will browse the on-line HTML; otherwise it will - browse the local HTML. If no pep arguments are given, this - will browse PEP 0. - --i, --install - After generating the HTML, install it and the plaintext source file - (.txt) on python.org. In that case the user's name is used in the scp - and ssh commands, unless "-u username" is given (in which case, it is - used instead). Without -i, -u is ignored. - --l, --local - Same as -i/--install, except install on the local machine. Use this - when logged in to the python.org machine (dinsdale). - -q, --quiet Turn off verbose messages. @@ -34,22 +14,15 @@ The optional arguments ``peps`` are either pep numbers, .rst or .txt files. """ -from __future__ import print_function, unicode_literals - import sys import os import re import glob import getopt import errno -import random import time from io import open from pathlib import Path -try: - from html import escape -except ImportError: - from cgi import escape from docutils import core, nodes, utils from docutils.readers import standalone @@ -60,41 +33,9 @@ class DataError(Exception): pass -REQUIRES = {'python': '2.6', - 'docutils': '0.2.7'} PROGRAM = sys.argv[0] -RFCURL = 'http://www.faqs.org/rfcs/rfc%d.html' -PEPURL = 'pep-%04d.html' PEPCVSURL = ('https://hg.python.org/peps/file/tip/pep-%04d.txt') -PEPDIRRUL = 'http://www.python.org/peps/' - - -HOST = "dinsdale.python.org" # host for update -HDIR = "/data/ftp.python.org/pub/www.python.org/peps" # target host directory -LOCALVARS = "Local Variables:" - -COMMENT = """""" - -# The generated HTML doesn't validate -- you cannot use
and

inside -#
 tags.  But if I change that, the result doesn't look very nice...
-DTD = ('')
 
-fixpat = re.compile(r"((https?|ftp):[-_a-zA-Z0-9/.+~:?#$=&,]+)|(pep-\d+(.txt|.rst)?)|"
-                    r"(RFC[- ]?(?P\d+))|"
-                    r"(PEP\s+(?P\d+))|"
-                    r".")
-
-EMPTYSTRING = ''
-SPACE = ' '
-COMMASPACE = ', '
-
-
-
 def usage(code, msg=''):
     """Print usage message and exit.  Uses stderr if code != 0."""
     if code == 0:
@@ -106,222 +47,6 @@ def usage(code, msg=''):
         print(msg, file=out)
     sys.exit(code)
 
-
-
-def fixanchor(current, match):
-    text = match.group(0)
-    link = None
-    if (text.startswith('http:') or text.startswith('https:')
-        or text.startswith('ftp:')):
-        # Strip off trailing punctuation.  Pattern taken from faqwiz.
-        ltext = list(text)
-        while ltext:
-            c = ltext.pop()
-            if c not in '''();:,.?'"<>''':
-                ltext.append(c)
-                break
-        link = EMPTYSTRING.join(ltext)
-    elif text.startswith('pep-') and text != current:
-        link = os.path.splitext(text)[0] + ".html"
-    elif text.startswith('PEP'):
-        pepnum = int(match.group('pepnum'))
-        link = PEPURL % pepnum
-    elif text.startswith('RFC'):
-        rfcnum = int(match.group('rfcnum'))
-        link = RFCURL % rfcnum
-    if link:
-        return '%s' % (escape(link), escape(text))
-    return escape(match.group(0)) # really slow, but it works...
-
-
-
-NON_MASKED_EMAILS = [
-    'peps@python.org',
-    'python-list@python.org',
-    'python-dev@python.org',
-    ]
-
-def fixemail(address, pepno):
-    if address.lower() in NON_MASKED_EMAILS:
-        # return hyperlinked version of email address
-        return linkemail(address, pepno)
-    else:
-        # return masked version of email address
-        parts = address.split('@', 1)
-        return '%s at %s' % (parts[0], parts[1])
-
-
-def linkemail(address, pepno):
-    parts = address.split('@', 1)
-    return (''
-            '%s at %s'
-            % (parts[0], parts[1], pepno, parts[0], parts[1]))
-
-
-def fixfile(inpath, input_lines, outfile):
-    try:
-        from email.Utils import parseaddr
-    except ImportError:
-        from email.utils import parseaddr
-    basename = os.path.basename(inpath)
-    infile = iter(input_lines)
-    # convert plaintext pep to minimal XHTML markup
-    print(DTD, file=outfile)
-    print('', file=outfile)
-    print(COMMENT, file=outfile)
-    print('', file=outfile)
-    # head
-    header = []
-    pep = ""
-    title = ""
-    for line in infile:
-        if not line.strip():
-            break
-        if line[0].strip():
-            if ":" not in line:
-                break
-            key, value = line.split(":", 1)
-            value = value.strip()
-            header.append((key, value))
-        else:
-            # continuation line
-            key, value = header[-1]
-            value = value + line
-            header[-1] = key, value
-        if key.lower() == "title":
-            title = value
-        elif key.lower() == "pep":
-            pep = value
-    if pep:
-        title = "PEP " + pep + " -- " + title
-    if title:
-        print('  %s' % escape(title), file=outfile)
-    r = random.choice(list(range(64)))
-    print((
-        '  \n'
-        '\n'
-        '\n'
-        '\n'
-        '\n'
-        '', file=outfile)
-    print('
\n', file=outfile) - for k, v in header: - if k.lower() in ('author', 'pep-delegate', 'bdfl-delegate', 'discussions-to', - 'sponsor'): - mailtos = [] - for part in re.split(r',\s*', v): - if '@' in part: - realname, addr = parseaddr(part) - if k.lower() == 'discussions-to': - m = linkemail(addr, pep) - else: - m = fixemail(addr, pep) - mailtos.append('%s <%s>' % (realname, m)) - elif part.startswith('http:'): - mailtos.append( - '%s' % (part, part)) - else: - mailtos.append(part) - v = COMMASPACE.join(mailtos) - elif k.lower() in ('replaces', 'superseded-by', 'requires'): - otherpeps = '' - for otherpep in re.split(r',?\s+', v): - otherpep = int(otherpep) - otherpeps += '%i ' % (otherpep, - otherpep) - v = otherpeps - elif k.lower() in ('last-modified',): - date = v or time.strftime('%d-%b-%Y', - time.localtime(os.stat(inpath)[8])) - if date.startswith('$' 'Date: ') and date.endswith(' $'): - date = date[6:-2] - if basename == 'pep-0000.txt': - v = date - else: - try: - url = PEPCVSURL % int(pep) - v = '%s ' % (url, escape(date)) - except ValueError as error: - v = date - elif k.lower() in ('content-type',): - url = PEPURL % 9 - pep_type = v or 'text/x-rst' - v = '%s ' % (url, escape(pep_type)) - elif k.lower() == 'version': - if v.startswith('$' 'Revision: ') and v.endswith(' $'): - v = escape(v[11:-2]) - else: - v = escape(v) - print(' ' \ - % (escape(k), v), file=outfile) - print('
%s: %s
', file=outfile) - print('
', file=outfile) - print('
', file=outfile) - print('
', file=outfile) - need_pre = 1 - for line in infile: - if line[0] == '\f': - continue - if line.strip() == LOCALVARS: - break - if line[0].strip(): - if not need_pre: - print('
', file=outfile) - print('

%s

' % line.strip(), file=outfile) - need_pre = 1 - elif not line.strip() and need_pre: - continue - else: - # PEP 0 has some special treatment - if basename == 'pep-0000.txt': - parts = line.split() - if len(parts) > 1 and re.match(r'\s*\d{1,4}', parts[1]): - # This is a PEP summary line, which we need to hyperlink - url = PEPURL % int(parts[1]) - if need_pre: - print('
', file=outfile)
-                        need_pre = 0
-                    print(re.sub(
-                        parts[1],
-                        '%s' % (url, parts[1]),
-                        line, 1), end='', file=outfile)
-                    continue
-                elif parts and '@' in parts[-1]:
-                    # This is a pep email address line, so filter it.
-                    url = fixemail(parts[-1], pep)
-                    if need_pre:
-                        print('
', file=outfile)
-                        need_pre = 0
-                    print(re.sub(
-                        parts[-1], url, line, 1), end='', file=outfile)
-                    continue
-            line = fixpat.sub(lambda x, c=inpath: fixanchor(c, x), line)
-            if need_pre:
-                print('
', file=outfile)
-                need_pre = 0
-            outfile.write(line)
-    if not need_pre:
-        print('
', file=outfile) - print('', file=outfile) - print('', file=outfile) - print('', file=outfile) - - EXPLICIT_TITLE_RE = re.compile(r'^(.+?)\s*(?$', re.DOTALL) def _pep_reference_role(role, rawtext, text, lineno, inliner, @@ -381,10 +106,6 @@ def _rfc_reference_role(role, rawtext, text, lineno, inliner, roles.register_canonical_role("pep-reference", _pep_reference_role) roles.register_canonical_role("rfc-reference", _rfc_reference_role) -docutils_settings = None -"""Runtime settings object used by Docutils. Can be set by the client -application when this module is imported.""" - class PEPHeaders(Transform): """ @@ -561,32 +282,11 @@ def fix_rst_pep(inpath, input_lines, outfile): reader=PEPReader(), parser_name='restructuredtext', writer_name='pep_html', - settings=docutils_settings, + settings=None, # Allow Docutils traceback if there's an exception: settings_overrides={'traceback': 1, 'halt_level': 2}) outfile.write(output.decode('utf-8')) - -def get_pep_type(input_lines): - """ - Return the Content-Type of the input. "text/x-rst" 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/x-rst' - break - elif line.startswith('pep: '): - # Default PEP type, used if no explicit content-type specified: - pep_type = 'text/x-rst' - return pep_type - - def get_input_lines(inpath): try: infile = open(inpath, encoding='utf-8') @@ -599,7 +299,6 @@ def get_input_lines(inpath): infile.close() return lines - def find_pep(pep_str): """Find the .rst or .txt file indicated by a cmd line argument""" if os.path.exists(pep_str): @@ -614,183 +313,46 @@ def make_html(inpath, verbose=0): input_lines = get_input_lines(inpath) if input_lines is None: return None - pep_type = get_pep_type(input_lines) - if pep_type is None: - print('Error: Input file %s is not a PEP.' % inpath, file=sys.stderr) - sys.stdout.flush() - return None - elif pep_type not in PEP_TYPE_DISPATCH: - print(('Error: Unknown PEP type for input file %s: %s' - % (inpath, pep_type)), file=sys.stderr) - sys.stdout.flush() - return None - elif PEP_TYPE_DISPATCH[pep_type] is None: - pep_type_error(inpath, pep_type) - return None outpath = os.path.splitext(inpath)[0] + ".html" if verbose: - print(inpath, "(%s)" % pep_type, "->", outpath) + print(inpath, "(text/x-rst)", "->", outpath) sys.stdout.flush() outfile = open(outpath, "w", encoding='utf-8') - PEP_TYPE_DISPATCH[pep_type](inpath, input_lines, outfile) + fix_rst_pep(inpath, input_lines, outfile) outfile.close() os.chmod(outfile.name, 0o664) return outpath -def push_pep(htmlfiles, txtfiles, username, verbose, local=0): - quiet = "" - if local: - if verbose: - quiet = "-v" - target = HDIR - copy_cmd = "cp" - chmod_cmd = "chmod" - else: - if not verbose: - quiet = "-q" - if username: - username = username + "@" - target = username + HOST + ":" + HDIR - copy_cmd = "scp" - chmod_cmd = "ssh %s%s chmod" % (username, HOST) - files = htmlfiles[:] - files.extend(txtfiles) - files.append("style.css") - files.append("pep.css") - filelist = SPACE.join(files) - rc = os.system("%s %s %s %s" % (copy_cmd, quiet, filelist, target)) - if rc: - sys.exit(rc) -## rc = os.system("%s 664 %s/*" % (chmod_cmd, HDIR)) -## if rc: -## sys.exit(rc) - - -PEP_TYPE_DISPATCH = {'text/plain': fixfile, - 'text/x-rst': fix_rst_pep} -PEP_TYPE_MESSAGES = {} - -def check_requirements(): - # Check Python: - # This is pretty much covered by the __future__ imports... - if sys.version_info < (2, 6, 0): - 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.rst for installation.') - else: - installed = [int(part) for part in docutils.__version__.split('.')] - required = [int(part) for part in REQUIRES['docutils'].split('.')] - if installed < required: - 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.rst for installation.' - % (REQUIRES['docutils'], docutils.__version__)) - -def pep_type_error(inpath, pep_type): - print('Error: ' + PEP_TYPE_MESSAGES[pep_type] % locals(), file=sys.stderr) - sys.stdout.flush() - - -def browse_file(pep): - import webbrowser - file = find_pep(pep) - if file.startswith('pep-') and file.endswith((".txt", '.rst')): - file = file[:-3] + "html" - file = os.path.abspath(file) - url = "file:" + file - webbrowser.open(url) - -def browse_remote(pep): - import webbrowser - file = find_pep(pep) - if file.startswith('pep-') and file.endswith((".txt", '.rst')): - file = file[:-3] + "html" - url = PEPDIRRUL + file - webbrowser.open(url) - - def main(argv=None): # defaults - update = 0 - local = 0 - username = '' verbose = 1 - browse = 0 - - check_requirements() if argv is None: argv = sys.argv[1:] try: opts, args = getopt.getopt( - argv, 'bilhqu:', - ['browse', 'install', 'local', 'help', 'quiet', 'user=']) + argv, 'hq:', + ['help', 'quiet']) except getopt.error as msg: usage(1, msg) for opt, arg in opts: if opt in ('-h', '--help'): usage(0) - elif opt in ('-i', '--install'): - update = 1 - elif opt in ('-l', '--local'): - update = 1 - local = 1 - elif opt in ('-u', '--user'): - username = arg elif opt in ('-q', '--quiet'): verbose = 0 - elif opt in ('-b', '--browse'): - browse = 1 if args: - pep_list = [] - html = [] for pep in args: file = find_pep(pep) - pep_list.append(file) - newfile = make_html(file, verbose=verbose) - if newfile: - html.append(newfile) - if browse and not update: - browse_file(pep) + make_html(file, verbose=verbose) else: # do them all - pep_list = [] - html = [] files = glob.glob("pep-*.txt") + glob.glob("pep-*.rst") files.sort() for file in files: - pep_list.append(file) - newfile = make_html(file, verbose=verbose) - if newfile: - html.append(newfile) - if browse and not update: - browse_file("0") - - if update: - push_pep(html, pep_list, username, verbose, local=local) - if browse: - if args: - for pep in args: - browse_remote(pep) - else: - browse_remote("0") - + make_html(file, verbose=verbose) - if __name__ == "__main__": main()