Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Ignacio Fdez. Galván
2015-03-17 11:44:21 +01:00
51 changed files with 290 additions and 135 deletions

20
CHANGES
View File

@@ -14,6 +14,26 @@ Documentation
-------------
Release 1.3.1 (released Mar 17, 2015)
=====================================
Bugs fixed
----------
* #1769: allows generating quickstart files/dirs for destination dir that
doesn't overwrite existent files/dirs. Thanks to WAKAYAMA shirou.
* #1773: sphinx-quickstart doesn't accept non-ASCII character as a option argument.
* #1766: the message "least Python 2.6 to run" is at best misleading.
* #1772: cross reference in docstrings like ``:param .write:`` breaks building.
* #1770, #1774: ``literalinclude`` with empty file occurs exception. Thanks to
Takayuki Hirai.
* #1777: Sphinx 1.3 can't load extra theme. Thanks to tell-k.
* #1776: ``source_suffix = ['.rst']`` cause unfriendly error on prior version.
* #1771: automated .mo building doesn't work properly.
* #1783: Autodoc: Python2 Allow unicode string in __all__.
Thanks to Jens Hedegaard Nielsen.
* #1781: Setting `html_domain_indices` to a list raises a type check warnings.
Release 1.3 (released Mar 10, 2015)
===================================

View File

@@ -8,10 +8,29 @@ This is the Sphinx documentation generator, see http://sphinx-doc.org/.
Installing
==========
Use ``setup.py``::
Install from PyPI to use stable version::
python setup.py build
sudo python setup.py install
pip install -U sphinx
Install from PyPI to use beta version::
pip install -U --pre sphinx
Install from newest dev version in stable branch::
pip install git+https://github.com/sphinx-doc/sphinx@stable
Install from newest dev version in master branch::
pip install git+https://github.com/sphinx-doc/sphinx
Install from cloned source::
pip install .
Install from cloned source as editable::
pip install -e .
Reading the docs

View File

@@ -263,5 +263,5 @@ following directive exists:
format and the builder name.
Note that the current builder tag is not available in ``conf.py``, it is
only available after the builder is intialized.
only available after the builder is initialized.

View File

@@ -1,5 +1,5 @@
[egg_info]
tag_build = dev
tag_build = .dev
tag_date = true
[aliases]

View File

