Commits

Eric Knibbe committed d673df4 Draft

removing fork

  • Participants
  • Parent commits 3df602e

Comments (0)

Files changed (11)

python/restview/MANIFEST.in

-include restview
-include sample.rst
-include test.py
-include src/restview/default.css
-include Makefile

python/restview/Makefile

-PYTHON = python
-
-FILE_WITH_VERSION = src/restview/restviewhttp.py
-FILE_WITH_CHANGELOG = README.txt
-VCS_STATUS = bzr status
-VCS_EXPORT = bzr export
-VCS_TAG = bzr tag
-VCS_COMMIT_AND_PUSH = bzr ci -m "Post-release version bump" && bzr push
-
-
-.PHONY: default
-default: all
-
-
-.PHONY: all
-all:
-	@echo "Nothing to do"
-
-
-.PHONY: check test
-check test:
-	$(PYTHON) test.py
-
-.PHONY: coverage
-coverage:
-	tox -e coverage
-
-.PHONY: dist
-dist:
-	$(PYTHON) setup.py sdist
-
-.PHONY: distcheck
-distcheck:
-	# Bit of a chicken-and-egg here, but if the tree is unclean, make
-	# distcheck will fail.
-ifndef FORCE
-	@test -z "`$(VCS_STATUS) 2>&1`" || { echo; echo "Your working tree is not clean" 1>&2; $(VCS_STATUS); exit 1; }
-endif
-	make dist
-	pkg_and_version=`$(PYTHON) setup.py --name`-`$(PYTHON) setup.py --version` && \
-	rm -rf tmp && \
-	mkdir tmp && \
-	$(VCS_EXPORT) tmp/tree && \
-	cd tmp && \
-	tar xvzf ../dist/$$pkg_and_version.tar.gz && \
-	diff -ur $$pkg_and_version tree -x PKG-INFO -x setup.cfg -x '*.egg-info' && \
-	cd $$pkg_and_version && \
-	make dist check && \
-	cd .. && \
-	mkdir one two && \
-	cd one && \
-	tar xvzf ../../dist/$$pkg_and_version.tar.gz && \
-	cd ../two/ && \
-	tar xvzf ../$$pkg_and_version/dist/$$pkg_and_version.tar.gz && \
-	cd .. && \
-	diff -ur one two -x SOURCES.txt && \
-	cd .. && \
-	rm -rf tmp && \
-	echo "sdist seems to be ok"
-
-.PHONY: releasechecklist
-releasechecklist:
-	@$(PYTHON) setup.py --version | grep -qv dev || { \
-	    echo "Please remove the 'dev' suffix from the version number in $(FILE_WITH_VERSION)"; exit 1; }
-	@$(PYTHON) setup.py --long-description | rst2html --exit-status=2 > /dev/null
-	@ver_and_date="`$(PYTHON) setup.py --version` (`date +%Y-%m-%d`)" && \
-	    grep -q "^$$ver_and_date$$" $(FILE_WITH_CHANGELOG) || { \
-	        echo "$(FILE_WITH_CHANGELOG) has no entry for $$ver_and_date"; exit 1; }
-	make distcheck
-
-.PHONY: release
-release: releasechecklist
-	# I'm chicken so I won't actually do these things yet
-	@echo "Please run"
-	@echo
-	@echo "  $(PYTHON) setup.py sdist register upload && $(VCS_TAG) `$(PYTHON) setup.py --version`"
-	@echo
-	@echo "Please increment the version number in $(FILE_WITH_VERSION)"
-	@echo "and add a new empty entry at the top of the changelog in $(FILE_WITH_CHANGELOG), then"
-	@echo
-	@echo '  $(VCS_COMMIT_AND_PUSH)'
-	@echo
-

python/restview/README.txt

