diff --git a/TODO b/TODO index daaf7d3c0..b90190864 100644 --- a/TODO +++ b/TODO @@ -4,18 +4,18 @@ Global TODO Sphinx ****** -- section numbers -- split the general index +- HTML section numbers? +- split the general index? - add OpenSearch - "seealso" links to external examples, see http://svn.python.org/projects/sandbox/trunk/seealso/ and http://effbot.org/zone/idea-seealso.htm -- write a "printable" builder (export to latex, most probably) - "often used" combo box in sidebar -- link to keywords - source file cross-references? Web App ******* +- fix /download + - discuss and debug comments system - prepare for databases other than sqlite for comments - add search via Xapian or Nucular (Python indexer - nucular.sf.net) diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 02fc66cdb..ddca826a5 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -35,6 +35,7 @@ options: -b -- builder to use (one of %s) -D -- override a setting in sourcedir/conf.py -N -- do not do colored output -q -- no output on stdout, just warnings on stderr + -P -- run Pdb on exception modi: * without -a and without filenames, write new and changed files. * with -a, write all files. @@ -43,7 +44,7 @@ modi: def main(argv): try: - opts, args = getopt.getopt(argv[1:], 'ab:d:O:D:NEq') + opts, args = getopt.getopt(argv[1:], 'ab:d:O:D:NEqP') srcdirname = path.abspath(args[0]) if not path.isdir(srcdirname): print >>sys.stderr, 'Error: Cannot find source directory.' @@ -69,7 +70,7 @@ def main(argv): return 1 builder = all_files = None - opt_help = freshenv = False + opt_help = freshenv = use_pdb = False status = sys.stdout options = {} confoverrides = {} @@ -111,6 +112,8 @@ def main(argv): freshenv = True elif opt == '-q': status = StringIO() + elif opt == '-P': + use_pdb = True if not sys.stdout.isatty() or sys.platform == 'win32': # Windows' cmd box doesn't understand ANSI sequences @@ -128,17 +131,23 @@ def main(argv): print ' * %s: %s' % (optname, description) return 0 - builderobj = builderobj(srcdirname, outdirname, doctreedir, options, - status_stream=status, - warning_stream=sys.stderr, - confoverrides=confoverrides, - freshenv=freshenv) - if all_files: - builderobj.build_all() - elif filenames: - builderobj.build_specific(filenames) - else: - builderobj.build_update() + try: + builderobj = builderobj(srcdirname, outdirname, doctreedir, options, + status_stream=status, + warning_stream=sys.stderr, + confoverrides=confoverrides, + freshenv=freshenv) + if all_files: + builderobj.build_all() + elif filenames: + builderobj.build_specific(filenames) + else: + builderobj.build_update() + except: + if not use_pdb: + raise + import pdb + pdb.post_mortem(sys.exc_info()[2]) if __name__ == '__main__': diff --git a/sphinx/builder.py b/sphinx/builder.py index 0ecbe2583..468f7ab9d 100644 --- a/sphinx/builder.py +++ b/sphinx/builder.py @@ -19,6 +19,7 @@ import shutil import cPickle as pickle import cStringIO as StringIO from os import path +from cgi import escape from docutils.io import StringOutput, FileOutput, DocTreeInput from docutils.core import publish_parts @@ -33,7 +34,7 @@ from .patchlevel import get_version_info, get_sys_version_info from .htmlwriter import HTMLWriter from .latexwriter import LaTeXWriter from .environment import BuildEnvironment, NoUri -from .highlighting import pygments, get_stylesheet +from .highlighting import pygments, highlight_block, get_stylesheet from .util.console import bold, purple, green from . import addnodes @@ -194,66 +195,74 @@ class Builder(object): def build_update(self): """Only rebuild files changed or added since last build.""" self.load_env() - to_build = list(self.get_outdated_files()) + to_build = self.get_outdated_files() if not to_build: self.msg('no target files are out of date, exiting.') return - self.build(to_build, - summary='targets for %d source files that are ' - 'out of date' % len(to_build)) + if isinstance(to_build, str): + self.build([], to_build) + else: + to_build = list(to_build) + self.build(to_build, + summary='targets for %d source files that are ' + 'out of date' % len(to_build)) def build(self, filenames, summary=None): if summary: self.msg('building [%s]:' % self.name, nonl=1) self.msg(summary, nobold=1) + updated_filenames = [] # while reading, collect all warnings from docutils with collect_env_warnings(self): self.msg('reading, updating environment:', nonl=1) iterator = self.env.update(self.config) - self.msg(iterator.next(), nobold=1) + self.msg(iterator.next(), nonl=1, nobold=1) for filename in iterator: + if not updated_filenames: + self.msg('') + updated_filenames.append(filename) self.msg(purple(filename), nonl=1, nobold=1) self.msg() - # save the environment - self.msg('pickling the env...', nonl=True) - self.env.topickle(path.join(self.doctreedir, ENV_PICKLE_FILENAME)) - self.msg('done', nobold=True) + if updated_filenames: + # save the environment + self.msg('pickling the env...', nonl=True) + self.env.topickle(path.join(self.doctreedir, ENV_PICKLE_FILENAME)) + self.msg('done', nobold=True) - # global actions - self.msg('checking consistency...') - self.env.check_consistency() + # global actions + self.msg('checking consistency...') + self.env.check_consistency() # another indirection to support methods which don't build files # individually - self.write(filenames) + self.write(filenames, updated_filenames) # finish (write style files etc.) self.msg('finishing...') self.finish() self.msg('done!') - def write(self, filenames): + def write(self, build_filenames, updated_filenames): + if build_filenames is None: # build_all + build_filenames = self.env.all_files + filenames = set(build_filenames) | set(updated_filenames) + + # add all toctree-containing files that may have changed + for filename in list(filenames): + for tocfilename in self.env.files_to_rebuild.get(filename, []): + filenames.add(tocfilename) + filenames.add('contents.rst') + self.msg('creating index...') self.env.create_index(self) - if filenames: - # add all TOC files that may have changed - filenames_set = set(filenames) - for filename in filenames: - for tocfilename in self.env.files_to_rebuild.get(filename, []): - filenames_set.add(tocfilename) - filenames_set.add('contents.rst') - else: - # build all - filenames_set = set(self.env.all_files) - - self.prepare_writing(filenames_set) + self.prepare_writing(filenames) # write target files with collect_env_warnings(self): self.msg('writing output...') - for filename in status_iterator(sorted(filenames_set), green, + for filename in status_iterator(sorted(filenames), green, stream=self.status_stream): doctree = self.env.get_and_resolve_doctree(filename, self) self.write_file(filename, doctree) @@ -595,7 +604,8 @@ class WebHTMLBuilder(StandaloneHTMLBuilder): # if there is a source file, copy the source file for the "show source" link if context.get('sourcename'): - source_name = path.join(self.outdir, 'sources', os_path(context['sourcename'])) + source_name = path.join(self.outdir, 'sources', + os_path(context['sourcename'])) ensuredir(path.dirname(source_name)) shutil.copyfile(path.join(self.srcdir, os_path(filename)), source_name) @@ -652,8 +662,7 @@ class LaTeXBuilder(Builder): self.filenames = [] def get_outdated_files(self): - # XXX always rebuild everything for now - return ['dummy'] + return 'all documents' # for now def get_target_uri(self, source_filename, typ=None): if typ == 'token': @@ -677,9 +686,7 @@ class LaTeXBuilder(Builder): and not fn.endswith('index.rst')]: yield (howto, 'howto-'+howto[6:-4]+'.tex', 'howto') - def write(self, filenames): - # "filenames" is ignored here... - + def write(self, *ignored): # first, assemble the "special" docs that are in every PDF specials = [] for fname in ["glossary", "about", "license", "copyright"]: @@ -695,8 +702,8 @@ class LaTeXBuilder(Builder): destination_path=path.join(self.outdir, targetname), encoding='utf-8') print "processing", targetname + "...", - doctree = self.assemble_doctree(sourcename, - specials=(docclass == 'manual') and specials or []) + doctree = self.assemble_doctree( + sourcename, specials=(docclass == 'manual') and specials or []) print "writing...", doctree.settings = docsettings doctree.settings.filename = sourcename @@ -743,9 +750,119 @@ class LaTeXBuilder(Builder): path.join(self.outdir, filename)) +class ChangesBuilder(Builder): + """ + Write a summary with all versionadded/changed directives. + """ + name = 'changes' + + def init(self): + from ._jinja import Environment, FileSystemLoader + templates_path = path.join(path.dirname(__file__), 'templates') + jinja_env = Environment(loader=FileSystemLoader(templates_path), + # disable traceback, more likely that something in the + # application is broken than in the templates + friendly_traceback=False) + self.ftemplate = jinja_env.get_template('versionchanges_frameset.html') + self.vtemplate = jinja_env.get_template('versionchanges.html') + self.stemplate = jinja_env.get_template('rstsource.html') + + def get_outdated_files(self): + return self.outdir + + typemap = { + 'versionadded': 'added', + 'versionchanged': 'changed', + 'deprecated': 'deprecated', + } + + def write(self, *ignored): + ver = self.config['version'] + libchanges = {} + apichanges = [] + otherchanges = {} + self.msg('writing summary file...') + for type, filename, lineno, module, descname, content in \ + self.env.versionchanges[ver]: + ttext = self.typemap[type] + context = content.replace('\n', ' ') + if descname and filename.startswith('c-api'): + if not descname: + continue + if context: + entry = '%s: %s: %s' % (descname, ttext, context) + else: + entry = '%s: %s.' % (descname, ttext) + apichanges.append((entry, filename, lineno)) + elif descname or module: + if not module: + module = 'Builtins' + if not descname: + descname = 'Module level' + if context: + entry = '%s: %s: %s' % (descname, ttext, context) + else: + entry = '%s: %s.' % (descname, ttext) + libchanges.setdefault(module, []).append((entry, filename, lineno)) + else: + if not context: + continue + entry = '%s: %s' % (ttext.capitalize(), context) + title = self.env.titles[filename].astext() + otherchanges.setdefault((filename, title), []).append( + (entry, filename, lineno)) + + ctx = { + 'version': ver, + 'libchanges': sorted(libchanges.iteritems()), + 'apichanges': sorted(apichanges), + 'otherchanges': sorted(otherchanges.iteritems()), + } + with open(path.join(self.outdir, 'index.html'), 'w') as f: + f.write(self.ftemplate.render(ctx)) + with open(path.join(self.outdir, 'changes.html'), 'w') as f: + f.write(self.vtemplate.render(ctx)) + + hltext = ['.. versionadded:: %s' % ver, + '.. versionchanged:: %s' % ver, + '.. deprecated:: %s' % ver] + + def hl(no, line): + line = ' ' % no + escape(line) + for x in hltext: + if x in line: + line = '%s' % line + break + return line + + self.msg('copying source files...') + for filename in self.env.all_files: + with open(path.join(self.srcdir, os_path(filename))) as f: + lines = f.readlines() + targetfn = path.join(self.outdir, 'rst', os_path(filename)) + '.html' + ensuredir(path.dirname(targetfn)) + with codecs.open(targetfn, 'w', 'utf8') as f: + text = ''.join(hl(i+1, line) for (i, line) in enumerate(lines)) + ctx = {'filename': filename, 'text': text} + f.write(self.stemplate.render(ctx)) + shutil.copyfile(path.join(path.dirname(__file__), 'style', 'default.css'), + path.join(self.outdir, 'default.css')) + + def hl(self, text, ver): + text = escape(text) + for directive in ['versionchanged', 'versionadded', 'deprecated']: + text = text.replace('.. %s:: %s' % (directive, ver), + '.. %s:: %s' % (directive, ver)) + return text + + def finish(self): + pass + + builders = { 'html': StandaloneHTMLBuilder, 'web': WebHTMLBuilder, 'htmlhelp': HTMLHelpBuilder, 'latex': LaTeXBuilder, + 'changes': ChangesBuilder, } diff --git a/sphinx/directives.py b/sphinx/directives.py index d89b170fb..a53bb7c6e 100644 --- a/sphinx/directives.py +++ b/sphinx/directives.py @@ -428,7 +428,7 @@ def version_directive(name, arguments, options, content, lineno, else: ret = [node] env = state.document.settings.env - env.note_versionchange(node['type'], node['version'], node) + env.note_versionchange(node['type'], node['version'], node, lineno) return ret version_directive.arguments = (1, 1, 1) diff --git a/sphinx/environment.py b/sphinx/environment.py index a156cbd78..d755ca854 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -52,7 +52,7 @@ default_settings = { # This is increased every time a new environment attribute is added # to properly invalidate pickle files. -ENV_VERSION = 13 +ENV_VERSION = 14 def walk_depth(node, depth, maxdepth): @@ -222,7 +222,7 @@ class BuildEnvironment: self.indexentries = {} # filename -> list of # (type, string, target, aliasname) self.versionchanges = {} # version -> list of - # (type, filename, module, descname, content) + # (type, filename, lineno, module, descname, content) # These are set while parsing a file self.filename = None # current file name @@ -383,7 +383,8 @@ class BuildEnvironment: if save_parsed: # save the parsed doctree - doctree_filename = path.join(self.doctreedir, os_path(filename)[:-3] + 'doctree') + doctree_filename = path.join(self.doctreedir, + os_path(filename)[:-3] + 'doctree') dirname = path.dirname(doctree_filename) if not path.isdir(dirname): os.makedirs(dirname) @@ -528,9 +529,9 @@ class BuildEnvironment: self.indexentries.setdefault(self.filename, []).append( (type, string, targetid, aliasname)) - def note_versionchange(self, type, version, node): + def note_versionchange(self, type, version, node, lineno): self.versionchanges.setdefault(version, []).append( - (type, self.filename, self.currmodule, self.currdesc, node.deepcopy())) + (type, self.filename, lineno, self.currmodule, self.currdesc, node.astext())) # ------- # --------- RESOLVING REFERENCES AND TOCTREES ------------------------------ @@ -603,6 +604,8 @@ class BuildEnvironment: try: if typ == 'ref': + # reference to the named label; the final node will contain the + # section name after the label filename, labelid, sectname = self.labels.get(target, ('','','')) if not filename: newnode = doctree.reporter.system_message( @@ -620,6 +623,20 @@ class BuildEnvironment: newnode['refuri'] = builder.get_relative_uri( docfilename, filename) + '#' + labelid newnode.append(innernode) + elif typ == 'keyword': + # keywords are referenced by named labels + filename, labelid, _ = self.labels.get(target, ('','','')) + if not filename: + self._warnfunc('%s: unknown keyword: %s' % (docfilename, target)) + newnode = contnode + else: + newnode = nodes.reference('', '') + if filename == docfilename: + newnode['refid'] = labelid + else: + newnode['refuri'] = builder.get_relative_uri( + docfilename, filename) + '#' + labelid + newnode.append(contnode) elif typ in ('token', 'term', 'envvar', 'option'): filename, labelid = self.reftargets.get((typ, target), ('', '')) if not filename: @@ -656,10 +673,12 @@ class BuildEnvironment: synopsis, (' (deprecated)' if deprecated else '')) newnode.append(contnode) else: + # "descrefs" modname = node['modname'] clsname = node['classname'] searchorder = 1 if node.hasattr('refspecific') else 0 - name, desc = self.find_desc(modname, clsname, target, typ, searchorder) + name, desc = self.find_desc(modname, clsname, + target, typ, searchorder) if not desc: newnode = contnode else: diff --git a/sphinx/latexwriter.py b/sphinx/latexwriter.py index f95940913..a3d5a06ad 100644 --- a/sphinx/latexwriter.py +++ b/sphinx/latexwriter.py @@ -25,6 +25,7 @@ from . import highlighting HEADER = r'''%% Generated by Sphinx. \documentclass[%(papersize)s,%(pointsize)s]{%(docclass)s} \usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} \usepackage[colorlinks,breaklinks]{hyperref} \title{%(title)s} \date{%(date)s} @@ -408,7 +409,7 @@ class LaTeXTranslator(nodes.NodeVisitor): # this is a list in the source, but should be rendered as a # comma-separated list here self.body.append('\n\n') - self.body.append(', '.join(n.astext() for n in node.children[0].children)) + self.body.append(', '.join(n.astext() for n in node.children[0].children) + '.') self.body.append('\n\n') raise nodes.SkipNode diff --git a/sphinx/roles.py b/sphinx/roles.py index dea1d44ec..6721f547f 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -23,7 +23,6 @@ generic_docroles = { 'dfn' : nodes.emphasis, 'guilabel' : nodes.strong, 'kbd' : nodes.literal, - 'keyword' : nodes.literal, 'mailheader' : addnodes.literal_emphasis, 'makevar' : nodes.Text, 'manpage' : addnodes.literal_emphasis, @@ -172,6 +171,7 @@ specific_docroles = { 'mod' : xfileref_role, + 'keyword': xfileref_role, 'ref': xfileref_role, 'token' : xfileref_role, 'term': xfileref_role, diff --git a/sphinx/search.py b/sphinx/search.py index 8d8ce188f..f5622f704 100644 --- a/sphinx/search.py +++ b/sphinx/search.py @@ -10,9 +10,10 @@ """ import re import pickle - from collections import defaultdict + from docutils.nodes import Text, NodeVisitor + from .util.stemmer import PorterStemmer from .util.json import dump_json, load_json diff --git a/sphinx/style/default.css b/sphinx/style/default.css index 506aed816..ce7076da1 100644 --- a/sphinx/style/default.css +++ b/sphinx/style/default.css @@ -154,7 +154,6 @@ div.sidebar input { div.modulecloud { margin: -5px 10px 5px 10px; padding: 10px; - font-size: 110%; line-height: 160%; border: 1px solid #cbe7e5; background-color: #f2fbfd; @@ -708,6 +707,7 @@ pre { tt { background-color: #ecf0f3; padding: 0 1px 0 1px; + font-size: 0.95em; } tt.descname { diff --git a/sphinx/templates/rstsource.html b/sphinx/templates/rstsource.html new file mode 100644 index 000000000..4abef620f --- /dev/null +++ b/sphinx/templates/rstsource.html @@ -0,0 +1,15 @@ + + + + {{ filename }} — Python Documentation + + + +
+      {{ text }}
+    
+ + \ No newline at end of file diff --git a/sphinx/templates/sidebar.html b/sphinx/templates/sidebar.html index bb492ba85..cb9f66f4c 100644 --- a/sphinx/templates/sidebar.html +++ b/sphinx/templates/sidebar.html @@ -54,6 +54,9 @@ + {% if builder == 'web' %} +