@@ -17,6 +17,7 @@ from os import path
__version__ = '1.4a0+'
__released__ = '1.4a0' # used when Sphinx builds its own docs
# version info for better programmatic use
# possible values for 3rd element: 'alpha', 'beta', 'rc', 'final'
# 'final' has 0 as the last element
@@ -24,10 +25,13 @@ version_info = (1, 4, 0, 'alpha', 0)
package_dir = path.abspath(path.dirname(__file__))
if '+' in __version__ or 'pre' in __version__:
__display_version__ = __version__ # used for command line version
if __version__.endswith('+'):
# try to find out the changeset hash if checked out from hg, and append
# it to __version__ (since we use this value from setup.py, it gets
# automatically propagated to an installed copy as well)
__display_version__ = __version__
__version__ = __version__[:-1] # remove '+' for PEP-440 version spec.
try:
import subprocess
p = subprocess.Popen(['git', 'show', '-s', '--pretty=format:%h',
@@ -35,7 +39,7 @@ if '+' in __version__ or 'pre' in __version__:
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
if out:
__version__ += '/' + out.decode().strip()
__display_version__ += '/' + out.decode().strip()
except Exception:
pass
@@ -51,7 +55,7 @@ def build_main(argv=sys.argv):
"""Sphinx build "main" command-line entry."""
if (sys.version_info[:3] < (2, 6, 0) or
(3, 0, 0) <= sys.version_info[:3] < (3, 3, 0)):
sys.stderr.write('Error: Sphinx requires at least Python 2.6 to run.\n')
sys.stderr.write('Error: Sphinx requires at least Python 2.6 or 3.3 to run.\n')
return 1
try:
from sphinx import cmdline

View File

@@ -22,7 +22,7 @@ import optparse
from os import path
from sphinx.util.osutil import walk
from sphinx import __version__
from sphinx import __display_version__
# automodule options
if 'SPHINX_APIDOC_OPTIONS' in os.environ:
@@ -318,7 +318,7 @@ Note: By default this script will not overwrite already created files.""")
(opts, args) = parser.parse_args(argv[1:])
if opts.show_version:
print('Sphinx (sphinx-apidoc) %s' % __version__)
print('Sphinx (sphinx-apidoc) %s' % __display_version__)
return 0
if not args:

View File

@@ -111,7 +111,7 @@ class Sphinx(object):
self.messagelog = deque(maxlen=10)
# say hello to the world
self.info(bold('Running Sphinx v%s' % sphinx.__version__))
self.info(bold('Running Sphinx v%s' % sphinx.__display_version__))
# status code for command-line application
self.statuscode = 0
@@ -158,7 +158,7 @@ class Sphinx(object):
# check the Sphinx version if requested
if self.config.needs_sphinx and \
self.config.needs_sphinx > sphinx.__version__[:3]:
self.config.needs_sphinx > sphinx.__display_version__[:3]:
raise VersionRequirementError(
'This project needs at least Sphinx v%s and therefore cannot '
'be built with this version.' % self.config.needs_sphinx)
@@ -453,7 +453,7 @@ class Sphinx(object):
def require_sphinx(self, version):
# check the Sphinx version if requested
if version > sphinx.__version__[:3]:
if version > sphinx.__display_version__[:3]:
raise VersionRequirementError(version)
def import_object(self, objname, source=None):

View File

@@ -21,7 +21,8 @@ except ImportError:
from docutils import nodes
from sphinx.util import i18n, path_stabilize
from sphinx.util.osutil import SEP, relative_uri, find_catalog
from sphinx.util.osutil import SEP, relative_uri
from sphinx.util.i18n import find_catalog
from sphinx.util.console import bold, darkgreen
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \
parallel_available
@@ -166,9 +167,11 @@ class Builder(object):
catalog.write_mo(self.config.language)
def compile_all_catalogs(self):
catalogs = i18n.get_catalogs(
catalogs = i18n.find_catalog_source_files(
[path.join(self.srcdir, x) for x in self.config.locale_dirs],
self.config.language, True)
self.config.language,
gettext_compact=self.config.gettext_compact,
force_all=True)
message = 'all of %d po files' % len(catalogs)
self.compile_catalogs(catalogs, message)
@@ -179,17 +182,19 @@ class Builder(object):
return dom
specified_domains = set(map(to_domain, specified_files))
catalogs = i18n.get_catalogs(
catalogs = i18n.find_catalog_source_files(
[path.join(self.srcdir, x) for x in self.config.locale_dirs],
self.config.language, True)
catalogs = [f for f in catalogs if f.domain in specified_domains]
self.config.language,
domains=list(specified_domains),
gettext_compact=self.config.gettext_compact)
message = 'targets for %d po files that are specified' % len(catalogs)
self.compile_catalogs(catalogs, message)
def compile_update_catalogs(self):
catalogs = i18n.get_catalogs(
catalogs = i18n.find_catalog_source_files(
[path.join(self.srcdir, x) for x in self.config.locale_dirs],
self.config.language)
self.config.language,
gettext_compact=self.config.gettext_compact)
message = 'targets for %d po files that are out of date' % len(catalogs)
self.compile_catalogs(catalogs, message)

View File

@@ -23,7 +23,8 @@ from six import iteritems
from sphinx.builders import Builder
from sphinx.util import split_index_msg
from sphinx.util.nodes import extract_messages, traverse_translatable_index
from sphinx.util.osutil import safe_relpath, ensuredir, find_catalog, SEP
from sphinx.util.osutil import safe_relpath, ensuredir, SEP
from sphinx.util.i18n import find_catalog
from sphinx.util.console import darkgreen, purple, bold
from sphinx.locale import pairindextypes

View File

@@ -26,7 +26,7 @@ from docutils.utils import new_document
from docutils.frontend import OptionParser
from docutils.readers.doctree import Reader as DoctreeReader
from sphinx import package_dir, __version__
from sphinx import package_dir, __display_version__
from sphinx.util import jsonimpl, copy_static_entry
from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \
movefile, ustrftime, copyfile
@@ -343,7 +343,7 @@ class StandaloneHTMLBuilder(Builder):
script_files = self.script_files,
language = self.config.language,
css_files = self.css_files,
sphinx_version = __version__,
sphinx_version = __display_version__,
style = stylename,
rellinks = rellinks,
builder = self.name,

View File

@@ -18,7 +18,7 @@ from os import path
from six import text_type, binary_type
from docutils.utils import SystemMessage
from sphinx import __version__
from sphinx import __display_version__
from sphinx.errors import SphinxError
from sphinx.application import Sphinx
from sphinx.util import Tee, format_exception_cut_frames, save_traceback
@@ -40,7 +40,7 @@ Filename arguments:
without -a and without filenames, write new and changed files.
with -a, write all files.
with filenames, write these.
""" % __version__
""" % __display_version__
EPILOG = """\
For more information, visit <http://sphinx-doc.org/>.
@@ -131,7 +131,7 @@ def main(argv):
# handle basic options
if opts.version:
print('Sphinx (sphinx-build) %s' % __version__)
print('Sphinx (sphinx-build) %s' % __display_version__)
return 0
# get paths (first and second positional argument)

View File

@@ -28,6 +28,10 @@ if PY3:
CONFIG_EXIT_ERROR = "The configuration file (or one of the modules it imports) " \
"called sys.exit()"
IGNORE_CONFIG_TYPE_CHECKS = (
'html_domain_indices', 'latex_domain_indices', 'texinfo_domain_indices'
)
class Config(object):
"""
@@ -288,6 +292,8 @@ class Config(object):
# NB. since config values might use l_() we have to wait with calling
# this method until i18n is initialized
for name in self._raw_config:
if name in IGNORE_CONFIG_TYPE_CHECKS:
continue # for a while, ignore multiple types config value. see #1781
if name not in Config.config_values:
continue # we don't know a default value
default, dummy_rebuild = Config.config_values[name]

View File

@@ -219,7 +219,7 @@ class LiteralInclude(Directive):
lines = self.read_with_encoding(filename, document,
codec_info, encoding)
if not isinstance(lines[0], string_types):
if lines and not isinstance(lines[0], string_types):
return lines
diffsource = self.options.get('diff')

View File

@@ -90,13 +90,15 @@ class PyXrefMixin(object):
result = super(PyXrefMixin, self).make_xref(rolename, domain, target,
innernode, contnode)
result['refspecific'] = True
if target.startswith('.'):
result['reftarget'] = target[1:]
result[0][0] = nodes.Text(target[1:])
if target.startswith('~'):
result['reftarget'] = target[1:]
title = target.split('.')[-1]
result[0][0] = nodes.Text(title)
if target.startswith(('.', '~')):
prefix, result['reftarget'] = target[0], target[1:]
if prefix == '.':
text = target[1:]
elif prefix == '~':
text = target.split('.')[-1]
for node in result.traverse(nodes.Text):
node.parent[node.parent.index(node)] = nodes.Text(text)
break
return result

View File

@@ -40,7 +40,8 @@ from sphinx import addnodes
from sphinx.util import url_re, get_matching_docs, docname_join, split_into, \
FilenameUniqDict, get_figtype, import_object
from sphinx.util.nodes import clean_astext, make_refnode, WarningStream, is_translatable
from sphinx.util.osutil import SEP, find_catalog_files, getcwd, fs_encoding
from sphinx.util.osutil import SEP, getcwd, fs_encoding
from sphinx.util.i18n import find_catalog_files
from sphinx.util.console import bold, purple
from sphinx.util.matching import compile_matchers
from sphinx.util.parallel import ParallelTasks, parallel_available, make_chunks

View File

@@ -17,7 +17,7 @@ import inspect
import traceback
from types import FunctionType, BuiltinFunctionType, MethodType
from six import iteritems, itervalues, text_type, class_types
from six import iteritems, itervalues, text_type, class_types, string_types
from docutils import nodes
from docutils.utils import assemble_option_dict
from docutils.statemachine import ViewList
@@ -888,7 +888,7 @@ class ModuleDocumenter(Documenter):
memberlist = self.object.__all__
# Sometimes __all__ is broken...
if not isinstance(memberlist, (list, tuple)) or not \
all(isinstance(entry, str) for entry in memberlist):
all(isinstance(entry, string_types) for entry in memberlist):
self.directive.warn(
'__all__ should be a list of strings, not %r '
'(in module %s) -- ignoring __all__' %
@@ -1525,7 +1525,7 @@ def setup(app):
app.add_event('autodoc-process-signature')
app.add_event('autodoc-skip-member')
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
class testcls:

View File

@@ -584,4 +584,4 @@ def setup(app):
app.connect('doctree-read', process_autosummary_toc)
app.connect('builder-inited', process_generate_options)
app.add_config_value('autosummary_generate', [], True)
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -266,4 +266,4 @@ def setup(app):
app.add_config_value('coverage_ignore_c_items', {}, False)
app.add_config_value('coverage_write_headline', True, False)
app.add_config_value('coverage_skip_undoc_in_source', False, False)
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -444,4 +444,4 @@ def setup(app):
app.add_config_value('doctest_test_doctest_blocks', 'default', False)
app.add_config_value('doctest_global_setup', '', False)
app.add_config_value('doctest_global_cleanup', '', False)
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -61,4 +61,4 @@ def setup_link_roles(app):
def setup(app):
app.add_config_value('extlinks', {}, 'env')
app.connect('builder-inited', setup_link_roles)
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -317,4 +317,4 @@ def setup(app):
app.add_config_value('graphviz_dot', 'dot', 'html')
app.add_config_value('graphviz_dot_args', [], 'html')
app.add_config_value('graphviz_output_format', 'png', 'html')
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -75,4 +75,4 @@ def setup(app):
app.add_node(ifconfig)
app.add_directive('ifconfig', IfConfig)
app.connect('doctree-resolved', process_ifconfig_nodes)
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -408,4 +408,4 @@ def setup(app):
app.add_config_value('inheritance_graph_attrs', {}, False),
app.add_config_value('inheritance_node_attrs', {}, False),
app.add_config_value('inheritance_edge_attrs', {}, False),
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -282,4 +282,4 @@ def setup(app):
app.add_config_value('intersphinx_cache_limit', 5, False)
app.connect('missing-reference', missing_reference)
app.connect('builder-inited', load_mappings)
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -59,4 +59,4 @@ def setup(app):
mathbase_setup(app, (html_visit_math, None), (html_visit_displaymath, None))
app.add_config_value('jsmath_path', '', False)
app.connect('builder-inited', builder_inited)
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -74,4 +74,4 @@ def doctree_read(app, doctree):
def setup(app):
app.connect('doctree-read', doctree_read)
app.add_config_value('linkcode_resolve', None, '')
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -71,4 +71,4 @@ def setup(app):
app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html')
app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html')
app.connect('builder-inited', builder_inited)
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -256,7 +256,7 @@ def setup(app):
for name, (default, rebuild) in iteritems(Config._config_values):
app.add_config_value(name, default, rebuild)
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
def _process_docstring(app, what, name, obj, options, lines):

View File

@@ -247,4 +247,4 @@ def setup(app):
app.add_config_value('pngmath_latex_preamble', '', 'html')
app.add_config_value('pngmath_add_tooltips', True, 'html')
app.connect('build-finished', cleanup_tempdir)
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -188,4 +188,4 @@ def setup(app):
app.connect('doctree-resolved', process_todo_nodes)
app.connect('env-purge-doc', purge_todos)
app.connect('env-merge-info', merge_info)
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -217,4 +217,4 @@ def setup(app):
app.connect('missing-reference', missing_reference)
# app.add_config_value('viewcode_include_modules', [], 'env')
# app.add_config_value('viewcode_exclude_modules', [], 'env')
return {'version': sphinx.__version__, 'parallel_read_safe': True}
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@@ -208,6 +208,14 @@ def init(locale_dirs, language, catalog='sphinx'):
translator = None
# the None entry is the system's default locale path
has_translation = True
# compile mo files if po file is updated
# TODO: remove circular importing
from sphinx.util.i18n import find_catalog_source_files
for catinfo in find_catalog_source_files(locale_dirs, language, domains=[catalog]):
catinfo.write_mo(language)
# loading
for dir_ in locale_dirs:
try:
trans = gettext.translation(catalog, localedir=dir_,

View File

@@ -78,7 +78,7 @@ class Make(object):
shutil.rmtree(self.builddir_join(item))
def build_help(self):
print(bold("Sphinx v%s" % sphinx.__version__))
print(bold("Sphinx v%s" % sphinx.__display_version__))
print("Please use `make %s' where %s is one of" % ((blue('target'),)*2))
for osname, bname, description in BUILDERS:
if not osname or os.name == osname:

View File

@@ -28,12 +28,12 @@ try:
except ImportError:
pass
from six import PY2, PY3, text_type
from six import PY2, PY3, text_type, binary_type
from six.moves import input
from six.moves.urllib.parse import quote as urlquote
from docutils.utils import column_width
from sphinx import __version__
from sphinx import __display_version__
from sphinx.util.osutil import make_filename
from sphinx.util.console import purple, bold, red, turquoise, \
nocolor, color_terminal
@@ -108,7 +108,9 @@ extensions = [%(extensions)s]
templates_path = ['%(dot)stemplates']
# The suffix(es) of source filenames.
source_suffix = ['%(suffix)s']
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '%(suffix)s'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
@@ -1048,6 +1050,27 @@ def ok(x):
return x
def term_decode(text):
if isinstance(text, text_type):
return text
# for Python 2.x, try to get a Unicode string out of it
if text.decode('ascii', 'replace').encode('ascii', 'replace') == text:
return text
if TERM_ENCODING:
text = text.decode(TERM_ENCODING)
else:
print(turquoise('* Note: non-ASCII characters entered '
'and terminal encoding unknown -- assuming '
'UTF-8 or Latin-1.'))
try:
text = text.decode('utf-8')
except UnicodeDecodeError:
text = text.decode('latin1')
return text
def do_prompt(d, key, text, default=None, validator=nonempty):
while True:
if default:
@@ -1072,19 +1095,7 @@ def do_prompt(d, key, text, default=None, validator=nonempty):
x = term_input(prompt).strip()
if default and not x:
x = default
if not isinstance(x, text_type):
# for Python 2.x, try to get a Unicode string out of it
if x.decode('ascii', 'replace').encode('ascii', 'replace') != x:
if TERM_ENCODING:
x = x.decode(TERM_ENCODING)
else:
print(turquoise('* Note: non-ASCII characters entered '
'and terminal encoding unknown -- assuming '
'UTF-8 or Latin-1.'))
try:
x = x.decode('utf-8')
except UnicodeDecodeError:
x = x.decode('latin1')
x = term_decode(x)
try:
x = validator(x)
except ValidationError as err:
@@ -1126,7 +1137,7 @@ def ask_user(d):
* batchfile: make command file
"""
print(bold('Welcome to the Sphinx %s quickstart utility.') % __version__)
print(bold('Welcome to the Sphinx %s quickstart utility.') % __display_version__)
print('''
Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).''')
@@ -1396,13 +1407,42 @@ def usage(argv, msg=None):
USAGE = """\
Sphinx v%s
Usage: %%prog [options] [projectdir]
""" % __version__
""" % __display_version__
EPILOG = """\
For more information, visit <http://sphinx-doc.org/>.
"""
def valid_dir(d):
dir = d['path']
if not path.exists(dir):
return True
if not path.isdir(dir):
return False
if set(['Makefile', 'make.bat']) & set(os.listdir(dir)):
return False
if d['sep']:
dir = os.path.join('source', dir)
if not path.exists(dir):
return True
if not path.isdir(dir):
return False
reserved_names = [
'conf.py',
d['dot'] + 'static',
d['dot'] + 'templates',
d['master'] + d['suffix'],
]
if set(reserved_names) & set(os.listdir(dir)):
return False
return True
class MyFormatter(optparse.IndentedHelpFormatter):
def format_usage(self, usage):
return usage
@@ -1421,7 +1461,7 @@ def main(argv=sys.argv):
nocolor()
parser = optparse.OptionParser(USAGE, epilog=EPILOG,
version='Sphinx v%s' % __version__,
version='Sphinx v%s' % __display_version__,
formatter=MyFormatter())
parser.add_option('-q', '--quiet', action='store_true', dest='quiet',
default=False,
@@ -1486,21 +1526,17 @@ def main(argv=sys.argv):
opts.ensure_value('path', args[0])
d = vars(opts)
for k, v in list(d.items()):
# delete None or False value
if v is None or v is False:
del d[k]
# delete None or False value
d = dict((k, v) for k, v in d.items() if not (v is None or v is False))
try:
if 'quiet' in d:
if 'project' not in d or 'author' not in d or \
'version' not in d:
if not set(['project', 'author', 'version']).issubset(d):
print('''"quiet" is specified, but any of "project", \
"author" or "version" is not specified.''')
return
if all(['quiet' in d, 'project' in d, 'author' in d,
'version' in d]):
if set(['quiet', 'project', 'author', 'version']).issubset(d):
# quiet mode with all required params satisfied, use default
d.setdefault('release', d['version'])
d2 = DEFAULT_VALUE.copy()
@@ -1512,11 +1548,10 @@ def main(argv=sys.argv):
if 'no_batchfile' in d:
d['batchfile'] = False
if path.exists(d['path']) and (
not path.isdir(d['path']) or os.listdir(d['path'])):
if not valid_dir(d):
print()
print(bold('Error: specified path is not a directory, or not a'
' empty directory.'))
print(bold('Error: specified path is not a directory, or sphinx'
' files already exist.'))
print('sphinx-quickstart only generate into a empty directory.'
' Please specify a new root path.')
return
@@ -1526,6 +1561,12 @@ def main(argv=sys.argv):
print()
print('[Interrupted.]')
return
# decode values in d if value is a Python string literal
for key, value in d.items():
if isinstance(value, binary_type):
d[key] = term_decode(value)
generate(d)
if __name__ == '__main__':

View File

@@ -86,7 +86,7 @@ class Theme(object):
if not path.isdir(themedir):
continue
for theme in os.listdir(themedir):
if theme != 'name':
if theme != name:
continue
if not path.isfile(path.join(themedir, theme, THEMECONF)):
continue

View File

@@ -23,7 +23,8 @@ from sphinx.util import split_index_msg
from sphinx.util.nodes import (
traverse_translatable_index, extract_messages, LITERAL_TYPE_NODES, IMAGE_TYPE_NODES,
)
from sphinx.util.osutil import ustrftime, find_catalog
from sphinx.util.osutil import ustrftime
from sphinx.util.i18n import find_catalog
from sphinx.util.pycompat import indent
from sphinx.domains.std import (
make_term_from_paragraph_node,

View File

@@ -207,7 +207,7 @@ def save_traceback(app):
'# %s' % strip_colors(force_decode(s, 'utf-8')).strip()
for s in app.messagelog)
os.write(fd, (_DEBUG_HEADER %
(sphinx.__version__,
(sphinx.__display_version__,
platform.python_version(),
platform.python_implementation(),
docutils.__version__, docutils.__version_details__,

View File

@@ -8,7 +8,7 @@
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import gettext
from os import path
from collections import namedtuple
@@ -16,6 +16,7 @@ from babel.messages.pofile import read_po
from babel.messages.mofile import write_mo
from sphinx.util.osutil import walk
from sphinx.util import SEP
LocaleFileInfoBase = namedtuple('CatalogInfo', 'base_dir,domain')
@@ -50,13 +51,36 @@ class CatalogInfo(LocaleFileInfoBase):
write_mo(mo, read_po(po, locale))
def get_catalogs(locale_dirs, locale, gettext_compact=False, force_all=False):
def find_catalog(docname, compaction):
if compaction:
ret = docname.split(SEP, 1)[0]
else:
ret = docname
return ret
def find_catalog_files(docname, srcdir, locale_dirs, lang, compaction):
if not(lang and locale_dirs):
return []
domain = find_catalog(docname, compaction)
files = [gettext.find(domain, path.join(srcdir, dir_), [lang])
for dir_ in locale_dirs]
files = [path.relpath(f, srcdir) for f in files if f]
return files
def find_catalog_source_files(locale_dirs, locale, domains=None, gettext_compact=False,
force_all=False):
"""
:param list locale_dirs:
list of path as `['locale_dir1', 'locale_dir2', ...]` to find
translation catalogs. Each path contains a structure such as
`<locale>/LC_MESSAGES/domain.po`.
:param str locale: a language as `'en'`
:param list domains: list of domain names to get. If empty list or None
is specified, get all domain names. default is None.
:param boolean gettext_compact:
* False: keep domains directory structure (default).
* True: domains in the sub directory will be merged into 1 file.
@@ -70,6 +94,9 @@ def get_catalogs(locale_dirs, locale, gettext_compact=False, force_all=False):
catalogs = set()
for locale_dir in locale_dirs:
if not locale_dir:
continue # skip system locale directory
base_dir = path.join(locale_dir, locale, 'LC_MESSAGES')
if not path.exists(base_dir):
@@ -82,6 +109,9 @@ def get_catalogs(locale_dirs, locale, gettext_compact=False, force_all=False):
domain = path.relpath(path.join(dirpath, base), base_dir)
if gettext_compact and path.sep in domain:
domain = path.split(domain)[0]
domain = domain.replace(path.sep, SEP)
if domains and domain not in domains:
continue
cat = CatalogInfo(base_dir, domain)
if force_all or cat.is_outdated():
catalogs.add(cat)

View File

@@ -17,7 +17,6 @@ import time
import errno
import locale
import shutil
import gettext
from os import path
import contextlib
@@ -170,26 +169,6 @@ def safe_relpath(path, start=None):
return path
def find_catalog(docname, compaction):
if compaction:
ret = docname.split(SEP, 1)[0]
else:
ret = docname
return ret
def find_catalog_files(docname, srcdir, locale_dirs, lang, compaction):
if not(lang and locale_dirs):
return []
domain = find_catalog(docname, compaction)
files = [gettext.find(domain, path.join(srcdir, dir_), [lang])
for dir_ in locale_dirs]
files = [path.relpath(f, srcdir) for f in files if f]
return files
fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()

View File

@@ -17,7 +17,7 @@ from six import itervalues
from six.moves import range
from docutils import nodes, writers
from sphinx import addnodes, __version__
from sphinx import addnodes, __display_version__
from sphinx.locale import admonitionlabels, _
from sphinx.util import ustrftime
from sphinx.writers.latex import collected_footnote
@@ -39,7 +39,7 @@ TEMPLATE = """\
@setfilename %(filename)s
@documentencoding UTF-8
@ifinfo
@*Generated by Sphinx """ + __version__ + """.@*
@*Generated by Sphinx """ + __display_version__ + """.@*
@end ifinfo
@settitle %(title)s
@defindex ge

View File

@@ -0,0 +1,2 @@
recursive-include test_theme *.conf

View File

@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
html_theme = 'test-theme'
master_doc = 'index'

View File

@@ -0,0 +1,5 @@
=======
Theming
=======

View File

@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
from setuptools import setup, find_packages
setup(
name='test-theme',
packages=find_packages(),
include_package_data=True,
entry_points="""
[sphinx_themes]
path = test_theme:get_path
""",
)

View File

@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
import os
def get_path():
return os.path.dirname(os.path.abspath(__file__))

View File

@@ -0,0 +1,2 @@
[theme]
inherit = classic

View File

@@ -15,7 +15,7 @@ import re
from six import PY3, iteritems
from six.moves import html_entities
from sphinx import __version__
from sphinx import __display_version__
from util import remove_unicode_literals, gen_with_app
from etree13 import ElementTree as ET
@@ -347,7 +347,7 @@ def check_static_entries(outdir):
assert (staticdir / 'subdir' / 'foo.css').isfile()
# a file from a file entry in html_static_path
assert (staticdir / 'templated.css').isfile()
assert (staticdir / 'templated.css').text().splitlines()[1] == __version__
assert (staticdir / 'templated.css').text().splitlines()[1] == __display_version__
# a file from _static, but matches exclude_patterns
assert not (staticdir / 'excluded.css').exists()

View File

@@ -55,10 +55,13 @@ def test_compile_all_catalogs(app, status, warning):
@with_app(buildername='html', testroot='intl',
confoverrides={'language': 'en', 'locale_dirs': [locale_dir]})
def test_compile_specific_catalogs(app, status, warning):
app.builder.compile_specific_catalogs(['admonitions'])
catalog_dir = locale_dir / app.config.language / 'LC_MESSAGES'
actual = set(find_files(catalog_dir, '.mo'))
def get_actual():
return set(find_files(catalog_dir, '.mo'))
actual_on_boot = get_actual() # sphinx.mo might be included
app.builder.compile_specific_catalogs(['admonitions'])
actual = get_actual() - actual_on_boot
assert actual == set(['admonitions.mo'])

View File

@@ -144,7 +144,7 @@ def test_quickstart_defaults(tempdir):
execfile_(conffile, ns)
assert ns['extensions'] == []
assert ns['templates_path'] == ['_templates']
assert ns['source_suffix'] == ['.rst']
assert ns['source_suffix'] == '.rst'
assert ns['master_doc'] == 'index'
assert ns['project'] == 'Sphinx Test'
assert ns['copyright'] == '%s, Georg Brandl' % time.strftime('%Y')
@@ -203,7 +203,7 @@ def test_quickstart_all_answers(tempdir):
'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo'
]
assert ns['templates_path'] == ['.templates']
assert ns['source_suffix'] == ['.txt']
assert ns['source_suffix'] == '.txt'
assert ns['master_doc'] == 'contents'
assert ns['project'] == u'STASI™'
assert ns['copyright'] == u'%s, Wolfgang Schäuble & G\'Beckstein' % \

View File

@@ -14,7 +14,7 @@ import zipfile
from sphinx.theming import Theme, ThemeError
from util import with_app, raises
from util import with_app, raises, TestApp
@with_app(confoverrides={'html_theme': 'ziptheme',

View File

@@ -72,13 +72,13 @@ def test_get_catalogs_for_xx(dir):
(dir / 'loc1' / 'xx' / 'LC_ALL').makedirs()
(dir / 'loc1' / 'xx' / 'LC_ALL' / 'test7.po').write_text('#')
catalogs = i18n.get_catalogs([dir / 'loc1'], 'xx', force_all=False)
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'xx', force_all=False)
domains = set(c.domain for c in catalogs)
assert domains == set([
'test1',
'test2',
path.normpath('sub/test4'),
path.normpath('sub/test5'),
'sub/test4',
'sub/test5',
])
@@ -89,22 +89,22 @@ def test_get_catalogs_for_en(dir):
(dir / 'loc1' / 'en' / 'LC_MESSAGES').makedirs()
(dir / 'loc1' / 'en' / 'LC_MESSAGES' / 'en_dom.po').write_text('#')
catalogs = i18n.get_catalogs([dir / 'loc1'], 'en', force_all=False)
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'en', force_all=False)
domains = set(c.domain for c in catalogs)
assert domains == set(['en_dom'])
@with_tempdir
def test_get_catalogs_with_non_existent_locale(dir):
catalogs = i18n.get_catalogs([dir / 'loc1'], 'xx')
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'xx')
assert not catalogs
catalogs = i18n.get_catalogs([dir / 'loc1'], None)
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], None)
assert not catalogs
def test_get_catalogs_with_non_existent_locale_dirs():
catalogs = i18n.get_catalogs(['dummy'], 'xx')
catalogs = i18n.find_catalog_source_files(['dummy'], 'xx')
assert not catalogs
@@ -123,16 +123,16 @@ def test_get_catalogs_for_xx_without_outdated(dir):
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test5.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test5.mo').write_text('#')
catalogs = i18n.get_catalogs([dir / 'loc1'], 'xx', force_all=False)
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'xx', force_all=False)
assert not catalogs
catalogs = i18n.get_catalogs([dir / 'loc1'], 'xx', force_all=True)
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'xx', force_all=True)
domains = set(c.domain for c in catalogs)
assert domains == set([
'test1',
'test2',
path.normpath('sub/test4'),
path.normpath('sub/test5'),
'sub/test4',
'sub/test5',
])
@@ -144,7 +144,7 @@ def test_get_catalogs_from_multiple_locale_dirs(dir):
(dir / 'loc2' / 'xx' / 'LC_MESSAGES' / 'test1.po').write_text('#')
(dir / 'loc2' / 'xx' / 'LC_MESSAGES' / 'test2.po').write_text('#')
catalogs = i18n.get_catalogs([dir / 'loc1', dir / 'loc2'], 'xx')
catalogs = i18n.find_catalog_source_files([dir / 'loc1', dir / 'loc2'], 'xx')
domains = sorted(c.domain for c in catalogs)
assert domains == ['test1', 'test1', 'test2']
@@ -158,6 +158,6 @@ def test_get_catalogs_with_compact(dir):
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test3.po').write_text('#')
(dir / 'loc1' / 'xx' / 'LC_MESSAGES' / 'sub' / 'test4.po').write_text('#')
catalogs = i18n.get_catalogs([dir / 'loc1'], 'xx', gettext_compact=True)
catalogs = i18n.find_catalog_source_files([dir / 'loc1'], 'xx', gettext_compact=True)
domains = set(c.domain for c in catalogs)
assert domains == set(['test1', 'test2', 'sub'])