-========
-restview
-========
-
-A viewer for ReStructuredText documents that renders them on the fly.
-
-Pass the name of a ReStructuredText document to restview, and it will
-launch a web server on localhost:random-port and open a web browser.
-Every time you reload the page, restview will reload the document from
-disk and render it.  This is very convenient for previewing a document
-while you're editing it.
-
-You can also pass the name of a directory, and restview will recursively
-look for files that end in .txt or .rst and present you with a list.
-
-Finally, you can make sure your Python package has valid ReStructuredText
-in the long_description field by using ::
-
-  restview -e 'python setup.py --long-description'
-
-This is so useful restview has a shortcut for it ::
-
-  restview --long-description
-
-
-Changelog
-=========
-
-1.3.0 (unreleased)
-------------------
-
-- Automatically reload the web page when the source file changes (LP#965746).
-  Patch by speq (sp@bsdx.org).
-
-- New option: restview --long-description.
-
-- Add Python 3 support (LP#1093098).  Patch by myint (no public email provided).
-
-1.2.2 (2010-09-14)
-------------------
-
-- setup.py no longer requires docutils (LP#637423).
-
-1.2.1 (2010-09-12)
-------------------
-
-- Handle spaces and other special characters in URLs (LP#616335).
-
-- Don't linkify filenames inside external references (LP#634827).
-
-1.2 (2010-08-06)
-----------------
-
-- "SEVERE" docutils errors now display a message and unformatted file in
-  the browser, instead of a traceback on the console.
-- New command-line option, -e COMMAND.
-- Added styles for admonitions; many other important styles are still missing.
-
-1.1.3 (2009-10-25)
-------------------
-
-- Spell 'extras_require' correctly in setup.py (LP#459840).
-- Add a MANIFEST.in for complete source distributions (LP#459845).
-
-1.1.2 (2009-10-14)
-------------------
-
-- Fix for 'localhost' name resolution error on Mac OS X.
-
-1.1.1 (2009-07-13)
-------------------
-
-- Launches the web server in the background.
-
-1.1.0 (2008-08-26)
-------------------
-
-- Accepts any number of files and directories on the command line.
-
-1.0.1 (2008-07-26)
-------------------
-
-- New option: --css.  Accepts a filename or a HTTP/HTTPS URL.
-
-1.0.0 (2008-07-26)
-------------------
-
-- Bumped version number to reflect the stability.
-- Minor CSS tweaks.
-
-0.0.5 (2007-09-29)
-------------------
-
-- Create links to other local files referenced by name.
-- Use pygments (if available) to syntax-highlight doctest blocks.
-- Handle JPEG images.
-
-0.0.4 (2007-09-28)
-------------------
-
-- Remove the unstable Gtk+ version.
-
-0.0.3 (2007-09-28)
-------------------
-
-- Use setuptools for packaging.
-
-0.0.2 (2007-01-21)
-------------------
-
-- Browser-based version.
-- Command line options -l, -b (thanks to Charlie Shepherd).
-- CSS tweaks.
-- Unicode bugfix.
-- Can browse directory trees.
-- Can serve images.
-
-0.0.1 (2005-12-06)
-------------------
-
-- PyGtk+ version with GtkMozEmbed.  Not very stable.
-

python/restview/restview

-#!/usr/bin/env python
-import sys, os
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
-
-from restview.restviewhttp import main
-main()
-

python/restview/sample.rst

-================================
-Sample ReStructuredText document
-================================
-
-This is a sample ReStructuredText document.
-
-Lists
------
-
-Here we have a numbered list
-
-1. Four
-2. Five
-3. Six
-
-and a regular list.
-
-- One
-- Two
-- Three
-

python/restview/setup.py

-#!/usr/bin/env python
-import os
-from setuptools import setup
-
-def test_suite():
-    import doctest
-    return doctest.DocTestSuite('restview.restviewhttp')
-
-def read(filename):
-    return open(os.path.join(os.path.dirname(__file__), filename)).read()
-
-def get_version(filename='src/restview/restviewhttp.py'):
-    for line in read(filename).splitlines():
-        if line.startswith('__version__'):
-            d = {}
-            exec(line, d)
-            return d['__version__']
-    raise AssertionError("couldn't find __version__ in %s" % filename)
-
-version = get_version()
-
-setup(
-    name='restview',
-    version=version,
-    author='Marius Gedminas',
-    author_email='marius@gedmin.as',
-    url='http://mg.pov.lt/restview/',
-    download_url='http://cheeseshop.python.org/pypi/restview',
-    description='ReStructuredText viewer',
-    long_description=read('README.txt'),
-    license='GPL',
-    classifiers=[
-        'Development Status :: 5 - Production/Stable',
-        'Environment :: Web Environment',
-        'Intended Audience :: Developers',
-        'Intended Audience :: End Users/Desktop',
-        'License :: OSI Approved :: GNU General Public License (GPL)',
-        'Programming Language :: Python',
-        'Programming Language :: Python :: 2',
-        'Programming Language :: Python :: 3',
-        'Operating System :: OS Independent',
-        'Topic :: Documentation',
-        'Topic :: Internet :: WWW/HTTP :: HTTP Servers',
-        'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
-        'Topic :: Software Development :: Documentation',
-        'Topic :: Text Processing :: Markup',
-    ],
-
-    packages=['restview'],
-    package_dir={'':'src'},
-    include_package_data=True,
-    install_requires=['docutils'],
-    extras_require={'syntax': ['pygments']},
-    test_suite='__main__.test_suite',
-    zip_safe=False,
-    entry_points="""
-    [console_scripts]
-    restview = restview.restviewhttp:main
-    """,
-)

python/restview/src/restview/__init__.py

Empty file removed.

python/restview/src/restview/default.css

-/*
- * Stylesheet for ReStructuredText by Marius Gedminas.
- * (I didn't like the default one)
- *
- * XXX: I'm doing it incorrectly:
- * http://docutils.sourceforge.net/docs/howto/html-stylesheets.html
- */
-
-body {
-    font-family: Verdana, sans;
-    margin: 3em;
-    max-width: 50em;
-}
-
-p {
-    text-align: justify;
-}
-p.rubric {
-    text-align: center;
-    font-weight: bold;
-}
-
-/* Monospace text */
-
-tt {
-    font-family: Andale Mono, Courier New, monospace;
-    color: #234F32;
-}
-
-/* Definition lists */
-
-dt {
-    font-weight: bold;
-}
-dd {
-    margin-bottom: 1em;
-}
-
-/* Admonitions */
-
-div.admonition p.admonition-title, div.hint p.admonition-title,
-div.important p.admonition-title, div.note p.admonition-title,
-div.tip p.admonition-title {
-    font-weight: bold;
-}
-
-div.attention p.admonition-title, div.caution p.admonition-title,
-div.danger p.admonition-title, div.error p.admonition-title,
-div.warning p.admonition-title {
-    color: red;
-    font-weight: bold;
-}
-
-div.admonition, div.attention, div.caution, div.danger, div.error,
-div.hint, div.important, div.note, div.tip, div.warning {
-    margin: 2em;
-    background: #fff7cc;
-    padding: 1em;
-}
-
-/* Doctest blocks */
-
-pre.doctest-block {
-    color: #008000;
-}
-
-/* Literal blocks */
-
-pre.literal-block {
-    color: #AA4400;
-    margin-left: 40px;
-}
-
-/* Indented quotations */
-
-blockquote > p {
-    color: #000080;
-}
-
-/* Tables */
-
-table {
-    border-top: 2px solid black;
-    border-bottom: 2px solid black;
-    border-left: none;
-    border-right: none;
-    border-collapse: collapse;
-    margin: 0.5em 0;
-}
-tr:first-child > th {
-    border-top: none;
-}
-th {
-    border-top: hidden;
-    border-left: hidden;
-    border-right: hidden;
-    border-bottom: none;
-    text-align: left;
-}
-tr:first-child > td {
-    border-top: 1px solid black;
-}
-table[rules=none] tr:first-child > td {
-    border-top: none;
-}
-td {
-    border-top: hidden;
-    border-left: hidden;
-    border-right: hidden;
-    border-bottom: none;
-    padding: 1px 4px;
-}
-td, th {
-    padding-left: 1em;
-}
-td:first-child,
-th:first-child {
-    padding-left: 4px;
-}
-
-td p:first-child {
-    margin-top: 0;
-}
-th.field-name, th.docinfo-name {
-  white-space: nowrap;
-  padding-left: 0;
-}
-
-/* Table of Contents */
-
-p.topic-title {
-    font-weight: bold;
-    font-size: 120%;
-}
-
-a.toc-backref {
-    color: inherit;
-    text-decoration: none;
-}
-
-/* Footnotes */
-
-a.footnote-reference,
-a.fn-backref {
-    font-size: xx-small;
-    vertical-align: super;
-    line-height: normal;
-    text-decoration: none;
-}
-a.footnote-reference:hover,
-a.fn-backref:hover {
-    text-decoration: underline;
-}
-
-table.footnote {
-    border: none;
-    margin-top: 0.5em;
-    margin-bottom: 0.5em;
-    margin-left: 20px;
-    margin-right: 0.5em;
-    font-size: small;
-}
-table.footnote td {
-    border: none;
-    padding-top: 1em;
-    padding-left: 0px;
-}
-table.footnote tr:first-child > td.label {
-    border-top: 1px solid #eee;
-    padding-left: 20px;
-    padding-right: 20px;
-}
-
-table.footnote + table.footnote {
-    margin-top: 0;
-}
-table.footnote + table.footnote td {
-    border: none;
-    padding-top: 0;
-}
-
-/* System messages (aka errors) */
-
-div.system-messages h1 {
-    color: red;
-}
-div.system-message {
-    border-left: 3px double red;
-    margin-left: 19px;
-    padding-left: 19px;
-    padding-top: 10px;
-    padding-bottom: 10px;
-    color: red;
-}
-div.system-message p.system-message-title {
-    margin-top: 0;
-    font-weight: bold;
-}
-
-/* Sidebars */
-
-div.sidebar {
-    margin: 2em;
-    background: #fff7cc;
-    padding: 1em;
-    width: 40%;
-    float: right;
-    clear: right;
-}
-p.sidebar-title {
-    font-weight: bold;
-    font-size: larger;
-}
-p.sidebar-subtitle {
-    font-weight: bold;
-}
-
-/* Rules taken from the original */
-
-/* used to remove borders from tables and images */
-.borderless, table.borderless td, table.borderless th {
-  border: 0 }
-
-table.borderless td, table.borderless th {
-  /* Override padding for "table.docutils td" with "! important".
-     The right padding separates the table cells. */
-  padding: 0 0.5em 0 0 ! important }
-
-.first {
-  /* Override more specific margin styles with "! important". */
-  margin-top: 0 ! important }
-
-.last, .with-subtitle {
-  margin-bottom: 0 ! important }
-
-.hidden {
-  display: none }
-
-blockquote.epigraph {
-  margin: 2em 5em ; }
-
-div.topic {
-  margin: 2em }
-
-div.abstract {
-  margin: 2em 5em }
-
-div.abstract p.topic-title {
-  font-weight: bold ;
-  text-align: center }
-
-div.dedication {
-  margin: 2em 5em ;
-  text-align: center ;
-  font-style: italic }
-
-div.dedication p.topic-title {
-  font-weight: bold ;
-  font-style: normal }
-
-div.figure {
-  margin-left: 2em ;
-  margin-right: 2em }
-
-div.line-block {
-  display: block ;
-  margin-top: 1em ;
-  margin-bottom: 1em }
-
-div.line-block div.line-block {
-  margin-top: 0 ;
-  margin-bottom: 0 ;
-  margin-left: 1.5em }
-
-ol.simple, ul.simple {
-  margin-bottom: 1em }
-
-span.option {
-  white-space: nowrap }
-
-span.problematic {
-  color: red }
-
-ul.auto-toc {
-  list-style-type: none }
-
-/* ... many more are missing ... */

python/restview/src/restview/restviewhttp.py

-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-"""
-HTTP-based ReStructuredText viewer.
-
-Usage:
-    restviewhttp [options] filename.rst
-or
-    restviewhttp [options] directory
-or
-    restviewhttp [options] -e "command"
-or
-    restviewhttp [options] --long-description
-or
-    restviewhttp --help
-
-Needs docutils and a web browser. Will syntax-highlight code or doctest blocks
-if you have pygments installed.
-"""
-from __future__ import print_function
-
-import os
-import re
-import sys
-import time
-import socket
-import optparse
-import threading
-import webbrowser
-
-try:
-    import BaseHTTPServer
-except ImportError:
-    import http.server as BaseHTTPServer
-
-try:
-    import SocketServer
-except ImportError:
-    import socketserver as SocketServer
-
-try:
-    from html import escape
-except ImportError:
-    from cgi import escape
-
-try:
-    from urllib import unquote
-except ImportError:
-    from urllib.parse import unquote
-
-try:
-    from urlparse import parse_qs
-except ImportError:
-    from urllib.parse import parse_qs
-
-from docutils import core
-from docutils.writers import html4css1
-
-try:
-    import pygments
-    from pygments import lexers, formatters
-except ImportError:
-    pygments = None
-
-
-try:
-    unicode
-except NameError:
-    unicode = str
-
-
-__version__ = "1.3.0dev"
-last_atime = 0
-
-
-class MyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
-    """HTTP request handler that renders ReStructuredText on the fly."""
-
-    server_version = "restviewhttp/" + __version__
-
-    def do_GET(self):
-        content = self.do_GET_or_HEAD()
-        if content:
-            self.wfile.write(content)
-
-    def do_HEAD(self):
-        self.do_GET_or_HEAD()
-
-    def do_GET_or_HEAD(self):
-        self.path = unquote(self.path)
-        root = self.server.renderer.root
-        command = self.server.renderer.command
-        if self.path == '/':
-            if command:
-                return self.handle_command(command)
-            elif isinstance(root, str):
-                if os.path.isdir(root):
-                    return self.handle_dir(root)
-                else:
-                    return self.handle_rest_file(root)
-            else:
-                return self.handle_list(root)
-        elif self.path.startswith('/polling?'):
-            saved_atime = last_atime
-            self.path = parse_qs(self.path.split('?', 1)[-1])['pathname'][0]
-            if self.path == '/':
-                self.path = os.path.basename(root)
-            self.server.renderer.root_mtime = os.stat(self.translate_path()).st_mtime
-            while last_atime == saved_atime:
-                if os.stat(self.translate_path()).st_mtime != self.server.renderer.root_mtime:
-                    try:
-                        self.send_response(200)
-                        self.send_header("Cache-Control", "no-cache, no-store, max-age=0")
-                        self.end_headers()
-                        self.server.renderer.root_mtime = os.stat(self.translate_path()).st_mtime
-                    except Exception as e:
-                        self.log_error('%s (client closed "%s" before acknowledgement)', e, self.path)
-                    finally:
-                        return
-                time.sleep(0.2)
-            try:
-                self.send_response(204)
-                self.end_headers()
-            except Exception as e:
-                self.log_error('%s (client closed "%s" before cancellation)', e, self.path)
-            finally:
-                return
-        elif '/..' in self.path:
-            self.send_error(400, "Bad request") # no hacking!
-        elif self.path.endswith('.gif'):
-            return self.handle_image(self.translate_path(), 'image/gif')
-        elif self.path.endswith('.png'):
-            return self.handle_image(self.translate_path(), 'image/png')
-        elif self.path.endswith('.jpg') or self.path.endswith('.jpeg'):
-            return self.handle_image(self.translate_path(), 'image/jpeg')
-        elif self.path.endswith('.txt') or self.path.endswith('.rst'):
-            return self.handle_rest_file(self.translate_path())
-        else:
-            self.send_error(501, "File type not supported: %s" % self.path)
-
-    def translate_path(self):
-        root = self.server.renderer.root
-        path = self.path.lstrip('/')
-        if not isinstance(root, str):
-            idx, path = path.split('/', 1)
-            root = root[int(idx)]
-        if not os.path.isdir(root):
-            root = os.path.dirname(root)
-        return os.path.join(root, path)
-
-    def handle_image(self, filename, ctype):
-        try:
-            data = file(filename, 'rb').read()
-        except IOError:
-            self.send_error(404, "File not found: %s" % self.path)
-        else:
-            self.send_response(200)
-            self.send_header("Content-Type", ctype)
-            self.send_header("Content-Length", str(len(data)))
-            self.end_headers()
-            return data
-
-    def handle_rest_file(self, filename):
-        try:
-            f = open(filename)
-            global last_atime
-            last_atime = time.time()
-            try:
-                return self.handle_rest_data(f.read())
-            finally:
-                f.close()
-        except IOError as e:
-            self.log_error("%s", e)
-            self.send_error(404, "File not found: %s" % self.path)
-
-    def handle_command(self, command):
-        try:
-            f = os.popen(command)
-            try:
-                return self.handle_rest_data(f.read())
-            finally:
-                f.close()
-        except OSError as e:
-            self.log_error("%s" % e)
-            self.send_error(500, "Command execution failed")
-
-    def handle_rest_data(self, data):
-        html = self.server.renderer.rest_to_html(data)
-        if isinstance(html, unicode):
-            html = html.encode('UTF-8')
-        self.send_response(200)
-        self.send_header("Content-Type", "text/html; charset=UTF-8")
-        self.send_header("Content-Length", str(len(html)))
-        self.send_header("Cache-Control", "no-cache, no-store, max-age=0")
-        self.end_headers()
-        return html
-
-    def collect_files(self, dirname):
-        if not dirname.endswith('/'):
-            dirname += '/'
-        files = []
-        for dirpath, dirnames, filenames in os.walk(dirname):
-            dirnames[:] = [dn for dn in dirnames
-                           if not dn.startswith('.')
-                           and not dn.endswith('.egg-info')]
-            for fn in filenames:
-                if fn.endswith('.txt') or fn.endswith('.rst'):
-                    prefix = dirpath[len(dirname):]
-                    files.append(os.path.join(prefix, fn))
-        files.sort(key=str.lower)
-        return files
-
-    def handle_dir(self, dirname):
-        files = [(fn, fn) for fn in self.collect_files(dirname)]
-        html = self.render_dir_listing("RST files in %s" % os.path.abspath(dirname), files)
-        if isinstance(html, unicode):
-            html = html.encode('UTF-8')
-        self.send_response(200)
-        self.send_header("Content-Type", "text/html; charset=UTF-8")
-        self.send_header("Content-Length", str(len(html)))
-        self.end_headers()
-        return html
-
-    def handle_list(self, list_of_files_or_dirs):
-        files = []
-        for idx, fn in enumerate(list_of_files_or_dirs):
-            if os.path.isdir(fn):
-                files.extend([(os.path.join(str(idx), f),
-                               os.path.join(fn, f))
-                              for f in self.collect_files(fn)])
-            else:
-                files.append((os.path.join(str(idx), os.path.basename(fn)),
-                              fn))
-        html = self.render_dir_listing("RST files", files)
-        if isinstance(html, unicode):
-            html = html.encode('UTF-8')
-        self.send_response(200)
-        self.send_header("Content-Type", "text/html; charset=UTF-8")
-        self.send_header("Content-Length", str(len(html)))
-        self.end_headers()
-        return html
-
-    def render_dir_listing(self, title, files):
-        files = ''.join([FILE_TEMPLATE.replace('$href', escape(href))
-                                      .replace('$file', escape(fn))
-                         for href, fn in files])
-        return (DIR_TEMPLATE.replace('$title', escape(title))
-                            .replace('$files', files))
-
-
-DIR_TEMPLATE = """\
-<!DOCTYPE html>
-<html>
-<head>
-<title>$title</title>
-</head>
-<body>
-<h1>$title</h1>
-<ul>
-$files</ul>
-</body>
-</html>
-"""
-
-FILE_TEMPLATE = """\
-  <li><a href="$href">$file</a></li>
-"""
-
-AJAX_STR = """
-<script type="text/javascript">
-var xmlHttp = null;
-window.onload = function () {
-    setTimeout(function () {
-        if (window.XMLHttpRequest) {
-            xmlHttp = new XMLHttpRequest();
-        } else if (window.ActiveXObject) {
-            xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
-        }
-        xmlHttp.onreadystatechange = function () {
-            if (xmlHttp.readyState == 4 && xmlHttp.status == '200') {
-                window.location.reload(true);
-            }
-        }
-        xmlHttp.open('HEAD', '/polling?pathname=' + location.pathname, true);
-        xmlHttp.send(null);
-    }, 0);
-}
-window.onbeforeunload = function () {
-    xmlHttp.abort();
-}
-</script>
-"""
-
-ERROR_TEMPLATE = """\
-<!DOCTYPE html>
-<html>
-<head>
-<title>$title</title>
-<style type="text/css">
-pre.error {
-    border-left: 3px double red;
-    margin-left: 19px;
-    padding-left: 19px;
-    padding-top: 10px;
-    padding-bottom: 10px;
-    color: red;
-}
-</style>
-</head>
-<body>
-<h1>$title</h1>
-<pre class="error">
-$error
-</pre>
-<pre>
-$source
-</pre>
-</body>
-</html>
-"""
-
-
-class ThreadingHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
-    daemon_threads = True
-
-    # tone down exception messages in the console
-    def handle_error(self, request, client_address):
-        print "Exception detected during processing of request from",
-        print client_address
-
-
-class RestViewer(object):
-    """Web server that renders ReStructuredText on the fly."""
-
-    server_class = ThreadingHTTPServer
-    handler_class = MyRequestHandler
-
-    local_address = ('localhost', 0)
-
-    # only set one of those
-    css_url = None
-    css_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
-                            'default.css')
-
-    strict = None
-
-    def __init__(self, root, command=None):
-        self.root = root
-        self.command = command
-
-    def listen(self):
-        """Start listening on a TCP port.
-
-        Returns the port number.
-        """
-        self.server = self.server_class(self.local_address, self.handler_class)
-        self.server.renderer = self
-        return self.server.socket.getsockname()[1]
-
-    def serve(self):
-        """Wait for HTTP requests and serve them.
-
-        This function does not return.
-        """
-        self.server.serve_forever()
-
-    def rest_to_html(self, rest_input, settings=None):
-        """Render ReStructuredText."""
-        writer = html4css1.Writer()
-        if pygments is not None:
-            writer.translator_class = SyntaxHighlightingHTMLTranslator
-        if self.css_url:
-            settings_overrides = {'stylesheet': self.css_url,
-                                  'stylesheet_path': None,
-                                  'embed_stylesheet': False}
-        elif self.css_path:
-            settings_overrides = {'stylesheet': self.css_path,
-                                  'stylesheet_path': None,
-                                  'embed_stylesheet': True}
-        else:
-            settings_overrides = {}
-        settings_overrides['syntax_highlight'] = 'short'
-        if self.strict:
-            settings_overrides['halt_level'] = 1
-
-        if settings:
-            settings_overrides.update(settings)
-
-        try:
-            core.publish_string(rest_input, writer=writer,
-                                settings_overrides=settings_overrides)
-        except Exception as e:
-            return self.render_exception(e.__class__.__name__, str(e),
-                                         rest_input)
-        return self.get_markup(writer.output)
-
-    def render_exception(self, title, error, source):
-        html = (ERROR_TEMPLATE.replace('$title', escape(title))
-                              .replace('$error', escape(error))
-                              .replace('$source', escape(source)))
-        return self.get_markup(html)
-
-    def get_markup(self, markup):
-        if self.command is None:
-            return markup.replace('</body>', AJAX_STR + '</body>')
-        else:
-            return markup.replace('</title>',
-                                  ' -e "' + escape(self.command) + '"</title>')
-
-
-class SyntaxHighlightingHTMLTranslator(html4css1.HTMLTranslator):
-
-    in_doctest = False
-    in_text = False
-    in_reference = False
-    formatter_styles = formatters.HtmlFormatter(style='trac').get_style_defs('pre')
-
-    def __init__(self, document):
-        html4css1.HTMLTranslator.__init__(self, document)
-        self.body_prefix[:0] = ['<style type="text/css">\n', self.formatter_styles, '\n</style>\n']
-
-    def visit_doctest_block(self, node):
-        html4css1.HTMLTranslator.visit_doctest_block(self, node)
-        self.in_doctest = True
-
-    def depart_doctest_block(self, node):
-        html4css1.HTMLTranslator.depart_doctest_block(self, node)
-        self.in_doctest = False
-
-    def visit_Text(self, node):
-        if self.in_doctest:
-            text = node.astext()
-            lexer = lexers.PythonConsoleLexer()
-            formatter = formatters.HtmlFormatter(nowrap=True)
-            self.body.append(pygments.highlight(text, lexer, formatter))
-        else:
-            text = node.astext()
-            self.in_text = True
-            encoded = self.encode(text)
-            self.in_text = False
-            if self.in_mailto and self.settings.cloak_email_addresses:
-                encoded = self.cloak_email(encoded)
-            self.body.append(encoded)
-
-    def visit_literal(self, node):
-        self.in_text = True
-        try:
-            html4css1.HTMLTranslator.visit_literal(self, node)
-        finally:
-            self.in_text = False
-
-    def visit_reference(self, node):
-        self.in_reference = True
-        html4css1.HTMLTranslator.visit_reference(self, node)
-
-    def depart_reference(self, node):
-        html4css1.HTMLTranslator.depart_reference(self, node)
-        self.in_reference = False
-
-    def encode(self, text):
-        encoded = html4css1.HTMLTranslator.encode(self, text)
-        if self.in_text and not self.in_reference:
-            encoded = self.link_local_files(encoded)
-        return encoded
-
-    @staticmethod
-    def link_local_files(text):
-        """Replace filenames with hyperlinks.
-
-            >>> link_local_files = SyntaxHighlightingHTMLTranslator.link_local_files
-            >>> link_local_files('e.g. see README.txt for more info')
-            'e.g. see <a href="README.txt">README.txt</a> for more info'
-            >>> link_local_files('e.g. see docs/HACKING.rst for more info')
-            'e.g. see <a href="docs/HACKING.rst">docs/HACKING.rst</a> for more info'
-            >>> link_local_files('what about http://example.com/README.txt ?')
-            'what about http://example.com/README.txt ?'
-
-        """
-        # jwz was right...
-        return re.sub(r"(^|\s)([-_a-zA-Z0-9/]+[.](txt|rst))",
-                      r'\1<a href="\2">\2</a>', text)
-
-
-def parse_address(addr):
-    """Parse a socket address.
-
-        >>> parse_address('1234')
-        ('localhost', 1234)
-
-        >>> parse_address('example.com:1234')
-        ('example.com', 1234)
-
-        >>> parse_address('*:1234')
-        ('', 1234)
-
-        >>> try: parse_address('notanumber')
-        ... except ValueError as e: print(e)
-        Invalid address: notanumber
-
-        >>> try: parse_address('la:la:la')
-        ... except ValueError as e: print(e)
-        Invalid address: la:la:la
-
-    """
-    if ':' in addr:
-        try:
-            host, port = addr.split(':')
-        except ValueError:
-            raise ValueError('Invalid address: %s' % addr)
-    else:
-        host, port = 'localhost', addr
-    if host == '*':
-        host = '' # any
-    try:
-        return (host, int(port))
-    except ValueError:
-        raise ValueError('Invalid address: %s' % addr)
-
-
-def get_host_name(listen_on):
-    """Convert a listening interface name to a host name.
-
-    The important part is to convert 0.0.0.0 to the system hostname, everything
-    else can be left as is.
-    """
-    try:
-        ip_addr = socket.inet_aton(listen_on)
-    except socket.error: # probably a hostname or ''
-        ip_addr = None
-    if listen_on == '' or ip_addr == b'\0\0\0\0':
-        return socket.gethostname()
-    else:
-        return listen_on
-
-
-def launch_browser(url):
-    """Launch the web browser for a given URL.
-
-    Does not block.
-    """
-    # Do it in the background as it may block
-    t = threading.Thread(target=webbrowser.open, args=(url,))
-    t.setDaemon(True)
-    t.start()
-
-
-def main():
-    progname = os.path.basename(sys.argv[0])
-    parser = optparse.OptionParser("%prog [options] filename-or-directory [...]",
-                    description="Serve ReStructuredText files over HTTP.",
-                    prog=progname)
-    parser.add_option('-l', '--listen',
-                      help='listen on a given port (or interface:port,'
-                           ' e.g. *:8080) [default: random port on localhost]',
-                      default=None)
-    parser.add_option('-b', '--browser',
-                      help='open a web browser [default: only if -l'
-                           ' was not specified]',
-                      action='store_true', default=None)
-    parser.add_option('-e', '--execute',
-                      help='run a command to produce ReStructuredText',
-                      default=None)
-    parser.add_option('--long-description',
-                      help='run "python setup.py --long-description" to produce ReStructuredText',
-                      action='store_const', dest='execute',
-                      const='python setup.py --long-description')
-    parser.add_option('--css',
-                      help='use the specified stylesheet',
-                      action='store', dest='css_path', default=None)
-    parser.add_option('--strict',
-                      help='halt at the slightest problem',
-                      action='store_true', default=False)
-    opts, args = parser.parse_args(sys.argv[1:])
-    if not args and not opts.execute:
-        parser.error("at least one argument expected")
-    if args and opts.execute:
-        parser.error("specify a command (-e) or a file/directory, but not both")
-    if opts.browser is None:
-        opts.browser = opts.listen is None
-    if opts.execute:
-        server = RestViewer('.', command=opts.execute)
-    elif len(args) == 1:
-        server = RestViewer(args[0])
-    else:
-        server = RestViewer(args)
-    if opts.css_path:
-        if (opts.css_path.startswith('http://') or
-            opts.css_path.startswith('https://')):
-            server.css_url = opts.css_path
-            server.css_path = None
-        else:
-            server.css_path = opts.css_path
-            server.css_url = None
-
-    server.strict = opts.strict
-
-    if opts.listen:
-        try:
-            server.local_address = parse_address(opts.listen)
-        except ValueError as e:
-            parser.error(str(e))
-    host = get_host_name(server.local_address[0])
-    port = server.listen()
-    url = 'http://%s:%d/' % (host, port)
-    print("Listening on %s" % url)
-    if opts.browser:
-        launch_browser(url)
-    try:
-        server.serve()
-    except KeyboardInterrupt:
-        pass
-
-
-if __name__ == '__main__':
-    main()
-

python/restview/test.py

-#!/usr/bin/env python
-import unittest
-import doctest
-
-def test_suite():
-    return doctest.DocTestSuite('restview.restviewhttp')
-
-if __name__ == '__main__':
-    import sys, os
-    sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
-    unittest.main(defaultTest='test_suite')

python/restview/tox.ini

-[tox]
-envlist =
-    py26,py27,py32,py33,pypy
-
-[testenv]
-deps =
-    docutils
-    pygments
-commands =
-    python setup.py test -q
-
-[testenv:coverage]
-basepython = python2.7
-deps =
-    {[testenv]deps}
-    coverage
-commands =
-    coverage run setup.py test -q
-    coverage report --include='src/restview/*'