Enter a module, class or function name.

+ {% endif %} {% endif %} diff --git a/sphinx/templates/versionchanges.html b/sphinx/templates/versionchanges.html new file mode 100644 index 000000000..e31de59c6 --- /dev/null +++ b/sphinx/templates/versionchanges.html @@ -0,0 +1,33 @@ +{% macro entries changes %} + +{% endmacro -%} + + + + + + Changes in Version {{ version }} — Python Documentation + + +
+
+

Automatically generated list of changes in version {{ version }}

+

Library changes

+ {% for modname, changes in libchanges %} +

{{ modname }}

+ {{ entries(changes) }} + {% endfor %} +

C API changes

+ {{ entries(apichanges) }} +

Other changes

+ {% for (fn, title), changes in otherchanges %} +

{{ title }} ({{ fn }})

+ {{ entries(changes) }} + {% endfor %} +
+
+ + \ No newline at end of file diff --git a/sphinx/templates/versionchanges_frameset.html b/sphinx/templates/versionchanges_frameset.html new file mode 100644 index 000000000..5c99af9ab --- /dev/null +++ b/sphinx/templates/versionchanges_frameset.html @@ -0,0 +1,11 @@ + + + + Changes in Version {{ version }} — Python Documentation + + + + + + \ No newline at end of file diff --git a/sphinx/texinputs/howto.cls b/sphinx/texinputs/howto.cls index 4b7c9d5f0..aacb36e70 100644 --- a/sphinx/texinputs/howto.cls +++ b/sphinx/texinputs/howto.cls @@ -1,5 +1,5 @@ % -% howto.cls for the Python documentation +% howto.cls for Sphinx % \NeedsTeXFormat{LaTeX2e}[1995/12/01] @@ -34,7 +34,7 @@ % This gives us all the Python-specific markup that we really want. % This should come last. Do not change this. % -\RequirePackage{python} +\RequirePackage{sphinx} % This comes after python.sty because it otherwise defines its own % "seealso" command. diff --git a/sphinx/texinputs/manual.cls b/sphinx/texinputs/manual.cls index 5e0eb7af2..7d326abe4 100644 --- a/sphinx/texinputs/manual.cls +++ b/sphinx/texinputs/manual.cls @@ -1,5 +1,5 @@ % -% manual.cls for the Python documentation +% manual.cls for Sphinx % \NeedsTeXFormat{LaTeX2e}[1995/12/01] @@ -43,9 +43,9 @@ % This gives us all the Python-specific markup that we really want. % This should come last. Do not change this. % -\RequirePackage{python} +\RequirePackage{sphinx} -% This comes after python.sty because it otherwise defines its own +% This comes after sphinx.sty because it otherwise defines its own % "seealso" command. \RequirePackage{makeidx} diff --git a/sphinx/texinputs/python.sty b/sphinx/texinputs/sphinx.sty similarity index 92% rename from sphinx/texinputs/python.sty rename to sphinx/texinputs/sphinx.sty index 18db7e6dc..dbf1f465f 100644 --- a/sphinx/texinputs/python.sty +++ b/sphinx/texinputs/sphinx.sty @@ -1,10 +1,13 @@ % -% python.sty for the Python docummentation [works only with Latex2e] +% sphinx.sty +% +% Adapted from the old python.sty, mostly written by Fred Drake, +% by Georg Brandl. % \NeedsTeXFormat{LaTeX2e}[1995/12/01] -\ProvidesPackage{python} - [1998/01/11 LaTeX package (Python markup)] +\ProvidesPackage{sphinx} + [2007/12/30 LaTeX package (Sphinx markup)] \RequirePackage{textcomp} \RequirePackage{longtable} @@ -310,17 +313,6 @@ \newcommand{\refexmodindex}[1]{\py@refmodule{#1}{extension }} \newcommand{\refstmodindex}[1]{\py@refmodule{#1}{standard }} -% Refer to a module's documentation using a hyperlink of the module's -% name, at least if we're building PDF: -\ifpdf - \newcommand{\refmodule}[2][\py@modulebadkey]{% - \ifx\py@modulebadkey#1\def\py@modulekey{#2}\else\def\py@modulekey{#1}\fi% - \py@linkToName{label-module-\py@modulekey}{\module{#2}}% - } -\else - \newcommand{\refmodule}[2][\py@modulebadkey]{\module{#2}} -\fi - % support for the module index \newif\ifpy@UseModuleIndex \py@UseModuleIndexfalse @@ -839,9 +831,7 @@ % Also for consistency: spell Python "Python", not "python"! -% code is the most difficult one... -\newcommand{\code}[1]{\textrm{\@vobeyspaces\@noligs\def\{{\char`\{}\def\}{\char`\}}\def\~{\char`\~}\def\^{\char`\^}\def\e{\char`\\}\def\${\char`\$}\def\#{\char`\#}\def\&{\char`\&}\def\%{\char`\%}% -\texttt{#1}}} +\newcommand{\code}[1]{\texttt{#1}} \newcommand{\bfcode}[1]{\code{\bfseries#1}} % bold-faced code font \newcommand{\csimplemacro}[1]{\code{#1}} @@ -861,28 +851,6 @@ \newcommand{\file}[1]{`\filenq{#1}'} \newcommand{\filenq}[1]{{\py@smallsize\textsf{\let\e=\textbackslash#1}}} -% Use this def/redef approach for \url{} since hyperref defined this already, -% but only if we actually used hyperref: -%\ifpdf -% \newcommand{\url}[1]{{% -% \py@pdfstartlink% -% attr{ /Border [0 0 0] }% -% user{% -% /Subtype/Link% -% /A<<% -% /Type/Action% -% /S/URI% -% /URI(#1)% -% >>% -% }% -% \py@LinkColor% color of the link text -% \py@smallsize\sf #1% -% \py@NormalColor% Turn it back off; these are declarative -% \pdfendlink}% and don't appear bound to the current -% }% formatting "box". -%\else -% \newcommand{\url}[1]{\mbox{\py@smallsize\textsf{#1}}} -%\fi \newcommand{\email}[1]{{\py@smallsize\textsf{#1}}} \newcommand{\newsgroup}[1]{{\py@smallsize\textsf{#1}}} @@ -891,14 +859,6 @@ \let\moreargs=\py@moreargs% \var{#1}}}} -% I'd really like to get rid of this! -\newif\iftexi\texifalse - -% This is used to get l2h to put the copyright and abstract on -% a separate HTML page. -\newif\ifhtml\htmlfalse - - % These should be used for all references to identifiers which are % used to refer to instances of specific language constructs. See the % names for specific semantic assignments. @@ -947,29 +907,6 @@ % Note that \longprogramopt provides the '--'! \newcommand{\longprogramopt}[1]{\strong{-{}-#1}} -% \ulink{link text}{URL} -\ifpdf - \newcommand{\ulink}[2]{{% - % For PDF, we *should* only generate a link when the URL is absolute. - \py@pdfstartlink% - attr{ /Border [0 0 0] }% - user{% - /Subtype/Link% - /A<<% - /Type/Action% - /S/URI% - /URI(#2)% - >>% - }% - \py@LinkColor% color of the link text - #1% - \py@NormalColor% Turn it back off; these are declarative - \pdfendlink}% and don't appear bound to the current - }% formatting "box". -\else - \newcommand{\ulink}[2]{#1} -\fi - % cited titles: \citetitle{Title of Work} % online: \citetitle[url-to-resource]{Title of Work} \ifpdf @@ -1160,27 +1097,6 @@ \end{center}% } -% XXX Don't think we can use this yet, though it cleans up some -% tedious markup. There's no equivalent for the HTML transform yet, -% and that needs to exist. I don't know how to write it. -% -% This should really have something that makes it easier to bind a -% table's ``Notes'' column and an associated tablenotes environment, -% and generates the right magic for getting the numbers right in the -% table. -% -% So this is quite incomplete. -% -\newcounter{py@tablenotescounter} -\newenvironment{tablenotes}{% - \noindent Notes: - \par - \setcounter{py@tablenotescounter}{0} - \begin{list}{(\arabic{py@tablenotescounter})}% - {\usecounter{py@tablenotescounter}} -}{\end{list}} - - % Cross-referencing (AMK, new impl. FLD) % Sample usage: % \begin{seealso} diff --git a/sphinx/web/admin.py b/sphinx/web/admin.py index 1930531b7..0c5f34862 100644 --- a/sphinx/web/admin.py +++ b/sphinx/web/admin.py @@ -88,7 +88,7 @@ class AdminPanel(object): Log the user out. """ req.logout() - return RedirectResponse('admin/login/') + return RedirectResponse('@admin/login/') def do_change_password(self, req): """ diff --git a/sphinx/web/antispam.py b/sphinx/web/antispam.py index 200171414..14fda41b0 100644 --- a/sphinx/web/antispam.py +++ b/sphinx/web/antispam.py @@ -43,13 +43,16 @@ class AntiSpam(object): else: lines = [l.strip() for l in data.splitlines() if not l.startswith('#')] - f = file(bad_content_file, 'w') - f.write('\n'.join(lines)) + with file(bad_content_file, 'w') as f: + f.write('\n'.join(lines)) last_change = int(time.time()) if lines is None: - with file(bad_content_file) as f: - lines = [l.strip() for l in f] + try: + with file(bad_content_file) as f: + lines = [l.strip() for l in f] + except: + lines = [] self.rules = [re.compile(rule) for rule in lines if rule] def is_spam(self, fields): diff --git a/sphinx/web/application.py b/sphinx/web/application.py index c17349308..df8069355 100644 --- a/sphinx/web/application.py +++ b/sphinx/web/application.py @@ -28,8 +28,7 @@ from collections import defaultdict from .feed import Feed from .mail import Email -from .util import render_template, render_simple_template, get_target_uri, \ - blackhole_dict, striptags +from .util import render_template, get_target_uri, blackhole_dict, striptags from .admin import AdminPanel from .userdb import UserDatabase from .robots import robots_txt @@ -39,9 +38,9 @@ from .database import connect, set_connection, Comment from .wsgiutil import Request, Response, RedirectResponse, \ JSONResponse, SharedDataMiddleware, NotFound, get_base_uri -from ..util import relative_uri, shorten_result +from ..util import relative_uri from ..search import SearchFrontend -from ..writer import HTMLWriter +from ..htmlwriter import HTMLWriter from ..builder import LAST_BUILD_FILENAME, ENV_PICKLE_FILENAME from docutils.io import StringOutput @@ -88,6 +87,7 @@ comments_methods = { class MockBuilder(object): def get_relative_uri(self, from_, to): return '' + name = 'web' NoCache = object() @@ -139,8 +139,7 @@ class DocumentationApplication(object): def load_env(self, new_mtime): - env_lock.acquire() - try: + with env_lock: if self.buildmtime == new_mtime: # happens if another thread already reloaded the env return @@ -153,8 +152,6 @@ class DocumentationApplication(object): self.search_frontend = SearchFrontend(pickle.load(f)) self.buildmtime = new_mtime self.cache.clear() - finally: - env_lock.release() def search(self, req): @@ -209,9 +206,11 @@ class DocumentationApplication(object): warning_stream = StringIO.StringIO() env2 = copy.deepcopy(self.env) destination = StringOutput(encoding='utf-8') - writer = HTMLWriter(env2.config) + builder = MockBuilder() + builder.config = env2.config + writer = HTMLWriter(builder) doctree = env2.read_file(page_id, pathname, save_parsed=False) - doctree = env2.get_and_resolve_doctree(page_id, MockBuilder(), doctree) + doctree = env2.get_and_resolve_doctree(page_id, builder, doctree) doctree.settings = OptionParser(defaults=env2.settings, components=(writer,)).get_default_values() doctree.reporter = Reporter(page_id, 2, 4, stream=warning_stream) diff --git a/sphinx/web/util.py b/sphinx/web/util.py index 616c724e4..872ec029b 100644 --- a/sphinx/web/util.py +++ b/sphinx/web/util.py @@ -71,11 +71,6 @@ def render_template(req, template_name, *contexts): return tmpl.render(context) -def render_simple_template(template_name, context): - tmpl = jinja_env.get_template(template_name) - return tmpl.render(context) - - class lazy_property(object): """ Descriptor implementing a "lazy property", i.e. the function