From c705e3ae1f4d614ab7a806c0fa3f9484bf98a789 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 24 Jul 2010 11:35:29 +0100 Subject: [PATCH 001/207] Trunk is now 1.1pre. --- CHANGES | 4 ++++ sphinx/__init__.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 8465dae09..1bb0a276e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +Release 1.1 (in development) +============================ + + Release 1.0.1 (in development) ============================== diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 8c1ebed56..31c61a86a 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -12,8 +12,8 @@ import sys from os import path -__version__ = '1.0+' -__released__ = '1.0' # used when Sphinx builds its own docs +__version__ = '1.1pre' +__released__ = '1.1 (hg)' # used when Sphinx builds its own docs package_dir = path.abspath(path.dirname(__file__)) From 12ecec3f5753881d7bd0509f057dd97353ae38cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Thu, 29 Apr 2010 18:06:22 +0200 Subject: [PATCH 002/207] Show python 3.x incompatibilities which cannot be trivially fixed --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7057a7152..682f03666 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PYTHON ?= python +PYTHON ?= python -3 export PYTHONPATH = $(shell echo "$$PYTHONPATH"):./sphinx From e97122236d9e908ae6b9806858ad09c1d70cbcc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Thu, 29 Apr 2010 18:08:44 +0200 Subject: [PATCH 003/207] Replace .has_key() calls with the in-operator --- sphinx/writers/latex.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 5674b388c..360cf40c9 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -314,7 +314,7 @@ class LaTeXTranslator(nodes.NodeVisitor): # ... and all others are the appendices self.body.append(u'\n\\appendix\n') self.first_document = -1 - if node.has_key('docname'): + if 'docname' in node: self.body.append(self.hypertarget(':doc')) # "- 1" because the level is increased before the title is visited self.sectionlevel = self.top_sectionlevel - 1 @@ -694,7 +694,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.table.rowcount += 1 def visit_entry(self, node): - if node.has_key('morerows') or node.has_key('morecols'): + if 'morerows' in node or 'morecols' in node: raise UnsupportedError('%s:%s: column or row spanning cells are ' 'not yet implemented.' % (self.curfilestack[-1], node.line or '')) @@ -751,7 +751,7 @@ class LaTeXTranslator(nodes.NodeVisitor): def visit_term(self, node): ctx = '}] \\leavevmode' - if node.has_key('ids') and node['ids']: + if node.get('ids'): ctx += self.hypertarget(node['ids'][0]) self.body.append('\\item[{') self.context.append(ctx) @@ -833,20 +833,20 @@ class LaTeXTranslator(nodes.NodeVisitor): post = [] include_graphics_options = [] is_inline = self.is_inline(node) - if attrs.has_key('scale'): + if 'scale' in attrs: # Could also be done with ``scale`` option to # ``\includegraphics``; doing it this way for consistency. pre.append('\\scalebox{%f}{' % (attrs['scale'] / 100.0,)) post.append('}') - if attrs.has_key('width'): + if 'width' in attrs: w = self.latex_image_length(attrs['width']) if w: include_graphics_options.append('width=%s' % w) - if attrs.has_key('height'): + if 'height' in attrs: h = self.latex_image_length(attrs['height']) if h: include_graphics_options.append('height=%s' % h) - if attrs.has_key('align'): + if 'align' in attrs: align_prepost = { # By default latex aligns the top of an image. (1, 'top'): ('', ''), @@ -887,13 +887,13 @@ class LaTeXTranslator(nodes.NodeVisitor): pass def visit_figure(self, node): - if node.has_key('width') and node.get('align', '') in ('left', 'right'): + if 'width' in node and node.get('align', '') in ('left', 'right'): self.body.append('\\begin{wrapfigure}{%s}{%s}\n\\centering' % (node['align'] == 'right' and 'r' or 'l', node['width'])) self.context.append('\\end{wrapfigure}\n') else: - if (not node.attributes.has_key('align') or + if (not 'align' in node.attributes or node.attributes['align'] == 'center'): # centering does not add vertical space like center. align = '\n\\centering' @@ -1154,7 +1154,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.no_contractions -= 1 if self.in_title: self.body.append(r'\texttt{%s}' % content) - elif node.has_key('role') and node['role'] == 'samp': + elif node.get('role') == 'samp': self.body.append(r'\samp{%s}' % content) else: self.body.append(r'\code{%s}' % content) @@ -1183,10 +1183,10 @@ class LaTeXTranslator(nodes.NodeVisitor): code = self.verbatim.rstrip('\n') lang = self.hlsettingstack[-1][0] linenos = code.count('\n') >= self.hlsettingstack[-1][1] - 1 - if node.has_key('language'): + if 'language' in node: # code-block directives lang = node['language'] - if node.has_key('linenos'): + if 'linenos' in node: linenos = node['linenos'] hlcode = self.highlighter.highlight_block(code, lang, linenos) # workaround for Unicode issue From 4adbc983503072918b058d6bfa6bca4fd64b86aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Thu, 29 Apr 2010 19:42:17 +0200 Subject: [PATCH 004/207] Removed map(None, ...) usage --- sphinx/writers/text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index 98528d5ba..b28b23792 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -390,7 +390,7 @@ class TextTranslator(nodes.NodeVisitor): self.add_text(''.join(out) + '\n') def writerow(row): - lines = map(None, *row) + lines = zip(*row) for line in lines: out = ['|'] for i, cell in enumerate(line): From 21376f21e7cee76761fccef6874c88c1b3f79e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Thu, 29 Apr 2010 20:34:08 +0200 Subject: [PATCH 005/207] Don't use execfile() anymore --- sphinx/config.py | 6 +++++- tests/test_quickstart.py | 12 ++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sphinx/config.py b/sphinx/config.py index 12c2a04ba..f76d330ac 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -165,7 +165,11 @@ class Config(object): try: try: os.chdir(dirname) - execfile(config['__file__'], config) + try: + f = open(config_file, 'U') + exec f in config + finally: + f.close() except SyntaxError, err: raise ConfigError('There is a syntax error in your ' 'configuration file: ' + str(err)) diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index cb40d27cf..34c54f95a 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -85,7 +85,11 @@ def test_quickstart_defaults(tempdir): conffile = tempdir / 'conf.py' assert conffile.isfile() ns = {} - execfile(conffile, ns) + try: + f = open(conffile, 'U') + exec f in ns + finally: + f.close() assert ns['extensions'] == [] assert ns['templates_path'] == ['_templates'] assert ns['source_suffix'] == '.rst' @@ -138,7 +142,11 @@ def test_quickstart_all_answers(tempdir): conffile = tempdir / 'source' / 'conf.py' assert conffile.isfile() ns = {} - execfile(conffile, ns) + try: + f = open(conffile, 'U') + exec f in ns + finally: + f.close() assert ns['extensions'] == ['sphinx.ext.autodoc', 'sphinx.ext.doctest'] assert ns['templates_path'] == ['.templates'] assert ns['source_suffix'] == '.txt' From 47557af776de7772da88a5d3ceaad62bf9edaef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Fri, 30 Apr 2010 12:32:42 +0200 Subject: [PATCH 006/207] Make sphinx.domains.cpp.DefExpr unhashable --- sphinx/domains/cpp.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 4dac89253..90c3533ef 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -132,6 +132,8 @@ class DefExpr(object): def __ne__(self, other): return not self.__eq__(other) + __hash__ = None + def clone(self): """Close a definition expression node""" return deepcopy(self) From f6bf9b13ff40ae8dfbc9afe19db0da3fcbac8f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 1 May 2010 19:17:52 +0200 Subject: [PATCH 007/207] Fixed issue #1 --- sphinx/environment.py | 3 ++- sphinx/pycode/pgen2/tokenize.py | 4 +++- utils/reindent.py | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/sphinx/environment.py b/sphinx/environment.py index 5edcb4d90..fa8460cb3 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -1488,8 +1488,9 @@ class BuildEnvironment: i += 1 # group the entries by letter - def keyfunc2((k, v), letters=string.ascii_uppercase + '_'): + def keyfunc2(item, letters=string.ascii_uppercase + '_'): # hack: mutating the subitems dicts to a list in the keyfunc + k, v = item v[1] = sorted((si, se) for (si, (se, void)) in v[1].iteritems()) # now calculate the key letter = k[0].upper() diff --git a/sphinx/pycode/pgen2/tokenize.py b/sphinx/pycode/pgen2/tokenize.py index 4489db898..7ad9f012c 100644 --- a/sphinx/pycode/pgen2/tokenize.py +++ b/sphinx/pycode/pgen2/tokenize.py @@ -143,7 +143,9 @@ class TokenError(Exception): pass class StopTokenizing(Exception): pass -def printtoken(type, token, (srow, scol), (erow, ecol), line): # for testing +def printtoken(type, token, scell, ecell, line): # for testing + srow, scol = scell + erow, ecol = ecell print "%d,%d-%d,%d:\t%s\t%s" % \ (srow, scol, erow, ecol, tok_name[type], repr(token)) diff --git a/utils/reindent.py b/utils/reindent.py index c499f671e..bcb6b4343 100755 --- a/utils/reindent.py +++ b/utils/reindent.py @@ -244,12 +244,13 @@ class Reindenter: return line # Line-eater for tokenize. - def tokeneater(self, type, token, (sline, scol), end, line, + def tokeneater(self, type, token, scell, end, line, INDENT=tokenize.INDENT, DEDENT=tokenize.DEDENT, NEWLINE=tokenize.NEWLINE, COMMENT=tokenize.COMMENT, NL=tokenize.NL): + sline, scol = scell if type == NEWLINE: # A program statement, or ENDMARKER, will eventually follow, From eef0b0821d01c3eb4d26eb3a4f8a185b29df8c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 1 May 2010 19:18:31 +0200 Subject: [PATCH 008/207] Make sphinx.pycode.nodes.BaseNode unhashable --- sphinx/pycode/nodes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sphinx/pycode/nodes.py b/sphinx/pycode/nodes.py index e71846779..fc6eb93aa 100644 --- a/sphinx/pycode/nodes.py +++ b/sphinx/pycode/nodes.py @@ -29,6 +29,8 @@ class BaseNode(object): return NotImplemented return not self._eq(other) + __hash__ = None + def get_prev_sibling(self): """Return previous child in parent's children, or None.""" if self.parent is None: From 6651f67602a51795447fee8f6f8ac517f26a8f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 1 May 2010 19:19:24 +0200 Subject: [PATCH 009/207] Removed pre-2.3 workaround for booleans --- tests/path.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/path.py b/tests/path.py index ceb895f50..20deb0489 100644 --- a/tests/path.py +++ b/tests/path.py @@ -56,12 +56,6 @@ try: except AttributeError: pass -# Pre-2.3 workaround for booleans -try: - True, False -except NameError: - True, False = 1, 0 - # Pre-2.3 workaround for basestring. try: basestring From 4391e63b07c02d317617fc061256fd77eb0cb9b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 1 May 2010 20:26:05 +0200 Subject: [PATCH 010/207] Move open() calls out of the try block --- sphinx/config.py | 2 +- tests/test_quickstart.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/config.py b/sphinx/config.py index f76d330ac..c22a5ee74 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -165,8 +165,8 @@ class Config(object): try: try: os.chdir(dirname) + f = open(config_file, 'U') try: - f = open(config_file, 'U') exec f in config finally: f.close() diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index 34c54f95a..71ca95a4d 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -85,8 +85,8 @@ def test_quickstart_defaults(tempdir): conffile = tempdir / 'conf.py' assert conffile.isfile() ns = {} + f = open(conffile, 'U') try: - f = open(conffile, 'U') exec f in ns finally: f.close() @@ -142,8 +142,8 @@ def test_quickstart_all_answers(tempdir): conffile = tempdir / 'source' / 'conf.py' assert conffile.isfile() ns = {} + f = open(conffile, 'U') try: - f = open(conffile, 'U') exec f in ns finally: f.close() From df236468781b3ef8dc33f31896fe64b7958587a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Thu, 6 May 2010 16:05:37 +0200 Subject: [PATCH 011/207] Added a file containing the changes made during GSoC. --- CHANGES.DasIch | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 CHANGES.DasIch diff --git a/CHANGES.DasIch b/CHANGES.DasIch new file mode 100644 index 000000000..856a5d87b --- /dev/null +++ b/CHANGES.DasIch @@ -0,0 +1,19 @@ +Changes +======= + +This file contains changes made by Daniel Neuhäuser, during the Google Summer +of Code 2010, to port Sphinx to Python 3.x. Changes are ordered descending by +date. + +May 1: - Removed deprecated tuple parameter unpacking. + - Removed a pre-2.3 workaround for booleans because this creates a + deprecation warning for 3.x, in which you can't assign values to + booleans. + - Moved :func:`open()` calls out of the try-blocks, which fixes revision + c577c25bd44b. + +April 30: Made :cls:`sphinx.domains.cpp.DefExpr` unhashable as described by the + documentation because classes in 3.x don't inherit ``__hash__`` if + they implement ``__eq__``. + +April 29: Removed several deprecated function/method calls. From 89cb0714b1041b77ceae5a777a18dd780c032bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 8 May 2010 20:34:19 +0200 Subject: [PATCH 012/207] Removed ez_setup which doesn't work with python3 and added use_2to3 for distribute --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 183fcceb1..2494851f5 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ A development egg can be found `here requires = ['Pygments>=0.8', 'Jinja2>=2.2', 'docutils>=0.5'] if sys.version_info < (2, 4): - print 'ERROR: Sphinx requires at least Python 2.4 to run.' + print('ERROR: Sphinx requires at least Python 2.4 to run.') sys.exit(1) if sys.version_info < (2, 5): @@ -198,4 +198,5 @@ setup( }, install_requires=requires, cmdclass=cmdclass, + use_2to3=True, ) From c09c74c3dfbbf166d60c80ce6fcb0a85f4df63a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 8 May 2010 20:53:49 +0200 Subject: [PATCH 013/207] Check for unicode before trying to decode input from raw_input. Also use codecs.open when writing non-binary files. sphinx-quickstart now works. --- sphinx/quickstart.py | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 884caca75..5820996f1 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -11,6 +11,7 @@ import sys, os, time from os import path +from codecs import open TERM_ENCODING = getattr(sys.stdin, 'encoding', None) @@ -659,17 +660,20 @@ def do_prompt(d, key, text, default=None, validator=nonempty): x = raw_input(prompt) if default and not x: x = default - 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') + # in 3.x raw_input returns a unicode string, those have no decode + # method + if not isinstance(x, unicode): + 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') try: x = validator(x) except ValidationError, err: @@ -834,28 +838,28 @@ directly.''' if d['ext_intersphinx']: conf_text += INTERSPHINX_CONFIG - f = open(path.join(srcdir, 'conf.py'), 'w') - f.write(conf_text.encode('utf-8')) + f = open(path.join(srcdir, 'conf.py'), 'w', encoding='utf-8') + f.write(conf_text) f.close() masterfile = path.join(srcdir, d['master'] + d['suffix']) - f = open(masterfile, 'w') - f.write((MASTER_FILE % d).encode('utf-8')) + f = open(masterfile, 'w', encoding='utf-8') + f.write(MASTER_FILE % d) f.close() if d['makefile']: d['rsrcdir'] = d['sep'] and 'source' or '.' d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build' # use binary mode, to avoid writing \r\n on Windows - f = open(path.join(d['path'], 'Makefile'), 'wb') - f.write((MAKEFILE % d).encode('utf-8')) + f = open(path.join(d['path'], 'Makefile'), 'wb', encoding='utf-8') + f.write(MAKEFILE % d) f.close() if d['batchfile']: d['rsrcdir'] = d['sep'] and 'source' or '.' d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build' - f = open(path.join(d['path'], 'make.bat'), 'w') - f.write((BATCHFILE % d).encode('utf-8')) + f = open(path.join(d['path'], 'make.bat'), 'w', encoding='utf-8') + f.write(BATCHFILE % d) f.close() print From 66244b8432b9a594848d29e6d43f354e643f7706 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:03:42 +0200 Subject: [PATCH 014/207] Use codecs.open(). --- sphinx/quickstart.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 5820996f1..fe2b43a33 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -660,9 +660,8 @@ def do_prompt(d, key, text, default=None, validator=nonempty): x = raw_input(prompt) if default and not x: x = default - # in 3.x raw_input returns a unicode string, those have no decode - # method if not isinstance(x, unicode): + # 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) @@ -838,12 +837,12 @@ directly.''' if d['ext_intersphinx']: conf_text += INTERSPHINX_CONFIG - f = open(path.join(srcdir, 'conf.py'), 'w', encoding='utf-8') + f = codecs.open(path.join(srcdir, 'conf.py'), 'w', encoding='utf-8') f.write(conf_text) f.close() masterfile = path.join(srcdir, d['master'] + d['suffix']) - f = open(masterfile, 'w', encoding='utf-8') + f = codecs.open(masterfile, 'w', encoding='utf-8') f.write(MASTER_FILE % d) f.close() @@ -851,14 +850,14 @@ directly.''' d['rsrcdir'] = d['sep'] and 'source' or '.' d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build' # use binary mode, to avoid writing \r\n on Windows - f = open(path.join(d['path'], 'Makefile'), 'wb', encoding='utf-8') + f = codecs.open(path.join(d['path'], 'Makefile'), 'wb', encoding='utf-8') f.write(MAKEFILE % d) f.close() if d['batchfile']: d['rsrcdir'] = d['sep'] and 'source' or '.' d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build' - f = open(path.join(d['path'], 'make.bat'), 'w', encoding='utf-8') + f = codecs.open(path.join(d['path'], 'make.bat'), 'w', encoding='utf-8') f.write(BATCHFILE % d) f.close() From 9c29a8cd9c7cd42a84e4243fa8cc20631c466c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 8 May 2010 21:47:52 +0200 Subject: [PATCH 015/207] Encode even bytestrings containing ascii tests, they are unicode in python3 --- sphinx/util/__init__.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index 8d1298cd3..c1e8d25c9 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -168,11 +168,14 @@ def save_traceback(): """ exc = traceback.format_exc() fd, path = tempfile.mkstemp('.log', 'sphinx-err-') - os.write(fd, '# Sphinx version: %s\n' % sphinx.__version__) - os.write(fd, '# Docutils version: %s %s\n' % (docutils.__version__, - docutils.__version_details__)) - os.write(fd, '# Jinja2 version: %s\n' % jinja2.__version__) - os.write(fd, exc) + os.write(fd, + (('# Sphinx version: %s\n' + '# Docutils version: %s %s\n' + '# Jinja2 version: %s\n') % (sphinx.__version__, + docutils.__version__, + docutils.__version_details__, + jinja2.__version__)).encode('utf-8')) + os.write(fd, exc.encode('utf-8')) os.close(fd) return path From b81d428b89137a3f763bc2fd95de9a55bcc2e29a Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:08:00 +0200 Subject: [PATCH 016/207] Take string constant out of function. --- sphinx/util/__init__.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index c1e8d25c9..2ef420ed1 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -162,19 +162,22 @@ def copy_static_entry(source, targetdir, builder, context={}, shutil.copytree(source, target) +_DEBUG_HEADER = '''\ +# Sphinx version: %s +# Docutils version: %s %s +# Jinja2 version: %s +''' + def save_traceback(): """ Save the current exception's traceback in a temporary file. """ exc = traceback.format_exc() fd, path = tempfile.mkstemp('.log', 'sphinx-err-') - os.write(fd, - (('# Sphinx version: %s\n' - '# Docutils version: %s %s\n' - '# Jinja2 version: %s\n') % (sphinx.__version__, - docutils.__version__, - docutils.__version_details__, - jinja2.__version__)).encode('utf-8')) + os.write(fd, (_DEBUG_HEADER % + (sphinx.__version__, + docutils.__version__, docutils.__version_details__, + jinja2.__version__)).encode('utf-8')) os.write(fd, exc.encode('utf-8')) os.close(fd) return path From 25b16f89e08be50c08fcc0f29ade8172d33cb347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 8 May 2010 22:00:15 +0200 Subject: [PATCH 017/207] Use code objects for exec statements instead of files --- sphinx/config.py | 3 ++- tests/test_quickstart.py | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/sphinx/config.py b/sphinx/config.py index c22a5ee74..2ec769871 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -167,9 +167,10 @@ class Config(object): os.chdir(dirname) f = open(config_file, 'U') try: - exec f in config + code = compile(f.read(), config_file, 'exec') finally: f.close() + exec code in config except SyntaxError, err: raise ConfigError('There is a syntax error in your ' 'configuration file: ' + str(err)) diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index 71ca95a4d..8acff5884 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -87,9 +87,10 @@ def test_quickstart_defaults(tempdir): ns = {} f = open(conffile, 'U') try: - exec f in ns + code = compile(f.read(), conffile, 'exec') finally: f.close() + exec code in ns assert ns['extensions'] == [] assert ns['templates_path'] == ['_templates'] assert ns['source_suffix'] == '.rst' @@ -144,9 +145,10 @@ def test_quickstart_all_answers(tempdir): ns = {} f = open(conffile, 'U') try: - exec f in ns + code = compile(f.read(), conffile, 'exec') finally: f.close() + exec code in ns assert ns['extensions'] == ['sphinx.ext.autodoc', 'sphinx.ext.doctest'] assert ns['templates_path'] == ['.templates'] assert ns['source_suffix'] == '.txt' From 8e9709290f5b38e108b975abc3bbc399950bbce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 8 May 2010 22:28:28 +0200 Subject: [PATCH 018/207] Removing unnecessary ez_setup.py --- ez_setup.py | 276 ---------------------------------------------------- 1 file changed, 276 deletions(-) delete mode 100644 ez_setup.py diff --git a/ez_setup.py b/ez_setup.py deleted file mode 100644 index d24e845e5..000000000 --- a/ez_setup.py +++ /dev/null @@ -1,276 +0,0 @@ -#!python -"""Bootstrap setuptools installation - -If you want to use setuptools in your package's setup.py, just include this -file in the same directory with it, and add this to the top of your setup.py:: - - from ez_setup import use_setuptools - use_setuptools() - -If you want to require a specific version of setuptools, set a download -mirror, or use an alternate download directory, you can do so by supplying -the appropriate options to ``use_setuptools()``. - -This file can also be run as a script to install or upgrade setuptools. -""" -import sys -DEFAULT_VERSION = "0.6c9" -DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] - -md5_data = { - 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', - 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', - 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', - 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', - 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', - 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', - 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', - 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', - 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', - 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', - 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', - 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', - 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', - 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', - 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', - 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', - 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', - 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', - 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', - 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', - 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', - 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', - 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', - 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', - 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', - 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', - 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', - 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', - 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', - 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', - 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03', - 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a', - 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6', - 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', -} - -import sys, os -try: from hashlib import md5 -except ImportError: from md5 import md5 - -def _validate_md5(egg_name, data): - if egg_name in md5_data: - digest = md5(data).hexdigest() - if digest != md5_data[egg_name]: - print >>sys.stderr, ( - "md5 validation of %s failed! (Possible download problem?)" - % egg_name - ) - sys.exit(2) - return data - -def use_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, - download_delay=15 -): - """Automatically find/download setuptools and make it available on sys.path - - `version` should be a valid setuptools version number that is available - as an egg for download under the `download_base` URL (which should end with - a '/'). `to_dir` is the directory where setuptools will be downloaded, if - it is not already available. If `download_delay` is specified, it should - be the number of seconds that will be paused before initiating a download, - should one be required. If an older version of setuptools is installed, - this routine will print a message to ``sys.stderr`` and raise SystemExit in - an attempt to abort the calling script. - """ - was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules - def do_download(): - egg = download_setuptools(version, download_base, to_dir, download_delay) - sys.path.insert(0, egg) - import setuptools; setuptools.bootstrap_install_from = egg - try: - import pkg_resources - except ImportError: - return do_download() - try: - pkg_resources.require("setuptools>="+version); return - except pkg_resources.VersionConflict, e: - if was_imported: - print >>sys.stderr, ( - "The required version of setuptools (>=%s) is not available, and\n" - "can't be installed while this script is running. Please install\n" - " a more recent version first, using 'easy_install -U setuptools'." - "\n\n(Currently using %r)" - ) % (version, e.args[0]) - sys.exit(2) - else: - del pkg_resources, sys.modules['pkg_resources'] # reload ok - return do_download() - except pkg_resources.DistributionNotFound: - return do_download() - -def download_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, - delay = 15 -): - """Download setuptools from a specified location and return its filename - - `version` should be a valid setuptools version number that is available - as an egg for download under the `download_base` URL (which should end - with a '/'). `to_dir` is the directory where the egg will be downloaded. - `delay` is the number of seconds to pause before an actual download attempt. - """ - import urllib2, shutil - egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) - url = download_base + egg_name - saveto = os.path.join(to_dir, egg_name) - src = dst = None - if not os.path.exists(saveto): # Avoid repeated downloads - try: - from distutils import log - if delay: - log.warn(""" ---------------------------------------------------------------------------- -This script requires setuptools version %s to run (even to display -help). I will attempt to download it for you (from -%s), but -you may need to enable firewall access for this script first. -I will start the download in %d seconds. - -(Note: if this machine does not have network access, please obtain the file - - %s - -and place it in this directory before rerunning this script.) ----------------------------------------------------------------------------""", - version, download_base, delay, url - ); from time import sleep; sleep(delay) - log.warn("Downloading %s", url) - src = urllib2.urlopen(url) - # Read/write all in one block, so we don't create a corrupt file - # if the download is interrupted. - data = _validate_md5(egg_name, src.read()) - dst = open(saveto,"wb"); dst.write(data) - finally: - if src: src.close() - if dst: dst.close() - return os.path.realpath(saveto) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def main(argv, version=DEFAULT_VERSION): - """Install or upgrade setuptools and EasyInstall""" - try: - import setuptools - except ImportError: - egg = None - try: - egg = download_setuptools(version, delay=0) - sys.path.insert(0,egg) - from setuptools.command.easy_install import main - return main(list(argv)+[egg]) # we're done here - finally: - if egg and os.path.exists(egg): - os.unlink(egg) - else: - if setuptools.__version__ == '0.0.1': - print >>sys.stderr, ( - "You have an obsolete version of setuptools installed. Please\n" - "remove it from your system entirely before rerunning this script." - ) - sys.exit(2) - - req = "setuptools>="+version - import pkg_resources - try: - pkg_resources.require(req) - except pkg_resources.VersionConflict: - try: - from setuptools.command.easy_install import main - except ImportError: - from easy_install import main - main(list(argv)+[download_setuptools(delay=0)]) - sys.exit(0) # try to force an exit - else: - if argv: - from setuptools.command.easy_install import main - main(argv) - else: - print "Setuptools version",version,"or greater has been installed." - print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' - -def update_md5(filenames): - """Update our built-in md5 registry""" - - import re - - for name in filenames: - base = os.path.basename(name) - f = open(name,'rb') - md5_data[base] = md5(f.read()).hexdigest() - f.close() - - data = [" %r: %r,\n" % it for it in md5_data.items()] - data.sort() - repl = "".join(data) - - import inspect - srcfile = inspect.getsourcefile(sys.modules[__name__]) - f = open(srcfile, 'rb'); src = f.read(); f.close() - - match = re.search("\nmd5_data = {\n([^}]+)}", src) - if not match: - print >>sys.stderr, "Internal error!" - sys.exit(2) - - src = src[:match.start(1)] + repl + src[match.end(1):] - f = open(srcfile,'w') - f.write(src) - f.close() - - -if __name__=='__main__': - if len(sys.argv)>2 and sys.argv[1]=='--md5update': - update_md5(sys.argv[2:]) - else: - main(sys.argv[1:]) - - - - - - From 4f13ff1ab7424d79dd9ed708315c6cc1d1a2c566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 8 May 2010 22:33:36 +0200 Subject: [PATCH 019/207] Added a distribute_setup to replace ez_setup --- distribute_setup.py | 481 ++++++++++++++++++++++++++++++++++++++++++++ setup.py | 4 +- 2 files changed, 483 insertions(+), 2 deletions(-) create mode 100644 distribute_setup.py diff --git a/distribute_setup.py b/distribute_setup.py new file mode 100644 index 000000000..4f7bd08c0 --- /dev/null +++ b/distribute_setup.py @@ -0,0 +1,481 @@ +#!python +"""Bootstrap distribute installation + +If you want to use setuptools in your package's setup.py, just include this +file in the same directory with it, and add this to the top of your setup.py:: + + from distribute_setup import use_setuptools + use_setuptools() + +If you want to require a specific version of setuptools, set a download +mirror, or use an alternate download directory, you can do so by supplying +the appropriate options to ``use_setuptools()``. + +This file can also be run as a script to install or upgrade setuptools. +""" +import os +import sys +import time +import fnmatch +import tempfile +import tarfile +from distutils import log + +try: + from site import USER_SITE +except ImportError: + USER_SITE = None + +try: + import subprocess + + def _python_cmd(*args): + args = (sys.executable,) + args + return subprocess.call(args) == 0 + +except ImportError: + # will be used for python 2.3 + def _python_cmd(*args): + args = (sys.executable,) + args + # quoting arguments if windows + if sys.platform == 'win32': + def quote(arg): + if ' ' in arg: + return '"%s"' % arg + return arg + args = [quote(arg) for arg in args] + return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 + +DEFAULT_VERSION = "0.6.12" +DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" +SETUPTOOLS_FAKED_VERSION = "0.6c11" + +SETUPTOOLS_PKG_INFO = """\ +Metadata-Version: 1.0 +Name: setuptools +Version: %s +Summary: xxxx +Home-page: xxx +Author: xxx +Author-email: xxx +License: xxx +Description: xxx +""" % SETUPTOOLS_FAKED_VERSION + + +def _install(tarball): + # extracting the tarball + tmpdir = tempfile.mkdtemp() + log.warn('Extracting in %s', tmpdir) + old_wd = os.getcwd() + try: + os.chdir(tmpdir) + tar = tarfile.open(tarball) + _extractall(tar) + tar.close() + + # going in the directory + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) + os.chdir(subdir) + log.warn('Now working in %s', subdir) + + # installing + log.warn('Installing Distribute') + if not _python_cmd('setup.py', 'install'): + log.warn('Something went wrong during the installation.') + log.warn('See the error message above.') + finally: + os.chdir(old_wd) + + +def _build_egg(egg, tarball, to_dir): + # extracting the tarball + tmpdir = tempfile.mkdtemp() + log.warn('Extracting in %s', tmpdir) + old_wd = os.getcwd() + try: + os.chdir(tmpdir) + tar = tarfile.open(tarball) + _extractall(tar) + tar.close() + + # going in the directory + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) + os.chdir(subdir) + log.warn('Now working in %s', subdir) + + # building an egg + log.warn('Building a Distribute egg in %s', to_dir) + _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) + + finally: + os.chdir(old_wd) + # returning the result + log.warn(egg) + if not os.path.exists(egg): + raise IOError('Could not build the egg.') + + +def _do_download(version, download_base, to_dir, download_delay): + egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' + % (version, sys.version_info[0], sys.version_info[1])) + if not os.path.exists(egg): + tarball = download_setuptools(version, download_base, + to_dir, download_delay) + _build_egg(egg, tarball, to_dir) + sys.path.insert(0, egg) + import setuptools + setuptools.bootstrap_install_from = egg + + +def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, + to_dir=os.curdir, download_delay=15, no_fake=True): + # making sure we use the absolute path + to_dir = os.path.abspath(to_dir) + was_imported = 'pkg_resources' in sys.modules or \ + 'setuptools' in sys.modules + try: + try: + import pkg_resources + if not hasattr(pkg_resources, '_distribute'): + if not no_fake: + _fake_setuptools() + raise ImportError + except ImportError: + return _do_download(version, download_base, to_dir, download_delay) + try: + pkg_resources.require("distribute>="+version) + return + except pkg_resources.VersionConflict: + e = sys.exc_info()[1] + if was_imported: + sys.stderr.write( + "The required version of distribute (>=%s) is not available,\n" + "and can't be installed while this script is running. Please\n" + "install a more recent version first, using\n" + "'easy_install -U distribute'." + "\n\n(Currently using %r)\n" % (version, e.args[0])) + sys.exit(2) + else: + del pkg_resources, sys.modules['pkg_resources'] # reload ok + return _do_download(version, download_base, to_dir, + download_delay) + except pkg_resources.DistributionNotFound: + return _do_download(version, download_base, to_dir, + download_delay) + finally: + if not no_fake: + _create_fake_setuptools_pkg_info(to_dir) + +def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, + to_dir=os.curdir, delay=15): + """Download distribute from a specified location and return its filename + + `version` should be a valid distribute version number that is available + as an egg for download under the `download_base` URL (which should end + with a '/'). `to_dir` is the directory where the egg will be downloaded. + `delay` is the number of seconds to pause before an actual download + attempt. + """ + # making sure we use the absolute path + to_dir = os.path.abspath(to_dir) + try: + from urllib.request import urlopen + except ImportError: + from urllib2 import urlopen + tgz_name = "distribute-%s.tar.gz" % version + url = download_base + tgz_name + saveto = os.path.join(to_dir, tgz_name) + src = dst = None + if not os.path.exists(saveto): # Avoid repeated downloads + try: + log.warn("Downloading %s", url) + src = urlopen(url) + # Read/write all in one block, so we don't create a corrupt file + # if the download is interrupted. + data = src.read() + dst = open(saveto, "wb") + dst.write(data) + finally: + if src: + src.close() + if dst: + dst.close() + return os.path.realpath(saveto) + +def _no_sandbox(function): + def __no_sandbox(*args, **kw): + try: + from setuptools.sandbox import DirectorySandbox + if not hasattr(DirectorySandbox, '_old'): + def violation(*args): + pass + DirectorySandbox._old = DirectorySandbox._violation + DirectorySandbox._violation = violation + patched = True + else: + patched = False + except ImportError: + patched = False + + try: + return function(*args, **kw) + finally: + if patched: + DirectorySandbox._violation = DirectorySandbox._old + del DirectorySandbox._old + + return __no_sandbox + +@_no_sandbox +def _patch_file(path, content): + """Will backup the file then patch it""" + existing_content = open(path).read() + if existing_content == content: + # already patched + log.warn('Already patched.') + return False + log.warn('Patching...') + _rename_path(path) + f = open(path, 'w') + try: + f.write(content) + finally: + f.close() + return True + + +def _same_content(path, content): + return open(path).read() == content + +def _rename_path(path): + new_name = path + '.OLD.%s' % time.time() + log.warn('Renaming %s into %s', path, new_name) + os.rename(path, new_name) + return new_name + +@_no_sandbox +def _remove_flat_installation(placeholder): + if not os.path.isdir(placeholder): + log.warn('Unkown installation at %s', placeholder) + return False + found = False + for file in os.listdir(placeholder): + if fnmatch.fnmatch(file, 'setuptools*.egg-info'): + found = True + break + if not found: + log.warn('Could not locate setuptools*.egg-info') + return + + log.warn('Removing elements out of the way...') + pkg_info = os.path.join(placeholder, file) + if os.path.isdir(pkg_info): + patched = _patch_egg_dir(pkg_info) + else: + patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) + + if not patched: + log.warn('%s already patched.', pkg_info) + return False + # now let's move the files out of the way + for element in ('setuptools', 'pkg_resources.py', 'site.py'): + element = os.path.join(placeholder, element) + if os.path.exists(element): + _rename_path(element) + else: + log.warn('Could not find the %s element of the ' + 'Setuptools distribution', element) + return True + + +def _after_install(dist): + log.warn('After install bootstrap.') + placeholder = dist.get_command_obj('install').install_purelib + _create_fake_setuptools_pkg_info(placeholder) + +@_no_sandbox +def _create_fake_setuptools_pkg_info(placeholder): + if not placeholder or not os.path.exists(placeholder): + log.warn('Could not find the install location') + return + pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) + setuptools_file = 'setuptools-%s-py%s.egg-info' % \ + (SETUPTOOLS_FAKED_VERSION, pyver) + pkg_info = os.path.join(placeholder, setuptools_file) + if os.path.exists(pkg_info): + log.warn('%s already exists', pkg_info) + return + + log.warn('Creating %s', pkg_info) + f = open(pkg_info, 'w') + try: + f.write(SETUPTOOLS_PKG_INFO) + finally: + f.close() + + pth_file = os.path.join(placeholder, 'setuptools.pth') + log.warn('Creating %s', pth_file) + f = open(pth_file, 'w') + try: + f.write(os.path.join(os.curdir, setuptools_file)) + finally: + f.close() + +@_no_sandbox +def _patch_egg_dir(path): + # let's check if it's already patched + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') + if os.path.exists(pkg_info): + if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): + log.warn('%s already patched.', pkg_info) + return False + _rename_path(path) + os.mkdir(path) + os.mkdir(os.path.join(path, 'EGG-INFO')) + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') + f = open(pkg_info, 'w') + try: + f.write(SETUPTOOLS_PKG_INFO) + finally: + f.close() + return True + + +def _before_install(): + log.warn('Before install bootstrap.') + _fake_setuptools() + + +def _under_prefix(location): + if 'install' not in sys.argv: + return True + args = sys.argv[sys.argv.index('install')+1:] + for index, arg in enumerate(args): + for option in ('--root', '--prefix'): + if arg.startswith('%s=' % option): + top_dir = arg.split('root=')[-1] + return location.startswith(top_dir) + elif arg == option: + if len(args) > index: + top_dir = args[index+1] + return location.startswith(top_dir) + elif option == '--user' and USER_SITE is not None: + return location.startswith(USER_SITE) + return True + + +def _fake_setuptools(): + log.warn('Scanning installed packages') + try: + import pkg_resources + except ImportError: + # we're cool + log.warn('Setuptools or Distribute does not seem to be installed.') + return + ws = pkg_resources.working_set + try: + setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools', + replacement=False)) + except TypeError: + # old distribute API + setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools')) + + if setuptools_dist is None: + log.warn('No setuptools distribution found') + return + # detecting if it was already faked + setuptools_location = setuptools_dist.location + log.warn('Setuptools installation detected at %s', setuptools_location) + + # if --root or --preix was provided, and if + # setuptools is not located in them, we don't patch it + if not _under_prefix(setuptools_location): + log.warn('Not patching, --root or --prefix is installing Distribute' + ' in another location') + return + + # let's see if its an egg + if not setuptools_location.endswith('.egg'): + log.warn('Non-egg installation') + res = _remove_flat_installation(setuptools_location) + if not res: + return + else: + log.warn('Egg installation') + pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') + if (os.path.exists(pkg_info) and + _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): + log.warn('Already patched.') + return + log.warn('Patching...') + # let's create a fake egg replacing setuptools one + res = _patch_egg_dir(setuptools_location) + if not res: + return + log.warn('Patched done.') + _relaunch() + + +def _relaunch(): + log.warn('Relaunching...') + # we have to relaunch the process + args = [sys.executable] + sys.argv + sys.exit(subprocess.call(args)) + + +def _extractall(self, path=".", members=None): + """Extract all members from the archive to the current working + directory and set owner, modification time and permissions on + directories afterwards. `path' specifies a different directory + to extract to. `members' is optional and must be a subset of the + list returned by getmembers(). + """ + import copy + import operator + from tarfile import ExtractError + directories = [] + + if members is None: + members = self + + for tarinfo in members: + if tarinfo.isdir(): + # Extract directories with a safe mode. + directories.append(tarinfo) + tarinfo = copy.copy(tarinfo) + tarinfo.mode = 448 # decimal for oct 0700 + self.extract(tarinfo, path) + + # Reverse sort directories. + if sys.version_info < (2, 4): + def sorter(dir1, dir2): + return cmp(dir1.name, dir2.name) + directories.sort(sorter) + directories.reverse() + else: + directories.sort(key=operator.attrgetter('name'), reverse=True) + + # Set correct owner, mtime and filemode on directories. + for tarinfo in directories: + dirpath = os.path.join(path, tarinfo.name) + try: + self.chown(tarinfo, dirpath) + self.utime(tarinfo, dirpath) + self.chmod(tarinfo, dirpath) + except ExtractError: + e = sys.exc_info()[1] + if self.errorlevel > 1: + raise + else: + self._dbg(1, "tarfile: %s" % e) + + +def main(argv, version=DEFAULT_VERSION): + """Install or upgrade setuptools and EasyInstall""" + tarball = download_setuptools() + _install(tarball) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/setup.py b/setup.py index 2494851f5..8d06f5691 100644 --- a/setup.py +++ b/setup.py @@ -2,8 +2,8 @@ try: from setuptools import setup, find_packages except ImportError: - import ez_setup - ez_setup.use_setuptools() + import distribute_setup + distribute_setup.use_setuptools() from setuptools import setup, find_packages import os From d6e5dfacd48c2d8bdc92a30b9bbeb3c015a03f12 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:13:57 +0200 Subject: [PATCH 020/207] Add a constant for class types, which lacks types.ClassType in Py3k. --- sphinx/application.py | 3 --- sphinx/environment.py | 4 ++-- sphinx/ext/autodoc.py | 13 ++++--------- sphinx/util/nodes.py | 4 ++-- sphinx/util/pycompat.py | 12 ++++++++++++ 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index 97778d3fb..b3d2aebc4 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -37,9 +37,6 @@ from sphinx.util.osutil import ENOENT from sphinx.util.console import bold -# Directive is either new-style or old-style -clstypes = (type, types.ClassType) - # List of all known core events. Maps name to arguments description. events = { 'builder-inited': '', diff --git a/sphinx/environment.py b/sphinx/environment.py index fa8460cb3..21994a746 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -39,7 +39,7 @@ from sphinx.util import url_re, get_matching_docs, docname_join, \ from sphinx.util.nodes import clean_astext, make_refnode from sphinx.util.osutil import movefile, SEP, ustrftime from sphinx.util.matching import compile_matchers -from sphinx.util.pycompat import all +from sphinx.util.pycompat import all, class_types from sphinx.errors import SphinxError, ExtensionError from sphinx.locale import _ @@ -251,7 +251,7 @@ class BuildEnvironment: if key.startswith('_') or \ isinstance(val, types.ModuleType) or \ isinstance(val, types.FunctionType) or \ - isinstance(val, (type, types.ClassType)): + isinstance(val, class_types): del self.config[key] try: pickle.dump(self, picklefile, pickle.HIGHEST_PROTOCOL) diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index adf08bcde..8a827a91f 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -14,7 +14,7 @@ import re import sys import inspect -from types import FunctionType, BuiltinFunctionType, MethodType, ClassType +from types import FunctionType, BuiltinFunctionType, MethodType from docutils import nodes from docutils.utils import assemble_option_dict @@ -27,15 +27,10 @@ from sphinx.application import ExtensionError from sphinx.util.nodes import nested_parse_with_titles from sphinx.util.compat import Directive from sphinx.util.inspect import isdescriptor, safe_getmembers, safe_getattr +from sphinx.util.pycompat import base_exception, class_types from sphinx.util.docstrings import prepare_docstring -try: - base_exception = BaseException -except NameError: - base_exception = Exception - - #: extended signature RE: with explicit module name separated by :: py_ext_sig_re = re.compile( r'''^ ([\w.]+::)? # explicit module name @@ -866,7 +861,7 @@ class ClassDocumenter(ModuleLevelDocumenter): @classmethod def can_document_member(cls, member, membername, isattr, parent): - return isinstance(member, (type, ClassType)) + return isinstance(member, class_types) def import_object(self): ret = ModuleLevelDocumenter.import_object(self) @@ -972,7 +967,7 @@ class ExceptionDocumenter(ClassDocumenter): @classmethod def can_document_member(cls, member, membername, isattr, parent): - return isinstance(member, (type, ClassType)) and \ + return isinstance(member, class_types) and \ issubclass(member, base_exception) diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index 97b585696..aab8f0142 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -10,11 +10,11 @@ """ import re -import types from docutils import nodes from sphinx import addnodes +from sphinx.util.pycompat import class_types # \x00 means the "<" was backslash-escaped @@ -115,7 +115,7 @@ def _new_traverse(self, condition=None, if include_self and descend and not siblings and not ascend: if condition is None: return self._all_traverse([]) - elif isinstance(condition, (types.ClassType, type)): + elif isinstance(condition, class_types): return self._fast_traverse(condition, []) return self._old_traverse(condition, include_self, descend, siblings, ascend) diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index bdd9507df..7bf768fac 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -13,6 +13,18 @@ import sys import codecs import encodings +try: + from types import ClassType + class_types = (type, ClassType) +except ImportError: + # Python 3 + class_types = (type,) + +try: + base_exception = BaseException +except NameError: + base_exception = Exception + try: any = any From 28349ed8569665196b4b2363ac23e13a22006f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 8 May 2010 23:23:56 +0200 Subject: [PATCH 021/207] Use 'U' if file is not present (we run under 3.x) --- tests/path.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/path.py b/tests/path.py index 20deb0489..7b89c0cd3 100644 --- a/tests/path.py +++ b/tests/path.py @@ -64,8 +64,13 @@ except NameError: # Universal newline support _textmode = 'r' -if hasattr(file, 'newlines'): +try: + file +except NameError: _textmode = 'U' +else: + if hasattr(file, 'newlines'): + _textmode = 'U' class TreeWalkWarning(Warning): From 84cba9c39c0b36c6837d8cc7ce19bbad05be7ff1 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:18:57 +0200 Subject: [PATCH 022/207] Fix wrong qualified name. --- sphinx/quickstart.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index fe2b43a33..a63907c7a 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -837,12 +837,12 @@ directly.''' if d['ext_intersphinx']: conf_text += INTERSPHINX_CONFIG - f = codecs.open(path.join(srcdir, 'conf.py'), 'w', encoding='utf-8') + f = open(path.join(srcdir, 'conf.py'), 'w', encoding='utf-8') f.write(conf_text) f.close() masterfile = path.join(srcdir, d['master'] + d['suffix']) - f = codecs.open(masterfile, 'w', encoding='utf-8') + f = open(masterfile, 'w', encoding='utf-8') f.write(MASTER_FILE % d) f.close() @@ -850,14 +850,14 @@ directly.''' d['rsrcdir'] = d['sep'] and 'source' or '.' d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build' # use binary mode, to avoid writing \r\n on Windows - f = codecs.open(path.join(d['path'], 'Makefile'), 'wb', encoding='utf-8') + f = open(path.join(d['path'], 'Makefile'), 'wb', encoding='utf-8') f.write(MAKEFILE % d) f.close() if d['batchfile']: d['rsrcdir'] = d['sep'] and 'source' or '.' d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build' - f = codecs.open(path.join(d['path'], 'make.bat'), 'w', encoding='utf-8') + f = open(path.join(d['path'], 'make.bat'), 'w', encoding='utf-8') f.write(BATCHFILE % d) f.close() From 420adbce2f75071b556e0d206b9f1887309c44c4 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:19:17 +0200 Subject: [PATCH 023/207] Make it easier for the test suite to override raw_input for test_quickstart. --- sphinx/quickstart.py | 5 ++++- tests/test_quickstart.py | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index a63907c7a..892bd641d 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -21,6 +21,9 @@ from sphinx.util.console import purple, bold, red, turquoise, \ nocolor, color_terminal from sphinx.util import texescape +# function to get input from terminal -- overridden by the test suite +term_input = raw_input + PROMPT_PREFIX = '> ' @@ -657,7 +660,7 @@ def do_prompt(d, key, text, default=None, validator=nonempty): prompt = purple(PROMPT_PREFIX + '%s [%s]: ' % (text, default)) else: prompt = purple(PROMPT_PREFIX + text + ': ') - x = raw_input(prompt) + x = term_input(prompt) if default and not x: x = default if not isinstance(x, unicode): diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index 8acff5884..d0403d3b2 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -37,7 +37,7 @@ def mock_raw_input(answers, needanswer=False): return raw_input def teardown_module(): - qs.raw_input = __builtin__.raw_input + qs.term_input = raw_input qs.TERM_ENCODING = getattr(sys.stdin, 'encoding', None) coloron() @@ -51,7 +51,7 @@ def test_do_prompt(): 'Q5': 'no', 'Q6': 'foo', } - qs.raw_input = mock_raw_input(answers) + qs.term_input = mock_raw_input(answers) try: qs.do_prompt(d, 'k1', 'Q1') except AssertionError: @@ -79,7 +79,7 @@ def test_quickstart_defaults(tempdir): 'Author name': 'Georg Brandl', 'Project version': '0.1', } - qs.raw_input = mock_raw_input(answers) + qs.term_input = mock_raw_input(answers) qs.inner_main([]) conffile = tempdir / 'conf.py' @@ -136,7 +136,7 @@ def test_quickstart_all_answers(tempdir): 'Create Windows command file': 'no', 'Do you want to use the epub builder': 'yes', } - qs.raw_input = mock_raw_input(answers, needanswer=True) + qs.term_input = mock_raw_input(answers, needanswer=True) qs.TERM_ENCODING = 'utf-8' qs.inner_main([]) From bcbce5955fe77854bf2a6781fab99fa2e23ab311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 9 May 2010 00:38:16 +0200 Subject: [PATCH 024/207] Changed tests/run.py so that it's possible to run the testsuite on python3 more easiely --- Makefile | 2 +- tests/run.py | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 682f03666..593c7ad49 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PYTHON ?= python -3 +PYTHON ?= python3 export PYTHONPATH = $(shell echo "$$PYTHONPATH"):./sphinx diff --git a/tests/run.py b/tests/run.py index 0cb41442c..5fd30d62b 100755 --- a/tests/run.py +++ b/tests/run.py @@ -11,7 +11,16 @@ """ import sys -from os import path +from os import path, chdir + +if sys.version_info >= (3,): + print('Copying and converting sources to build/lib/test...') + from distutils.util import copydir_run_2to3 + testroot = path.dirname(__file__) or '.' + newroot = path.join(testroot, path.pardir, 'build', 'lib', 'test') + copydir_run_2to3(testroot, newroot) + # switch to the converted dir so nose tests the right tests + chdir(newroot) # always test the sphinx package from this directory sys.path.insert(0, path.join(path.dirname(__file__), path.pardir)) @@ -19,8 +28,8 @@ sys.path.insert(0, path.join(path.dirname(__file__), path.pardir)) try: import nose except ImportError: - print "The nose package is needed to run the Sphinx test suite." + print("The nose package is needed to run the Sphinx test suite.") sys.exit(1) -print "Running Sphinx test suite..." +print("Running Sphinx test suite...") nose.main() From 5243c56d7abe5a4e2a2c5499f29fae8318c665f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 9 May 2010 00:54:14 +0200 Subject: [PATCH 025/207] Fixed DefExpr.__str__ --- sphinx/domains/cpp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 90c3533ef..8df89459b 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -110,7 +110,7 @@ class DefinitionError(Exception): return self.description def __str__(self): - return unicode(self.encode('utf-8')) + return unicode(self).encode('utf-8') class DefExpr(object): From e20b61b06e5b029d1b12f8fff392ebf4ca851574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 9 May 2010 14:57:18 +0200 Subject: [PATCH 026/207] Rename __unicode__ to __str__ --- custom_fixers/__init__.py | 0 custom_fixers/fix_alt_unicode.py | 12 ++++++++++++ setup.py | 1 + 3 files changed, 13 insertions(+) create mode 100644 custom_fixers/__init__.py create mode 100644 custom_fixers/fix_alt_unicode.py diff --git a/custom_fixers/__init__.py b/custom_fixers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/custom_fixers/fix_alt_unicode.py b/custom_fixers/fix_alt_unicode.py new file mode 100644 index 000000000..55175e90f --- /dev/null +++ b/custom_fixers/fix_alt_unicode.py @@ -0,0 +1,12 @@ +from lib2to3.fixer_base import BaseFix +from lib2to3.fixer_util import Name + +class FixAltUnicode(BaseFix): + PATTERN = """ + func=funcdef< 'def' name='__unicode__' + parameters< '(' NAME ')' > any+ > + """ + + def transform(self, node, results): + name = results['name'] + name.replace(Name('__str__', prefix=name.prefix)) diff --git a/setup.py b/setup.py index 8d06f5691..fe4066b80 100644 --- a/setup.py +++ b/setup.py @@ -199,4 +199,5 @@ setup( install_requires=requires, cmdclass=cmdclass, use_2to3=True, + use_2to3_fixers=['custom_fixers'], ) From 22a01fab9b7eb02266816c8001ba2db4ecb1573d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 10 May 2010 00:59:50 +0200 Subject: [PATCH 027/207] Added information about the i did during the weekend to the changes file --- CHANGES.DasIch | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGES.DasIch b/CHANGES.DasIch index 856a5d87b..711f9a534 100644 --- a/CHANGES.DasIch +++ b/CHANGES.DasIch @@ -5,6 +5,17 @@ This file contains changes made by Daniel Neuhäuser, during the Google Summer of Code 2010, to port Sphinx to Python 3.x. Changes are ordered descending by date. +May 10: Fixed a couple of tests and made several small changes. + +May 9: - Removed ez_setup.py which does not work with Python 3.x. and replaced + it with distribute_setup.py + - Use distribute (at least on 3.x) in order to run 2to3 automatically. + - Reverted some of the changes made in revision bac40c7c924c which + caused errors. + - Modified tests/run.py to test against the build created by + setup.py build in order to run the test suite with 3.x + - Several small changes to fix 3.x compatibilty. + May 1: - Removed deprecated tuple parameter unpacking. - Removed a pre-2.3 workaround for booleans because this creates a deprecation warning for 3.x, in which you can't assign values to From 36338fe9eaf559cbf7ede349c1bd6b5a650e3e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 16 May 2010 14:00:50 +0200 Subject: [PATCH 028/207] Added a clean-backupfiles target to the makefile --- Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 593c7ad49..aa2795147 100644 --- a/Makefile +++ b/Makefile @@ -12,17 +12,20 @@ check: -i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py \ -i env -i .tox . -clean: clean-pyc clean-patchfiles +clean: clean-pyc clean-patchfiles clean-backupfiles clean-pyc: find . -name '*.pyc' -exec rm -f {} + find . -name '*.pyo' -exec rm -f {} + - find . -name '*~' -exec rm -f {} + clean-patchfiles: find . -name '*.orig' -exec rm -f {} + find . -name '*.rej' -exec rm -f {} + +clean-backupfiles: + find . -name '*~' -exec rm -f {} + + find . -name '*.bak' -exec rm -f {} + + pylint: @pylint --rcfile utils/pylintrc sphinx From df444e822cc68e1e4717089c9fbb66bb110113ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 16 May 2010 16:20:44 +0200 Subject: [PATCH 029/207] Add setup_distribute.py to MANIFEST.in and remove ez_setup.py --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 25cbc334f..5e3104a82 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,7 +7,7 @@ include TODO include babel.cfg include Makefile -include ez_setup.py +include setup_distribute.py include sphinx-autogen.py include sphinx-build.py include sphinx-quickstart.py From 471da5aa21c6be081a68d7fc255456d81c5ee02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 16 May 2010 16:54:15 +0200 Subject: [PATCH 030/207] Added a build target to the Makefile which we need for python3 tests --- Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index aa2795147..72e047729 100644 --- a/Makefile +++ b/Makefile @@ -32,8 +32,11 @@ pylint: reindent: @$(PYTHON) utils/reindent.py -r -B . -test: +test: build @cd tests; $(PYTHON) run.py -d -m '^[tT]est' $(TEST) -covertest: +covertest: build @cd tests; $(PYTHON) run.py -d -m '^[tT]est' --with-coverage --cover-package=sphinx $(TEST) + +build: + @$(PYTHON) setup.py build From d8425102e27723839fc2c5078ab96c7752de1207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 16 May 2010 17:50:13 +0200 Subject: [PATCH 031/207] Switched check_sources.py from getopt to optparse --- utils/check_sources.py | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/utils/check_sources.py b/utils/check_sources.py index 0571ab1e8..1b30f2dc5 100755 --- a/utils/check_sources.py +++ b/utils/check_sources.py @@ -12,8 +12,8 @@ """ import sys, os, re -import getopt import cStringIO +from optparse import OptionParser from os.path import join, splitext, abspath @@ -165,34 +165,32 @@ def check_xhtml(fn, lines): def main(argv): - try: - gopts, args = getopt.getopt(argv[1:], "vi:") - except getopt.GetoptError: - print "Usage: %s [-v] [-i ignorepath]* [path]" % argv[0] - return 2 - opts = {} - for opt, val in gopts: - if opt == '-i': - val = abspath(val) - opts.setdefault(opt, []).append(val) + parser = OptionParser(usage='Usage: %prog [-v] [-i ignorepath]* [path]') + parser.add_option('-v', '--verbose', dest='verbose', default=False, + action='store_true') + parser.add_option('-i', '--ignore-path', dest='ignored_paths', + default=[], action='append') + options, args = parser.parse_args(argv[1:]) if len(args) == 0: path = '.' elif len(args) == 1: path = args[0] else: - print "Usage: %s [-v] [-i ignorepath]* [path]" % argv[0] - return 2 + print args + parser.error('No more then one path supported') - verbose = '-v' in opts + verbose = options.verbose + ignored_paths = set(abspath(p) for p in options.ignored_paths) num = 0 out = cStringIO.StringIO() for root, dirs, files in os.walk(path): - if '.svn' in dirs: - dirs.remove('.svn') - if '-i' in opts and abspath(root) in opts['-i']: + for vcs_dir in ['.svn', '.hg', '.git']: + if vcs_dir in dirs: + dirs.remove(vcs_dir) + if abspath(root) in ignored_paths: del dirs[:] continue in_check_pkg = root.startswith('./sphinx') @@ -201,7 +199,7 @@ def main(argv): fn = join(root, fn) if fn[:2] == './': fn = fn[2:] - if '-i' in opts and abspath(fn) in opts['-i']: + if abspath(fn) in ignored_paths: continue ext = splitext(fn)[1] From ad29ab1b860d13fcd0dacd2395f8f3dea5c2370a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 16 May 2010 19:45:23 +0200 Subject: [PATCH 032/207] Fixed file opening --- utils/check_sources.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/utils/check_sources.py b/utils/check_sources.py index 1b30f2dc5..8eeadbf4b 100755 --- a/utils/check_sources.py +++ b/utils/check_sources.py @@ -212,7 +212,10 @@ def main(argv): try: f = open(fn, 'r') - lines = list(f) + try: + lines = list(f) + finally: + f.close() except (IOError, OSError), err: print "%s: cannot open: %s" % (fn, err) num += 1 From 592a978c25d94579142c50c4be240d5856124891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 16 May 2010 22:19:38 +0200 Subject: [PATCH 033/207] Scripts in utils are now automatically converted. They may not work at the moment though --- Makefile | 14 ++++++++++---- utils/convert.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 utils/convert.py diff --git a/Makefile b/Makefile index 72e047729..53424b5d6 100644 --- a/Makefile +++ b/Makefile @@ -2,17 +2,17 @@ PYTHON ?= python3 export PYTHONPATH = $(shell echo "$$PYTHONPATH"):./sphinx -.PHONY: all check clean clean-pyc clean-patchfiles pylint reindent test +.PHONY: all check clean clean-pyc clean-patchfiles clean-generated pylint reindent test all: clean-pyc check test -check: +check: convert-utils @$(PYTHON) utils/check_sources.py -i build -i dist -i sphinx/style/jquery.js \ -i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py -i .ropeproject \ -i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py \ -i env -i .tox . -clean: clean-pyc clean-patchfiles clean-backupfiles +clean: clean-pyc clean-patchfiles clean-backupfiles clean-generated clean-pyc: find . -name '*.pyc' -exec rm -f {} + @@ -26,10 +26,13 @@ clean-backupfiles: find . -name '*~' -exec rm -f {} + find . -name '*.bak' -exec rm -f {} + +clean-generated: + rm utils/*3.py* + pylint: @pylint --rcfile utils/pylintrc sphinx -reindent: +reindent: convert-utils @$(PYTHON) utils/reindent.py -r -B . test: build @@ -40,3 +43,6 @@ covertest: build build: @$(PYTHON) setup.py build + +convert-utils: + @python3 utils/convert.py -i utils/convert.py utils/ diff --git a/utils/convert.py b/utils/convert.py new file mode 100644 index 000000000..65b4d3bdf --- /dev/null +++ b/utils/convert.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# coding: utf-8 +""" + Converts files with 2to3 + ~~~~~~~~~~~~~~~~~~~~~~~~ + + Creates a Python 3 version of each file. + + The Python3 version of a file foo.py will be called foo3.py. + + :copyright: Copyright 2010 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" +import os +import sys +from glob import iglob +from optparse import OptionParser +from shutil import copy +from distutils.util import run_2to3 + +def main(argv): + parser = OptionParser(usage='%prog [path]') + parser.add_option('-i', '--ignorepath', dest='ignored_paths', + action='append', default=[]) + options, args = parser.parse_args(argv) + + ignored_paths = set(options.ignored_paths) + + path = os.path.abspath(args[0]) if args else os.getcwd() + convertables = [] + for filename in iglob(os.path.join(path, '*.py')): + if filename in ignored_paths: + continue + basename, ext = os.path.splitext(filename) + if basename.endswith('3'): + continue + filename3 = basename + '3' + ext + copy(filename, filename3) + convertables.append(filename3) + run_2to3(convertables) + +if __name__ == "__main__": + main(sys.argv[1:]) From 315ad84fce2beab11457d23b53b48b41fb23332b Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:28:34 +0200 Subject: [PATCH 034/207] Ignore failures in removing converted utils. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 53424b5d6..4c0cdef87 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ clean-backupfiles: find . -name '*.bak' -exec rm -f {} + clean-generated: - rm utils/*3.py* + -rm utils/*3.py* pylint: @pylint --rcfile utils/pylintrc sphinx From e1b7381a94592d04717290f842f49a7aa08e33c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 16 May 2010 22:24:20 +0200 Subject: [PATCH 035/207] convert.py now properly ignores paths --- utils/convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/convert.py b/utils/convert.py index 65b4d3bdf..f025c49a0 100644 --- a/utils/convert.py +++ b/utils/convert.py @@ -24,7 +24,7 @@ def main(argv): action='append', default=[]) options, args = parser.parse_args(argv) - ignored_paths = set(options.ignored_paths) + ignored_paths = {os.path.abspath(p) for p in options.ignored_paths} path = os.path.abspath(args[0]) if args else os.getcwd() convertables = [] From 87d35afcfccd9c42faaf32c424e8de19f0e7b627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 16 May 2010 22:27:05 +0200 Subject: [PATCH 036/207] Ignore generated files --- .hgignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgignore b/.hgignore index 70ea36a52..40c00aac7 100644 --- a/.hgignore +++ b/.hgignore @@ -15,3 +15,4 @@ ^env/ \.DS_Store$ ~$ +^utils/.*3\.py$ From e8d98966dec388bce4e9076de0ea03454053e678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 16 May 2010 23:51:25 +0200 Subject: [PATCH 037/207] Automatically use converted scripts in the makefile --- Makefile | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 4c0cdef87..2672aad4b 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,22 @@ -PYTHON ?= python3 +PYTHON ?= python export PYTHONPATH = $(shell echo "$$PYTHONPATH"):./sphinx .PHONY: all check clean clean-pyc clean-patchfiles clean-generated pylint reindent test +DONT_CHECK = -i build -i dist -i sphinx/style/jquery.js -i sphinx/pycode/pgen2 \ + -i sphinx/util/smartypants.py -i .ropeproject -i doc/_build -i tests/path.py \ + -i tests/coverage.py -i env -i utils/convert.py -i utils/reindent3.py \ + -i utils/check_sources3.py + all: clean-pyc check test check: convert-utils - @$(PYTHON) utils/check_sources.py -i build -i dist -i sphinx/style/jquery.js \ - -i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py -i .ropeproject \ - -i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py \ - -i env -i .tox . +ifeq ($(PYTHON), python3) + @$(PYTHON) utils/check_sources3.py $(DONT_CHECK) . +else + @$(PYTHON) utils/check_sources.py $(DONT_CHECK) . +endif clean: clean-pyc clean-patchfiles clean-backupfiles clean-generated @@ -33,7 +39,11 @@ pylint: @pylint --rcfile utils/pylintrc sphinx reindent: convert-utils +ifeq ($(PYTHON), python3) + @$(PYTHON) utils/reindent3.py -r -B . +else @$(PYTHON) utils/reindent.py -r -B . +endif test: build @cd tests; $(PYTHON) run.py -d -m '^[tT]est' $(TEST) From 46e5c123d5125524d2563a641189820601004dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 16 May 2010 23:56:44 +0200 Subject: [PATCH 038/207] Keep under 80 chars per line in the Makefile --- Makefile | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 2672aad4b..cf4f292f7 100644 --- a/Makefile +++ b/Makefile @@ -2,12 +2,14 @@ PYTHON ?= python export PYTHONPATH = $(shell echo "$$PYTHONPATH"):./sphinx -.PHONY: all check clean clean-pyc clean-patchfiles clean-generated pylint reindent test +.PHONY: all check clean clean-pyc clean-patchfiles clean-generated pylint \ + reindent test -DONT_CHECK = -i build -i dist -i sphinx/style/jquery.js -i sphinx/pycode/pgen2 \ - -i sphinx/util/smartypants.py -i .ropeproject -i doc/_build -i tests/path.py \ - -i tests/coverage.py -i env -i utils/convert.py -i utils/reindent3.py \ - -i utils/check_sources3.py +DONT_CHECK = -i build -i dist -i sphinx/style/jquery.js \ + -i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py \ + -i .ropeproject -i doc/_build -i tests/path.py \ + -i tests/coverage.py -i env -i utils/convert.py \ + -i utils/reindent3.py -i utils/check_sources3.py -i .tox all: clean-pyc check test @@ -49,7 +51,8 @@ test: build @cd tests; $(PYTHON) run.py -d -m '^[tT]est' $(TEST) covertest: build - @cd tests; $(PYTHON) run.py -d -m '^[tT]est' --with-coverage --cover-package=sphinx $(TEST) + @cd tests; $(PYTHON) run.py -d -m '^[tT]est' --with-coverage \ + --cover-package=sphinx $(TEST) build: @$(PYTHON) setup.py build From acd1eaf9d7f6316e3f53e8d96de1d54f624c00cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 17 May 2010 00:44:44 +0200 Subject: [PATCH 039/207] check_sources.py is now ported to 3.x --- Makefile | 2 +- utils/check_sources.py | 72 +++++++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index cf4f292f7..209302302 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PYTHON ?= python +PYTHON ?= python3 export PYTHONPATH = $(shell echo "$$PYTHONPATH"):./sphinx diff --git a/utils/check_sources.py b/utils/check_sources.py index 8eeadbf4b..c412742b7 100755 --- a/utils/check_sources.py +++ b/utils/check_sources.py @@ -16,6 +16,12 @@ import cStringIO from optparse import OptionParser from os.path import join, splitext, abspath +if sys.version_info >= (3, 0): + def b(s): + return s.encode('utf-8') +else: + b = str + checkers = {} @@ -30,26 +36,26 @@ def checker(*suffixes, **kwds): name_mail_re = r'[\w ]+(<.*?>)?' -copyright_re = re.compile(r'^ :copyright: Copyright 200\d(-20\d\d)? ' - r'by %s(, %s)*[,.]$' % - (name_mail_re, name_mail_re)) -license_re = re.compile(r" :license: (.*?).\n") -copyright_2_re = re.compile(r'^ %s(, %s)*[,.]$' % - (name_mail_re, name_mail_re)) -coding_re = re.compile(r'coding[:=]\s*([-\w.]+)') -not_ix_re = re.compile(r'\bnot\s+\S+?\s+i[sn]\s\S+') -is_const_re = re.compile(r'if.*?==\s+(None|False|True)\b') +copyright_re = re.compile(b(r'^ :copyright: Copyright 200\d(-20\d\d)? ' + r'by %s(, %s)*[,.]$' % + (name_mail_re, name_mail_re))) +license_re = re.compile(b(r" :license: (.*?).\n")) +copyright_2_re = re.compile(b(r'^ %s(, %s)*[,.]$' % + (name_mail_re, name_mail_re))) +coding_re = re.compile(b(r'coding[:=]\s*([-\w.]+)')) +not_ix_re = re.compile(b(r'\bnot\s+\S+?\s+i[sn]\s\S+')) +is_const_re = re.compile(b(r'if.*?==\s+(None|False|True)\b')) -misspellings = ["developement", "adress", "verificate", # ALLOW-MISSPELLING - "informations"] # ALLOW-MISSPELLING +misspellings = [b("developement"), b("adress"), # ALLOW-MISSPELLING + b("verificate"), b("informations")] # ALLOW-MISSPELLING - -@checker('.py') -def check_syntax(fn, lines): - try: - compile(''.join(lines), fn, "exec") - except SyntaxError, err: - yield 0, "not compilable: %s" % err +if sys.version_info < (3, 0): + @checker('.py') + def check_syntax(fn, lines): + try: + compile(b('').join(lines), fn, "exec") + except SyntaxError, err: + yield 0, "not compilable: %s" % err @checker('.py') @@ -61,8 +67,8 @@ def check_style_and_encoding(fn, lines): if lno < 2: co = coding_re.search(line) if co: - encoding = co.group(1) - if line.strip().startswith('#'): + encoding = co.group(1).decode('ascii') + if line.strip().startswith(b('#')): continue #m = not_ix_re.search(line) #if m: @@ -82,7 +88,7 @@ def check_style_and_encoding(fn, lines): def check_fileheader(fn, lines): # line number correction c = 1 - if lines[0:1] == ['#!/usr/bin/env python\n']: + if lines[0:1] == [b('#!/usr/bin/env python\n')]: lines = lines[1:] c = 2 @@ -91,38 +97,38 @@ def check_fileheader(fn, lines): for lno, l in enumerate(lines): llist.append(l) if lno == 0: - if l == '# -*- coding: rot13 -*-\n': + if l == b('# -*- coding: rot13 -*-\n'): # special-case pony package return - elif l != '# -*- coding: utf-8 -*-\n': + elif l != b('# -*- coding: utf-8 -*-\n'): yield 1, "missing coding declaration" elif lno == 1: - if l != '"""\n' and l != 'r"""\n': + if l != b('"""\n') and l != b('r"""\n'): yield 2, 'missing docstring begin (""")' else: docopen = True elif docopen: - if l == '"""\n': + if l == b('"""\n'): # end of docstring if lno <= 4: yield lno+c, "missing module name in docstring" break - if l != "\n" and l[:4] != ' ' and docopen: + if l != b("\n") and l[:4] != b(' ') and docopen: yield lno+c, "missing correct docstring indentation" if lno == 2: # if not in package, don't check the module name modname = fn[:-3].replace('/', '.').replace('.__init__', '') while modname: - if l.lower()[4:-1] == modname: + if l.lower()[4:-1] == b(modname): break modname = '.'.join(modname.split('.')[1:]) else: yield 3, "wrong module name in docstring heading" modnamelen = len(l.strip()) elif lno == 3: - if l.strip() != modnamelen * "~": + if l.strip() != modnamelen * b("~"): yield 4, "wrong module name underline, should be ~~~...~" else: @@ -145,16 +151,16 @@ def check_fileheader(fn, lines): @checker('.py', '.html', '.rst') def check_whitespace_and_spelling(fn, lines): for lno, line in enumerate(lines): - if "\t" in line: + if b("\t") in line: yield lno+1, "OMG TABS!!!1 " - if line[:-1].rstrip(' \t') != line[:-1]: + if line[:-1].rstrip(b(' \t')) != line[:-1]: yield lno+1, "trailing whitespace" for word in misspellings: - if word in line and 'ALLOW-MISSPELLING' not in line: + if word in line and b('ALLOW-MISSPELLING') not in line: yield lno+1, '"%s" used' % word -bad_tags = ('', '', '', '
', '', '', '', '
', ' Date: Mon, 17 May 2010 01:11:22 +0200 Subject: [PATCH 040/207] ported utils/reindent.py to python 3.x --- utils/reindent.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/utils/reindent.py b/utils/reindent.py index bcb6b4343..63ff7ef73 100755 --- a/utils/reindent.py +++ b/utils/reindent.py @@ -47,6 +47,17 @@ recurse = 0 dryrun = 0 no_backup = 0 +if sys.version_info >= (3, 0): + def tokens(readline, tokeneater): + for token in tokenize.tokenize(readline): + tokeneater(*token) + + def b(s): + return s.encode('utf-8') +else: + tokens = tokenize.tokenize + b = str + def usage(msg=None): if msg is not None: print >> sys.stderr, msg @@ -106,7 +117,7 @@ def check(file): if verbose: print "checking", file, "...", try: - f = open(file) + f = open(file, 'rb') except IOError, msg: errprint("%s: I/O Error: %s" % (file, str(msg))) return @@ -129,7 +140,7 @@ def check(file): os.rename(file, bak) if verbose: print "renamed", file, "to", bak - f = open(file, "w") + f = open(file, "wb") r.write(f) f.close() if verbose: @@ -151,7 +162,7 @@ class Reindenter: # File lines, rstripped & tab-expanded. Dummy at start is so # that we can use tokenize's 1-based line numbering easily. # Note that a line is all-blank iff it's "\n". - self.lines = [line.rstrip('\n \t').expandtabs() + "\n" + self.lines = [line.rstrip(b('\n \t')).expandtabs() + b("\n") for line in self.raw] self.lines.insert(0, None) self.index = 1 # index into self.lines of next line @@ -163,10 +174,10 @@ class Reindenter: self.stats = [] def run(self): - tokenize.tokenize(self.getline, self.tokeneater) + tokens(self.getline, self.tokeneater) # Remove trailing empty lines. lines = self.lines - while lines and lines[-1] == "\n": + while lines and lines[-1] == b("\n"): lines.pop() # Sentinel. stats = self.stats @@ -222,10 +233,10 @@ class Reindenter: else: for line in lines[thisstmt:nextstmt]: if diff > 0: - if line == "\n": + if line == b("\n"): after.append(line) else: - after.append(" " * diff + line) + after.append(b(" ") * diff + line) else: remove = min(getlspace(line), -diff) after.append(line[remove:]) @@ -237,7 +248,7 @@ class Reindenter: # Line-getter for tokenize. def getline(self): if self.index >= len(self.lines): - line = "" + line = b("") else: line = self.lines[self.index] self.index += 1 @@ -286,7 +297,7 @@ class Reindenter: # Count number of leading blanks. def getlspace(line): i, n = 0, len(line) - while i < n and line[i] == " ": + while i < n and line[i] == b(" "): i += 1 return i From 936d68fc8364c2274e1416a951bf2af9b54cbd3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 17 May 2010 01:28:50 +0200 Subject: [PATCH 041/207] Ignore errors when removing generated files --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 209302302..c1b266dcb 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ clean-backupfiles: find . -name '*.bak' -exec rm -f {} + clean-generated: - -rm utils/*3.py* + rm -f utils/*3.py* pylint: @pylint --rcfile utils/pylintrc sphinx From 765871c86c1ca26f013b6fc489c24fa6dba96e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 17 May 2010 02:23:59 +0200 Subject: [PATCH 042/207] Added latest changes to the Changes.DasIch file --- CHANGES.DasIch | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.DasIch b/CHANGES.DasIch index 711f9a534..3f7167263 100644 --- a/CHANGES.DasIch +++ b/CHANGES.DasIch @@ -5,6 +5,12 @@ This file contains changes made by Daniel Neuhäuser, during the Google Summer of Code 2010, to port Sphinx to Python 3.x. Changes are ordered descending by date. +May 16: - Added utils/convert.py which converts entire directories of python + files with 2to3 and names the converted files foo3.py. + - Modified the Makefile so that in case Python 3 is used the scripts in + utils get converted with utils/convert.py and are used instead of the + Python 2 scripts. + May 10: Fixed a couple of tests and made several small changes. May 9: - Removed ez_setup.py which does not work with Python 3.x. and replaced From ad9055868ee81971bf9a7aa0cd2c6d24a6e55522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 17 May 2010 02:26:31 +0200 Subject: [PATCH 043/207] Added latest reindent.py file --- Makefile | 4 +- utils/reindent.py | 96 +++++++++++++++++++++++++---------------------- 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/Makefile b/Makefile index c1b266dcb..ecc7722c2 100644 --- a/Makefile +++ b/Makefile @@ -42,9 +42,9 @@ pylint: reindent: convert-utils ifeq ($(PYTHON), python3) - @$(PYTHON) utils/reindent3.py -r -B . + @$(PYTHON) utils/reindent3.py -r -n . else - @$(PYTHON) utils/reindent.py -r -B . + @$(PYTHON) utils/reindent.py -r -n . endif test: build diff --git a/utils/reindent.py b/utils/reindent.py index 63ff7ef73..59828fd86 100755 --- a/utils/reindent.py +++ b/utils/reindent.py @@ -1,16 +1,14 @@ #! /usr/bin/env python # Released to the public domain, by Tim Peters, 03 October 2000. -# -B option added by Georg Brandl, 2006. """reindent [-d][-r][-v] [ path ... ] --d (--dryrun) Dry run. Analyze, but don't make any changes to files. --r (--recurse) Recurse. Search for all .py files in subdirectories too. --B (--no-backup) Don't write .bak backup files. --v (--verbose) Verbose. Print informative msgs; else only names of \ -changed files. --h (--help) Help. Print this usage information and exit. +-d (--dryrun) Dry run. Analyze, but don't make any changes to, files. +-r (--recurse) Recurse. Search for all .py files in subdirectories too. +-n (--nobackup) No backup. Does not make a ".bak" file before reindenting. +-v (--verbose) Verbose. Print informative msgs; else no output. +-h (--help) Help. Print this usage information and exit. Change Python (.py) files to use 4-space indents and no hard tab characters. Also trim excess spaces and tabs from ends of lines, and remove empty lines @@ -34,29 +32,30 @@ resulting .py file won't change it again). The hard part of reindenting is figuring out what to do with comment lines. So long as the input files get a clean bill of health from tabnanny.py, reindent should do a good job. + +The backup file is a copy of the one that is being reindented. The ".bak" +file is generated with shutil.copy(), but some corner cases regarding +user/group and permissions could leave the backup file more readable that +you'd prefer. You can always use the --nobackup option to prevent this. """ __version__ = "1" import tokenize -import os +import os, shutil import sys -verbose = 0 -recurse = 0 -dryrun = 0 -no_backup = 0 - if sys.version_info >= (3, 0): def tokens(readline, tokeneater): for token in tokenize.tokenize(readline): - tokeneater(*token) - - def b(s): - return s.encode('utf-8') + yield tokeneater(*token) else: tokens = tokenize.tokenize - b = str + +verbose = 0 +recurse = 0 +dryrun = 0 +makebackup = True def usage(msg=None): if msg is not None: @@ -72,12 +71,10 @@ def errprint(*args): def main(): import getopt - global verbose, recurse, dryrun, no_backup - + global verbose, recurse, dryrun, makebackup try: - opts, args = getopt.getopt(sys.argv[1:], "drvhB", - ["dryrun", "recurse", "verbose", "help", - "no-backup"]) + opts, args = getopt.getopt(sys.argv[1:], "drnvh", + ["dryrun", "recurse", "nobackup", "verbose", "help"]) except getopt.error, msg: usage(msg) return @@ -86,10 +83,10 @@ def main(): dryrun += 1 elif o in ('-r', '--recurse'): recurse += 1 + elif o in ('-n', '--nobackup'): + makebackup = False elif o in ('-v', '--verbose'): verbose += 1 - elif o in ('-B', '--no-backup'): - no_backup += 1 elif o in ('-h', '--help'): usage() return @@ -109,7 +106,8 @@ def check(file): for name in names: fullname = os.path.join(file, name) if ((recurse and os.path.isdir(fullname) and - not os.path.islink(fullname)) + not os.path.islink(fullname) and + not os.path.split(fullname)[1].startswith(".")) or name.lower().endswith(".py")): check(fullname) return @@ -117,7 +115,7 @@ def check(file): if verbose: print "checking", file, "...", try: - f = open(file, 'rb') + f = open(file) except IOError, msg: errprint("%s: I/O Error: %s" % (file, str(msg))) return @@ -129,26 +127,35 @@ def check(file): print "changed." if dryrun: print "But this is a dry run, so leaving it alone." - else: - print "reindented", file, \ - (dryrun and "(dry run => not really)" or "") if not dryrun: - if not no_backup: - bak = file + ".bak" - if os.path.exists(bak): - os.remove(bak) - os.rename(file, bak) + bak = file + ".bak" + if makebackup: + shutil.copyfile(file, bak) if verbose: - print "renamed", file, "to", bak - f = open(file, "wb") + print "backed up", file, "to", bak + f = open(file, "w") r.write(f) f.close() if verbose: print "wrote new", file + return True else: if verbose: print "unchanged." + return False +def _rstrip(line, JUNK='\n \t'): + """Return line stripped of trailing spaces, tabs, newlines. + + Note that line.rstrip() instead also strips sundry control characters, + but at least one known Emacs user expects to keep junk like that, not + mentioning Barry by name or anything . + """ + + i = len(line) + while i > 0 and line[i-1] in JUNK: + i -= 1 + return line[:i] class Reindenter: @@ -162,7 +169,7 @@ class Reindenter: # File lines, rstripped & tab-expanded. Dummy at start is so # that we can use tokenize's 1-based line numbering easily. # Note that a line is all-blank iff it's "\n". - self.lines = [line.rstrip(b('\n \t')).expandtabs() + b("\n") + self.lines = [_rstrip(line).expandtabs() + "\n" for line in self.raw] self.lines.insert(0, None) self.index = 1 # index into self.lines of next line @@ -177,7 +184,7 @@ class Reindenter: tokens(self.getline, self.tokeneater) # Remove trailing empty lines. lines = self.lines - while lines and lines[-1] == b("\n"): + while lines and lines[-1] == "\n": lines.pop() # Sentinel. stats = self.stats @@ -233,10 +240,10 @@ class Reindenter: else: for line in lines[thisstmt:nextstmt]: if diff > 0: - if line == b("\n"): + if line == "\n": after.append(line) else: - after.append(b(" ") * diff + line) + after.append(" " * diff + line) else: remove = min(getlspace(line), -diff) after.append(line[remove:]) @@ -248,20 +255,19 @@ class Reindenter: # Line-getter for tokenize. def getline(self): if self.index >= len(self.lines): - line = b("") + line = "" else: line = self.lines[self.index] self.index += 1 return line # Line-eater for tokenize. - def tokeneater(self, type, token, scell, end, line, + def tokeneater(self, type, token, (sline, scol), end, line, INDENT=tokenize.INDENT, DEDENT=tokenize.DEDENT, NEWLINE=tokenize.NEWLINE, COMMENT=tokenize.COMMENT, NL=tokenize.NL): - sline, scol = scell if type == NEWLINE: # A program statement, or ENDMARKER, will eventually follow, @@ -297,7 +303,7 @@ class Reindenter: # Count number of leading blanks. def getlspace(line): i, n = 0, len(line) - while i < n and line[i] == b(" "): + while i < n and line[i] == " ": i += 1 return i From 614a7f048fb51de38b1a55460714670c3f6de901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 23 May 2010 01:34:52 +0200 Subject: [PATCH 044/207] make now works without python3 --- Makefile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index ecc7722c2..21a87e367 100644 --- a/Makefile +++ b/Makefile @@ -11,12 +11,13 @@ DONT_CHECK = -i build -i dist -i sphinx/style/jquery.js \ -i tests/coverage.py -i env -i utils/convert.py \ -i utils/reindent3.py -i utils/check_sources3.py -i .tox -all: clean-pyc check test +all: clean-pyc clean-backupfiles check test -check: convert-utils ifeq ($(PYTHON), python3) +check: convert-utils @$(PYTHON) utils/check_sources3.py $(DONT_CHECK) . else +check: @$(PYTHON) utils/check_sources.py $(DONT_CHECK) . endif @@ -40,10 +41,11 @@ clean-generated: pylint: @pylint --rcfile utils/pylintrc sphinx -reindent: convert-utils ifeq ($(PYTHON), python3) +reindent: convert-utils @$(PYTHON) utils/reindent3.py -r -n . else +reindent: @$(PYTHON) utils/reindent.py -r -n . endif @@ -57,5 +59,7 @@ covertest: build build: @$(PYTHON) setup.py build +ifeq ($(PYTHON), python3) convert-utils: @python3 utils/convert.py -i utils/convert.py utils/ +endif From a83c48ec8a5f275c5ecb67251945eb454969ef90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 24 May 2010 17:32:00 +0200 Subject: [PATCH 045/207] test_autodoc.test_get_doc now passes --- sphinx/ext/autodoc.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index 8a827a91f..1113f97a0 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -411,9 +411,11 @@ class Documenter(object): def get_doc(self, encoding=None): """Decode and return lines of the docstring(s) for the object.""" docstring = self.get_attr(self.object, '__doc__', None) - if docstring: - # make sure we have Unicode docstrings, then sanitize and split - # into lines + # make sure we have Unicode docstrings, then sanitize and split + # into lines + if isinstance(docstring, unicode): + return [prepare_docstring(docstring)] + elif docstring: return [prepare_docstring(force_decode(docstring, encoding))] return [] @@ -934,9 +936,12 @@ class ClassDocumenter(ModuleLevelDocumenter): docstrings = [initdocstring] else: docstrings.append(initdocstring) - - return [prepare_docstring(force_decode(docstring, encoding)) - for docstring in docstrings] + doc = [] + for docstring in docstrings: + if not isinstance(docstring, unicode): + docstring = force_decode(docstring, encoding) + doc.append(prepare_docstring(docstring)) + return doc def add_content(self, more_content, no_docstring=False): if self.doc_as_attr: From f8b12a45dae561b611769bd4f1cd231497d7c2b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 24 May 2010 17:35:43 +0200 Subject: [PATCH 046/207] use open instead of file --- tests/path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/path.py b/tests/path.py index 7b89c0cd3..f27e58a9d 100644 --- a/tests/path.py +++ b/tests/path.py @@ -516,7 +516,7 @@ class path(_base): def open(self, mode='r'): """ Open this file. Return a file object. """ - return file(self, mode) + return open(self, mode) def bytes(self): """ Open this file, read all bytes, return them as a string. """ From d1d5d20f65e0cd298fa1a9885c133ae4bddb4c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 24 May 2010 18:13:56 +0200 Subject: [PATCH 047/207] Workaround for 2to3 --- sphinx/ext/intersphinx.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 0a210879a..fb1f0e4ff 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -36,8 +36,10 @@ from sphinx.builders.html import INVENTORY_FILENAME handlers = [urllib2.ProxyHandler(), urllib2.HTTPRedirectHandler(), urllib2.HTTPHandler()] -if hasattr(urllib2, 'HTTPSHandler'): +try: handlers.append(urllib2.HTTPSHandler) +except NameError: + pass urllib2.install_opener(urllib2.build_opener(*handlers)) From bedbbe288ed774d9d26dd114fcf6c2769fc1a2f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 24 May 2010 18:25:20 +0200 Subject: [PATCH 048/207] don't assume strings to be byte strings --- sphinx/pycode/__init__.py | 3 ++- sphinx/pycode/pgen2/literals.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py index b8e2fded2..cb9c08878 100644 --- a/sphinx/pycode/__init__.py +++ b/sphinx/pycode/__init__.py @@ -98,7 +98,8 @@ class AttrDocVisitor(nodes.NodeVisitor): if not pnode or pnode.type not in (token.INDENT, token.DEDENT): break prefix = pnode.get_prefix() - prefix = prefix.decode(self.encoding) + if not isinstance(prefix, unicode): + prefix = prefix.decode(self.encoding) docstring = prepare_commentdoc(prefix) self.add_docstring(node, docstring) diff --git a/sphinx/pycode/pgen2/literals.py b/sphinx/pycode/pgen2/literals.py index 319002910..d48937028 100644 --- a/sphinx/pycode/pgen2/literals.py +++ b/sphinx/pycode/pgen2/literals.py @@ -66,7 +66,7 @@ uni_escape_re = re.compile(r"\\(\'|\"|\\|[abfnrtv]|x.{0,2}|[0-7]{1,3}|" def evalString(s, encoding=None): regex = escape_re repl = escape - if encoding: + if encoding and not isinstance(s, unicode): s = s.decode(encoding) if s.startswith('u') or s.startswith('U'): regex = uni_escape_re From 24f1d4c12d76b4eb90818b3a10e0cb26ca120a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 24 May 2010 19:41:02 +0200 Subject: [PATCH 049/207] fixed test_markup test --- sphinx/util/osutil.py | 11 +++++++---- tests/test_markup.py | 9 ++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py index beab38cbd..1010fb2fe 100644 --- a/sphinx/util/osutil.py +++ b/sphinx/util/osutil.py @@ -14,6 +14,7 @@ import re import time import errno import shutil +import sys from os import path # Errnos that we need. @@ -124,7 +125,9 @@ no_fn_re = re.compile(r'[^a-zA-Z0-9_-]') def make_filename(string): return no_fn_re.sub('', string) - -def ustrftime(format, *args): - # strftime for unicode strings - return time.strftime(unicode(format).encode('utf-8'), *args).decode('utf-8') +if sys.version_info < (3, 0): + def ustrftime(format, *args): + # strftime for unicode strings + return time.strftime(unicode(format).encode('utf-8'), *args).decode('utf-8') +else: + ustrftime = time.strftime diff --git a/tests/test_markup.py b/tests/test_markup.py index 31817df62..6d6badbbc 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -10,6 +10,7 @@ """ import re +import sys from util import * @@ -20,6 +21,12 @@ from sphinx.util import texescape from sphinx.writers.html import HTMLWriter, SmartyPantsHTMLTranslator from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator +if sys.version_info > (3, 0): + def b(s): + return s.encode('utf-8') +else: + b = str + def setup_module(): global app, settings, parser texescape.init() # otherwise done by the latex builder @@ -50,7 +57,7 @@ class ForgivingLaTeXTranslator(LaTeXTranslator, ForgivingTranslator): def verify_re(rst, html_expected, latex_expected): - document = utils.new_document('test data', settings) + document = utils.new_document(b('test data'), settings) document['file'] = 'dummy' parser.parse(rst, document) for msg in document.traverse(nodes.system_message): From ec5a5e739bd93273be9649250443c1267069b203 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:43:40 +0200 Subject: [PATCH 050/207] Move the "b" function to pycompat. --- sphinx/util/osutil.py | 2 +- sphinx/util/pycompat.py | 8 ++++++++ tests/test_markup.py | 8 +------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py index 1010fb2fe..250e75741 100644 --- a/sphinx/util/osutil.py +++ b/sphinx/util/osutil.py @@ -11,10 +11,10 @@ import os import re +import sys import time import errno import shutil -import sys from os import path # Errnos that we need. diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index 7bf768fac..8787a144e 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -26,6 +26,14 @@ except NameError: base_exception = Exception +# the ubiquitous "bytes" helper function +if sys.version_info > (3, 0): + def b(s): + return s.encode('utf-8') +else: + b = str + + try: any = any all = all diff --git a/tests/test_markup.py b/tests/test_markup.py index 6d6badbbc..092113bbe 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -10,7 +10,6 @@ """ import re -import sys from util import * @@ -18,15 +17,10 @@ from docutils import frontend, utils, nodes from docutils.parsers import rst from sphinx.util import texescape +from sphinx.util.pycompat import b from sphinx.writers.html import HTMLWriter, SmartyPantsHTMLTranslator from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator -if sys.version_info > (3, 0): - def b(s): - return s.encode('utf-8') -else: - b = str - def setup_module(): global app, settings, parser texescape.init() # otherwise done by the latex builder From 6af81b8506d3f5ab7eec86ad031bf89870fd6035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Tue, 25 May 2010 00:55:30 +0200 Subject: [PATCH 051/207] fix line length --- sphinx/util/osutil.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py index 250e75741..9943b207f 100644 --- a/sphinx/util/osutil.py +++ b/sphinx/util/osutil.py @@ -128,6 +128,7 @@ def make_filename(string): if sys.version_info < (3, 0): def ustrftime(format, *args): # strftime for unicode strings - return time.strftime(unicode(format).encode('utf-8'), *args).decode('utf-8') + return time.strftime(unicode(format).encode('utf-8'), *args) \ + .decode('utf-8') else: ustrftime = time.strftime From 7f2990455155c67b906b0cc93d9b20bbbf23d85f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 30 May 2010 02:07:53 +0200 Subject: [PATCH 052/207] Use .gettext() instead of .ugettext() on python3 --- sphinx/locale/__init__.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index b0b89720c..8df5f0060 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -8,6 +8,7 @@ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import sys import gettext import UserString @@ -178,8 +179,12 @@ pairindextypes = { translator = None -def _(message): - return translator.ugettext(message) +if sys.version_info >= (3, 0): + def _(message): + return translator.gettext(message) +else: + def _(message): + return translator.ugettext(message) def init(locale_dirs, language): global translator From ba02a69c1c9c7fa742e37f477cc99f8c8454c4f2 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:46:12 +0200 Subject: [PATCH 053/207] Nit. --- sphinx/locale/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index 8df5f0060..02958457b 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -8,6 +8,7 @@ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ + import sys import gettext import UserString From 918a509efc91189ab548533e29a839ec62d125c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 30 May 2010 02:28:57 +0200 Subject: [PATCH 054/207] Check if a string is not unicode as a workaround for 3.x --- sphinx/highlighting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py index f5ea859cb..c94405bc2 100644 --- a/sphinx/highlighting.py +++ b/sphinx/highlighting.py @@ -175,7 +175,7 @@ class PygmentsBridge(object): return True def highlight_block(self, source, lang, linenos=False, warn=None): - if isinstance(source, str): + if not isinstance(source, unicode): source = source.decode() if not pygments: return self.unhighlighted(source) From 23ef216a157c1da346ffc635c128692e367874d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 30 May 2010 15:15:57 +0200 Subject: [PATCH 055/207] encode source code for parsing only on python 2.x --- sphinx/highlighting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py index c94405bc2..c168aeffc 100644 --- a/sphinx/highlighting.py +++ b/sphinx/highlighting.py @@ -156,7 +156,7 @@ class PygmentsBridge(object): if sys.version_info >= (2, 5): src = 'from __future__ import with_statement\n' + src - if isinstance(src, unicode): + if sys.version_info < (3, 0) and isinstance(src, unicode): # Non-ASCII chars will only occur in string literals # and comments. If we wanted to give them to the parser # correctly, we'd have to find out the correct source From 31275a34c2a80c6243833f658a465c1a3338f4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 30 May 2010 17:51:14 +0200 Subject: [PATCH 056/207] Fix encoding in config test and open configs in binary mode to warn for possible encoding errors --- sphinx/config.py | 2 +- tests/test_config.py | 5 +++-- tests/util.py | 11 +++++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/sphinx/config.py b/sphinx/config.py index 2ec769871..07c3d63af 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -165,7 +165,7 @@ class Config(object): try: try: os.chdir(dirname) - f = open(config_file, 'U') + f = open(config_file, 'Ub') try: code = compile(f.read(), config_file, 'exec') finally: diff --git a/tests/test_config.py b/tests/test_config.py index cb4e11056..23d92e39c 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -84,11 +84,12 @@ def test_extension_values(app): @with_tempdir def test_errors_warnings(dir): # test the error for syntax errors in the config file - write_file(dir / 'conf.py', 'project = \n') + write_file(dir / 'conf.py', u'project = \n', 'ascii') raises_msg(ConfigError, 'conf.py', Config, dir, 'conf.py', {}, None) # test the warning for bytestrings with non-ascii content - write_file(dir / 'conf.py', '# -*- coding: latin-1\nproject = "foo\xe4"\n') + write_file(dir / 'conf.py', + u'# -*- coding: latin-1\nproject = "fooä"\n', 'latin-1') cfg = Config(dir, 'conf.py', {}, None) warned = [False] def warn(msg): diff --git a/tests/util.py b/tests/util.py index 1b24af0e2..2cf4a775b 100644 --- a/tests/util.py +++ b/tests/util.py @@ -11,6 +11,7 @@ import sys import StringIO import tempfile import shutil +from codecs import open try: from functools import wraps @@ -191,8 +192,14 @@ def with_tempdir(func): return new_func -def write_file(name, contents): - f = open(str(name), 'wb') +def write_file(name, contents, encoding=None): + if encoding is None: + mode = 'wb' + if isinstance(contents, unicode): + contents = contents.encode('ascii') + else: + mode = 'w' + f = open(str(name), 'wb', encoding=encoding) f.write(contents) f.close() From a153f84a171c9b6e87a10721491661c27b87cee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Tue, 1 Jun 2010 18:10:06 +0200 Subject: [PATCH 057/207] Replaced the path module with my own version --- tests/path.py | 980 +++----------------------------------------------- 1 file changed, 53 insertions(+), 927 deletions(-) diff --git a/tests/path.py b/tests/path.py index f27e58a9d..36ab3a9a0 100644 --- a/tests/path.py +++ b/tests/path.py @@ -1,952 +1,78 @@ -""" path.py - An object representing a path to a file or directory. - -Example: - -from path import path -d = path('/home/guido/bin') -for f in d.files('*.py'): - f.chmod(0755) - -This module requires Python 2.2 or later. - - -URL: http://www.jorendorff.com/articles/python/path -Author: Jason Orendorff (and others - see the url!) -Date: 9 Mar 2007 +#!/usr/bin/env python +# coding: utf-8 """ + path + ~~~~ + :copyright: Copyright 2010 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" +import os +import sys +import shutil +from codecs import open -# TODO -# - Tree-walking functions don't avoid symlink loops. Matt Harrison -# sent me a patch for this. -# - Bug in write_text(). It doesn't support Universal newline mode. -# - Better error message in listdir() when self isn't a -# directory. (On Windows, the error message really sucks.) -# - Make sure everything has a good docstring. -# - Add methods for regex find and replace. -# - guess_content_type() method? -# - Perhaps support arguments to touch(). -from __future__ import generators +FILESYSTEMENCODING = sys.getfilesystemencoding() or sys.getdefaultencoding() -import sys, warnings, os, fnmatch, glob, shutil, codecs -__version__ = '2.2' -__all__ = ['path'] - -# Platform-specific support for path.owner -if os.name == 'nt': - try: - import win32security - except ImportError: - win32security = None -else: - try: - import pwd - except ImportError: - pwd = None - -# Pre-2.3 support. Are unicode filenames supported? -_base = str -_getcwd = os.getcwd -try: - if os.path.supports_unicode_filenames: - _base = unicode - _getcwd = os.getcwdu -except AttributeError: - pass - -# Pre-2.3 workaround for basestring. -try: - basestring -except NameError: - basestring = (str, unicode) - -# Universal newline support -_textmode = 'r' -try: - file -except NameError: - _textmode = 'U' -else: - if hasattr(file, 'newlines'): - _textmode = 'U' - - -class TreeWalkWarning(Warning): - pass - -class path(_base): - """ Represents a filesystem path. - - For documentation on individual methods, consult their - counterparts in os.path. - """ - - # --- Special Python methods. - - def __repr__(self): - return 'path(%s)' % _base.__repr__(self) - - # Adding a path and a string yields a path. - def __add__(self, more): - try: - resultStr = _base.__add__(self, more) - except TypeError: #Python bug - resultStr = NotImplemented - if resultStr is NotImplemented: - return resultStr - return self.__class__(resultStr) - - def __radd__(self, other): - if isinstance(other, basestring): - return self.__class__(other.__add__(self)) - else: - return NotImplemented - - # The / operator joins paths. - def __div__(self, rel): - """ fp.__div__(rel) == fp / rel == fp.joinpath(rel) - - Join two path components, adding a separator character if - needed. - """ - return self.__class__(os.path.join(self, rel)) - - # Make the / operator work even when true division is enabled. - __truediv__ = __div__ - - def getcwd(cls): - """ Return the current working directory as a path object. """ - return cls(_getcwd()) - getcwd = classmethod(getcwd) - - - # --- Operations on path strings. - - isabs = os.path.isabs - def abspath(self): return self.__class__(os.path.abspath(self)) - def normcase(self): return self.__class__(os.path.normcase(self)) - def normpath(self): return self.__class__(os.path.normpath(self)) - def realpath(self): return self.__class__(os.path.realpath(self)) - def expanduser(self): return self.__class__(os.path.expanduser(self)) - def expandvars(self): return self.__class__(os.path.expandvars(self)) - def dirname(self): return self.__class__(os.path.dirname(self)) - basename = os.path.basename - - def expand(self): - """ Clean up a filename by calling expandvars(), - expanduser(), and normpath() on it. - - This is commonly everything needed to clean up a filename - read from a configuration file, for example. - """ - return self.expandvars().expanduser().normpath() - - def _get_namebase(self): - base, ext = os.path.splitext(self.name) - return base - - def _get_ext(self): - f, ext = os.path.splitext(_base(self)) - return ext - - def _get_drive(self): - drive, r = os.path.splitdrive(self) - return self.__class__(drive) - - parent = property( - dirname, None, None, - """ This path's parent directory, as a new path object. - - For example, path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib') - """) - - name = property( - basename, None, None, - """ The name of this file or directory without the full path. - - For example, path('/usr/local/lib/libpython.so').name == 'libpython.so' - """) - - namebase = property( - _get_namebase, None, None, - """ The same as path.name, but with one file extension stripped off. - - For example, path('/home/guido/python.tar.gz').name == 'python.tar.gz', - but path('/home/guido/python.tar.gz').namebase == 'python.tar' - """) - - ext = property( - _get_ext, None, None, - """ The file extension, for example '.py'. """) - - drive = property( - _get_drive, None, None, - """ The drive specifier, for example 'C:'. - This is always empty on systems that don't use drive specifiers. - """) - - def splitpath(self): - """ p.splitpath() -> Return (p.parent, p.name). """ - parent, child = os.path.split(self) - return self.__class__(parent), child - - def splitdrive(self): - """ p.splitdrive() -> Return (p.drive, ). - - Split the drive specifier from this path. If there is - no drive specifier, p.drive is empty, so the return value - is simply (path(''), p). This is always the case on Unix. - """ - drive, rel = os.path.splitdrive(self) - return self.__class__(drive), rel - - def splitext(self): - """ p.splitext() -> Return (p.stripext(), p.ext). - - Split the filename extension from this path and return - the two parts. Either part may be empty. - - The extension is everything from '.' to the end of the - last path segment. This has the property that if - (a, b) == p.splitext(), then a + b == p. - """ - filename, ext = os.path.splitext(self) - return self.__class__(filename), ext - - def stripext(self): - """ p.stripext() -> Remove one file extension from the path. - - For example, path('/home/guido/python.tar.gz').stripext() - returns path('/home/guido/python.tar'). - """ - return self.splitext()[0] - - if hasattr(os.path, 'splitunc'): - def splitunc(self): - unc, rest = os.path.splitunc(self) - return self.__class__(unc), rest - - def _get_uncshare(self): - unc, r = os.path.splitunc(self) - return self.__class__(unc) - - uncshare = property( - _get_uncshare, None, None, - """ The UNC mount point for this path. - This is empty for paths on local drives. """) - - def joinpath(self, *args): - """ Join two or more path components, adding a separator - character (os.sep) if needed. Returns a new path - object. - """ - return self.__class__(os.path.join(self, *args)) - - def splitall(self): - r""" Return a list of the path components in this path. - - The first item in the list will be a path. Its value will be - either os.curdir, os.pardir, empty, or the root directory of - this path (for example, '/' or 'C:\\'). The other items in - the list will be strings. - - path.path.joinpath(*result) will yield the original path. - """ - parts = [] - loc = self - while loc != os.curdir and loc != os.pardir: - prev = loc - loc, child = prev.splitpath() - if loc == prev: - break - parts.append(child) - parts.append(loc) - parts.reverse() - return parts - - def relpath(self): - """ Return this path as a relative path, - based from the current working directory. - """ - cwd = self.__class__(os.getcwd()) - return cwd.relpathto(self) - - def relpathto(self, dest): - """ Return a relative path from self to dest. - - If there is no relative path from self to dest, for example if - they reside on different drives in Windows, then this returns - dest.abspath(). - """ - origin = self.abspath() - dest = self.__class__(dest).abspath() - - orig_list = origin.normcase().splitall() - # Don't normcase dest! We want to preserve the case. - dest_list = dest.splitall() - - if orig_list[0] != os.path.normcase(dest_list[0]): - # Can't get here from there. - return dest - - # Find the location where the two paths start to differ. - i = 0 - for start_seg, dest_seg in zip(orig_list, dest_list): - if start_seg != os.path.normcase(dest_seg): - break - i += 1 - - # Now i is the point where the two paths diverge. - # Need a certain number of "os.pardir"s to work up - # from the origin to the point of divergence. - segments = [os.pardir] * (len(orig_list) - i) - # Need to add the diverging part of dest_list. - segments += dest_list[i:] - if len(segments) == 0: - # If they happen to be identical, use os.curdir. - relpath = os.curdir - else: - relpath = os.path.join(*segments) - return self.__class__(relpath) - - # --- Listing, searching, walking, and matching - - def listdir(self, pattern=None): - """ D.listdir() -> List of items in this directory. - - Use D.files() or D.dirs() instead if you want a listing - of just files or just subdirectories. - - The elements of the list are path objects. - - With the optional 'pattern' argument, this only lists - items whose names match the given pattern. - """ - names = os.listdir(self) - if pattern is not None: - names = fnmatch.filter(names, pattern) - return [self / child for child in names] - - def dirs(self, pattern=None): - """ D.dirs() -> List of this directory's subdirectories. - - The elements of the list are path objects. - This does not walk recursively into subdirectories - (but see path.walkdirs). - - With the optional 'pattern' argument, this only lists - directories whose names match the given pattern. For - example, d.dirs('build-*'). - """ - return [p for p in self.listdir(pattern) if p.isdir()] - - def files(self, pattern=None): - """ D.files() -> List of the files in this directory. - - The elements of the list are path objects. - This does not walk into subdirectories (see path.walkfiles). - - With the optional 'pattern' argument, this only lists files - whose names match the given pattern. For example, - d.files('*.pyc'). - """ - - return [p for p in self.listdir(pattern) if p.isfile()] - - def walk(self, pattern=None, errors='strict'): - """ D.walk() -> iterator over files and subdirs, recursively. - - The iterator yields path objects naming each child item of - this directory and its descendants. This requires that - D.isdir(). - - This performs a depth-first traversal of the directory tree. - Each directory is returned just before all its children. - - The errors= keyword argument controls behavior when an - error occurs. The default is 'strict', which causes an - exception. The other allowed values are 'warn', which - reports the error via warnings.warn(), and 'ignore'. - """ - if errors not in ('strict', 'warn', 'ignore'): - raise ValueError("invalid errors parameter") - - try: - childList = self.listdir() - except Exception: - if errors == 'ignore': - return - elif errors == 'warn': - warnings.warn( - "Unable to list directory '%s': %s" - % (self, sys.exc_info()[1]), - TreeWalkWarning) - return - else: - raise - - for child in childList: - if pattern is None or child.fnmatch(pattern): - yield child - try: - isdir = child.isdir() - except Exception: - if errors == 'ignore': - isdir = False - elif errors == 'warn': - warnings.warn( - "Unable to access '%s': %s" - % (child, sys.exc_info()[1]), - TreeWalkWarning) - isdir = False +class path(str): + if sys.version_info < (3, 0): + def __new__(cls, s, encoding=FILESYSTEMENCODING, errors=None): + if isinstance(s, unicode): + if errors is None: + s = s.encode(encoding) else: - raise + s = s.encode(encoding, errors=errors) + return str.__new__(cls, s) + return str.__new__(cls, s) - if isdir: - for item in child.walk(pattern, errors): - yield item + @property + def parent(self): + return self.__class__(os.path.dirname(self)) - def walkdirs(self, pattern=None, errors='strict'): - """ D.walkdirs() -> iterator over subdirs, recursively. + def abspath(self): + return self.__class__(os.path.abspath(self)) - With the optional 'pattern' argument, this yields only - directories whose names match the given pattern. For - example, mydir.walkdirs('*test') yields only directories - with names ending in 'test'. + def isdir(self): + return os.path.isdir(self) - The errors= keyword argument controls behavior when an - error occurs. The default is 'strict', which causes an - exception. The other allowed values are 'warn', which - reports the error via warnings.warn(), and 'ignore'. - """ - if errors not in ('strict', 'warn', 'ignore'): - raise ValueError("invalid errors parameter") + def isfile(self): + return os.path.isfile(self) + def rmtree(self, ignore_errors=False, onerror=None): + shutil.rmtree(self, ignore_errors=ignore_errors, onerror=onerror) + + def copytree(self, destination, symlinks=False, ignore=None): + shutil.copytree(self, destination, symlinks=symlinks, ignore=ignore) + + def unlink(self): + os.unlink(self) + + def write_text(self, text, **kwargs): + f = open(self, 'w', **kwargs) try: - dirs = self.dirs() - except Exception: - if errors == 'ignore': - return - elif errors == 'warn': - warnings.warn( - "Unable to list directory '%s': %s" - % (self, sys.exc_info()[1]), - TreeWalkWarning) - return - else: - raise + f.write(text) + finally: + f.close() - for child in dirs: - if pattern is None or child.fnmatch(pattern): - yield child - for subsubdir in child.walkdirs(pattern, errors): - yield subsubdir - - def walkfiles(self, pattern=None, errors='strict'): - """ D.walkfiles() -> iterator over files in D, recursively. - - The optional argument, pattern, limits the results to files - with names that match the pattern. For example, - mydir.walkfiles('*.tmp') yields only files with the .tmp - extension. - """ - if errors not in ('strict', 'warn', 'ignore'): - raise ValueError("invalid errors parameter") - - try: - childList = self.listdir() - except Exception: - if errors == 'ignore': - return - elif errors == 'warn': - warnings.warn( - "Unable to list directory '%s': %s" - % (self, sys.exc_info()[1]), - TreeWalkWarning) - return - else: - raise - - for child in childList: - try: - isfile = child.isfile() - isdir = not isfile and child.isdir() - except: - if errors == 'ignore': - continue - elif errors == 'warn': - warnings.warn( - "Unable to access '%s': %s" - % (self, sys.exc_info()[1]), - TreeWalkWarning) - continue - else: - raise - - if isfile: - if pattern is None or child.fnmatch(pattern): - yield child - elif isdir: - for f in child.walkfiles(pattern, errors): - yield f - - def fnmatch(self, pattern): - """ Return True if self.name matches the given pattern. - - pattern - A filename pattern with wildcards, - for example '*.py'. - """ - return fnmatch.fnmatch(self.name, pattern) - - def glob(self, pattern): - """ Return a list of path objects that match the pattern. - - pattern - a path relative to this directory, with wildcards. - - For example, path('/users').glob('*/bin/*') returns a list - of all the files users have in their bin directories. - """ - cls = self.__class__ - return [cls(s) for s in glob.glob(_base(self / pattern))] - - - # --- Reading or writing an entire file at once. - - def open(self, mode='r'): - """ Open this file. Return a file object. """ - return open(self, mode) - - def bytes(self): - """ Open this file, read all bytes, return them as a string. """ - f = self.open('rb') + def text(self, **kwargs): + f = open(self, mode='U', **kwargs) try: return f.read() finally: f.close() - def write_bytes(self, bytes, append=False): - """ Open this file and write the given bytes to it. - - Default behavior is to overwrite any existing file. - Call p.write_bytes(bytes, append=True) to append instead. - """ - if append: - mode = 'ab' - else: - mode = 'wb' - f = self.open(mode) - try: - f.write(bytes) - finally: - f.close() - - def text(self, encoding=None, errors='strict'): - r""" Open this file, read it in, return the content as a string. - - This uses 'U' mode in Python 2.3 and later, so '\r\n' and '\r' - are automatically translated to '\n'. - - Optional arguments: - - encoding - The Unicode encoding (or character set) of - the file. If present, the content of the file is - decoded and returned as a unicode object; otherwise - it is returned as an 8-bit str. - errors - How to handle Unicode errors; see help(str.decode) - for the options. Default is 'strict'. - """ - if encoding is None: - # 8-bit - f = self.open(_textmode) - try: - return f.read() - finally: - f.close() - else: - # Unicode - f = codecs.open(self, 'r', encoding, errors) - # (Note - Can't use 'U' mode here, since codecs.open - # doesn't support 'U' mode, even in Python 2.3.) - try: - t = f.read() - finally: - f.close() - return (t.replace(u'\r\n', u'\n') - .replace(u'\r\x85', u'\n') - .replace(u'\r', u'\n') - .replace(u'\x85', u'\n') - .replace(u'\u2028', u'\n')) - - def write_text(self, text, encoding=None, errors='strict', linesep=os.linesep, append=False): - r""" Write the given text to this file. - - The default behavior is to overwrite any existing file; - to append instead, use the 'append=True' keyword argument. - - There are two differences between path.write_text() and - path.write_bytes(): newline handling and Unicode handling. - See below. - - Parameters: - - - text - str/unicode - The text to be written. - - - encoding - str - The Unicode encoding that will be used. - This is ignored if 'text' isn't a Unicode string. - - - errors - str - How to handle Unicode encoding errors. - Default is 'strict'. See help(unicode.encode) for the - options. This is ignored if 'text' isn't a Unicode - string. - - - linesep - keyword argument - str/unicode - The sequence of - characters to be used to mark end-of-line. The default is - os.linesep. You can also specify None; this means to - leave all newlines as they are in 'text'. - - - append - keyword argument - bool - Specifies what to do if - the file already exists (True: append to the end of it; - False: overwrite it.) The default is False. - - - --- Newline handling. - - write_text() converts all standard end-of-line sequences - ('\n', '\r', and '\r\n') to your platform's default end-of-line - sequence (see os.linesep; on Windows, for example, the - end-of-line marker is '\r\n'). - - If you don't like your platform's default, you can override it - using the 'linesep=' keyword argument. If you specifically want - write_text() to preserve the newlines as-is, use 'linesep=None'. - - This applies to Unicode text the same as to 8-bit text, except - there are three additional standard Unicode end-of-line sequences: - u'\x85', u'\r\x85', and u'\u2028'. - - (This is slightly different from when you open a file for - writing with fopen(filename, "w") in C or file(filename, 'w') - in Python.) - - - --- Unicode - - If 'text' isn't Unicode, then apart from newline handling, the - bytes are written verbatim to the file. The 'encoding' and - 'errors' arguments are not used and must be omitted. - - If 'text' is Unicode, it is first converted to bytes using the - specified 'encoding' (or the default encoding if 'encoding' - isn't specified). The 'errors' argument applies only to this - conversion. - - """ - if isinstance(text, unicode): - if linesep is not None: - # Convert all standard end-of-line sequences to - # ordinary newline characters. - text = (text.replace(u'\r\n', u'\n') - .replace(u'\r\x85', u'\n') - .replace(u'\r', u'\n') - .replace(u'\x85', u'\n') - .replace(u'\u2028', u'\n')) - text = text.replace(u'\n', linesep) - if encoding is None: - encoding = sys.getdefaultencoding() - bytes = text.encode(encoding, errors) - else: - # It is an error to specify an encoding if 'text' is - # an 8-bit string. - assert encoding is None - - if linesep is not None: - text = (text.replace('\r\n', '\n') - .replace('\r', '\n')) - bytes = text.replace('\n', linesep) - - self.write_bytes(bytes, append) - - def lines(self, encoding=None, errors='strict', retain=True): - r""" Open this file, read all lines, return them in a list. - - Optional arguments: - encoding - The Unicode encoding (or character set) of - the file. The default is None, meaning the content - of the file is read as 8-bit characters and returned - as a list of (non-Unicode) str objects. - errors - How to handle Unicode errors; see help(str.decode) - for the options. Default is 'strict' - retain - If true, retain newline characters; but all newline - character combinations ('\r', '\n', '\r\n') are - translated to '\n'. If false, newline characters are - stripped off. Default is True. - - This uses 'U' mode in Python 2.3 and later. - """ - if encoding is None and retain: - f = self.open(_textmode) - try: - return f.readlines() - finally: - f.close() - else: - return self.text(encoding, errors).splitlines(retain) - - def write_lines(self, lines, encoding=None, errors='strict', - linesep=os.linesep, append=False): - r""" Write the given lines of text to this file. - - By default this overwrites any existing file at this path. - - This puts a platform-specific newline sequence on every line. - See 'linesep' below. - - lines - A list of strings. - - encoding - A Unicode encoding to use. This applies only if - 'lines' contains any Unicode strings. - - errors - How to handle errors in Unicode encoding. This - also applies only to Unicode strings. - - linesep - The desired line-ending. This line-ending is - applied to every line. If a line already has any - standard line ending ('\r', '\n', '\r\n', u'\x85', - u'\r\x85', u'\u2028'), that will be stripped off and - this will be used instead. The default is os.linesep, - which is platform-dependent ('\r\n' on Windows, '\n' on - Unix, etc.) Specify None to write the lines as-is, - like file.writelines(). - - Use the keyword argument append=True to append lines to the - file. The default is to overwrite the file. Warning: - When you use this with Unicode data, if the encoding of the - existing data in the file is different from the encoding - you specify with the encoding= parameter, the result is - mixed-encoding data, which can really confuse someone trying - to read the file later. - """ - if append: - mode = 'ab' - else: - mode = 'wb' - f = self.open(mode) - try: - for line in lines: - isUnicode = isinstance(line, unicode) - if linesep is not None: - # Strip off any existing line-end and add the - # specified linesep string. - if isUnicode: - if line[-2:] in (u'\r\n', u'\x0d\x85'): - line = line[:-2] - elif line[-1:] in (u'\r', u'\n', - u'\x85', u'\u2028'): - line = line[:-1] - else: - if line[-2:] == '\r\n': - line = line[:-2] - elif line[-1:] in ('\r', '\n'): - line = line[:-1] - line += linesep - if isUnicode: - if encoding is None: - encoding = sys.getdefaultencoding() - line = line.encode(encoding, errors) - f.write(line) - finally: - f.close() - - # --- Methods for querying the filesystem. - - exists = os.path.exists - isdir = os.path.isdir - isfile = os.path.isfile - islink = os.path.islink - ismount = os.path.ismount - - if hasattr(os.path, 'samefile'): - samefile = os.path.samefile - - getatime = os.path.getatime - atime = property( - getatime, None, None, - """ Last access time of the file. """) - - getmtime = os.path.getmtime - mtime = property( - getmtime, None, None, - """ Last-modified time of the file. """) - - if hasattr(os.path, 'getctime'): - getctime = os.path.getctime - ctime = property( - getctime, None, None, - """ Creation time of the file. """) - - getsize = os.path.getsize - size = property( - getsize, None, None, - """ Size of the file, in bytes. """) - - if hasattr(os, 'access'): - def access(self, mode): - """ Return true if current user has access to this path. - - mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK - """ - return os.access(self, mode) - - def stat(self): - """ Perform a stat() system call on this path. """ - return os.stat(self) - - def lstat(self): - """ Like path.stat(), but do not follow symbolic links. """ - return os.lstat(self) - - def get_owner(self): - r""" Return the name of the owner of this file or directory. - - This follows symbolic links. - - On Windows, this returns a name of the form ur'DOMAIN\User Name'. - On Windows, a group can own a file or directory. - """ - if os.name == 'nt': - if win32security is None: - raise Exception("path.owner requires win32all to be installed") - desc = win32security.GetFileSecurity( - self, win32security.OWNER_SECURITY_INFORMATION) - sid = desc.GetSecurityDescriptorOwner() - account, domain, typecode = win32security.LookupAccountSid(None, sid) - return domain + u'\\' + account - else: - if pwd is None: - raise NotImplementedError("path.owner is not implemented on this platform.") - st = self.stat() - return pwd.getpwuid(st.st_uid).pw_name - - owner = property( - get_owner, None, None, - """ Name of the owner of this file or directory. """) - - if hasattr(os, 'statvfs'): - def statvfs(self): - """ Perform a statvfs() system call on this path. """ - return os.statvfs(self) - - if hasattr(os, 'pathconf'): - def pathconf(self, name): - return os.pathconf(self, name) - - - # --- Modifying operations on files and directories - - def utime(self, times): - """ Set the access and modified times of this file. """ - os.utime(self, times) - - def chmod(self, mode): - os.chmod(self, mode) - - if hasattr(os, 'chown'): - def chown(self, uid, gid): - os.chown(self, uid, gid) - - def rename(self, new): - os.rename(self, new) - - def renames(self, new): - os.renames(self, new) - - - # --- Create/delete operations on directories - - def mkdir(self, mode=0777): - os.mkdir(self, mode) + def exists(self): + return os.path.exists(self) def makedirs(self, mode=0777): os.makedirs(self, mode) - def rmdir(self): - os.rmdir(self) + def joinpath(self, *args): + return self.__class__(os.path.join(self, *map(self.__class__, args))) - def removedirs(self): - os.removedirs(self) - - - # --- Modifying operations on files - - def touch(self): - """ Set the access/modified times of this file to the current time. - Create the file if it does not exist. - """ - fd = os.open(self, os.O_WRONLY | os.O_CREAT, 0666) - os.close(fd) - os.utime(self, None) - - def remove(self): - os.remove(self) - - def unlink(self): - os.unlink(self) - - - # --- Links - - if hasattr(os, 'link'): - def link(self, newpath): - """ Create a hard link at 'newpath', pointing to this file. """ - os.link(self, newpath) - - if hasattr(os, 'symlink'): - def symlink(self, newlink): - """ Create a symbolic link at 'newlink', pointing here. """ - os.symlink(self, newlink) - - if hasattr(os, 'readlink'): - def readlink(self): - """ Return the path to which this symbolic link points. - - The result may be an absolute or a relative path. - """ - return self.__class__(os.readlink(self)) - - def readlinkabs(self): - """ Return the path to which this symbolic link points. - - The result is always an absolute path. - """ - p = self.readlink() - if p.isabs(): - return p - else: - return (self.parent / p).abspath() - - - # --- High-level functions from shutil - - copyfile = shutil.copyfile - copymode = shutil.copymode - copystat = shutil.copystat - copy = shutil.copy - copy2 = shutil.copy2 - copytree = shutil.copytree - if hasattr(shutil, 'move'): - move = shutil.move - rmtree = shutil.rmtree - - - # --- Special stuff from os - - if hasattr(os, 'chroot'): - def chroot(self): - os.chroot(self) - - if hasattr(os, 'startfile'): - def startfile(self): - os.startfile(self) + __div__ = __truediv__ = joinpath + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, str.__repr__(self)) From 2683b839d5b701e4e7aa46efe1e57fed804afd93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Tue, 1 Jun 2010 19:59:38 +0200 Subject: [PATCH 058/207] Added a movetree method to the path object to make it more consistent along with documentation for every method of it. --- tests/path.py | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/tests/path.py b/tests/path.py index 36ab3a9a0..dccdac3ab 100644 --- a/tests/path.py +++ b/tests/path.py @@ -17,6 +17,9 @@ FILESYSTEMENCODING = sys.getfilesystemencoding() or sys.getdefaultencoding() class path(str): + """ + Represents a path which behaves like a string. + """ if sys.version_info < (3, 0): def __new__(cls, s, encoding=FILESYSTEMENCODING, errors=None): if isinstance(s, unicode): @@ -29,27 +32,103 @@ class path(str): @property def parent(self): + """ + The name of the directory the file or directory is in. + """ return self.__class__(os.path.dirname(self)) def abspath(self): + """ + Returns the absolute path. + """ return self.__class__(os.path.abspath(self)) + def isabs(self): + """ + Returns ``True`` if the path is absolute. + """ + return os.path.isabs(self) + def isdir(self): + """ + Returns ``True`` if the path is a directory. + """ return os.path.isdir(self) def isfile(self): + """ + Returns ``True`` if the path is a file. + """ return os.path.isfile(self) + def islink(self): + """ + Returns ``True`` if the path is a symbolic link. + """ + return os.path.islink(self) + + def ismount(self): + """ + Returns ``True`` if the path is a mount point. + """ + return os.path.ismount(self) + def rmtree(self, ignore_errors=False, onerror=None): + """ + Removes the file or directory and any files or directories it may + contain. + + :param ignore_errors: + If ``True`` errors are silently ignored, otherwise an exception + is raised in case an error occurs. + + :param onerror: + A callback which gets called with the arguments `func`, `path` and + `exc_info`. `func` is one of :func:`os.listdir`, :func:`os.remove` + or :func:`os.rmdir`. `path` is the argument to the function which + caused it to fail and `exc_info` is a tuple as returned by + :func:`sys.exc_info`. + """ shutil.rmtree(self, ignore_errors=ignore_errors, onerror=onerror) def copytree(self, destination, symlinks=False, ignore=None): + """ + Recursively copy a directory to the given `destination`. If the given + `destination` does not exist it will be created. + + :param symlinks: + If ``True`` symbolic links in the source tree result in symbolic + links in the destination tree otherwise the contents of the files + pointed to by the symbolic links are copied. + + :param ignore: + A callback which gets called with the path of the directory being + copied and a list of paths as returned by :func:`os.listdir`. + """ shutil.copytree(self, destination, symlinks=symlinks, ignore=ignore) + def movetree(self, destination): + """ + Recursively move the file or directory to the given `destination` + similar to the Unix "mv" command. + + If the `destination` is a file it may be overwritten depending on the + :func:`os.rename` semantics. + """ + shutil.move(self, destination) + + move = movetree + def unlink(self): + """ + Removes a file. + """ os.unlink(self) def write_text(self, text, **kwargs): + """ + Writes the given `text` to the file. + """ f = open(self, 'w', **kwargs) try: f.write(text) @@ -57,6 +136,9 @@ class path(str): f.close() def text(self, **kwargs): + """ + Returns the text in the file. + """ f = open(self, mode='U', **kwargs) try: return f.read() @@ -64,12 +146,28 @@ class path(str): f.close() def exists(self): + """ + Returns ``True`` if the path exist. + """ return os.path.exists(self) + def lexists(self): + """ + Returns ``True`` if the path exists unless it is a broken symbolic + link. + """ + return os.path.lexists(self) + def makedirs(self, mode=0777): + """ + Recursively create directories. + """ os.makedirs(self, mode) def joinpath(self, *args): + """ + Joins the path with the argument given and returns the result. + """ return self.__class__(os.path.join(self, *map(self.__class__, args))) __div__ = __truediv__ = joinpath From 87bbe8ddd50deb29eead624ff91356ede8a3fea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 6 Jun 2010 23:13:06 +0200 Subject: [PATCH 059/207] don't use string.strip anymore --- tests/test_autosummary.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_autosummary.py b/tests/test_autosummary.py index 7e3093676..20fb06e0e 100644 --- a/tests/test_autosummary.py +++ b/tests/test_autosummary.py @@ -9,8 +9,6 @@ :license: BSD, see LICENSE for details. """ -import string - from util import * from sphinx.ext.autosummary import mangle_signature @@ -27,7 +25,7 @@ def test_mangle_signature(): (a, b, c='foobar()', d=123) :: (a, b[, c, d]) """ - TEST = [map(string.strip, x.split("::")) for x in TEST.split("\n") + TEST = [map(lambda x: x.strip(), x.split("::")) for x in TEST.split("\n") if '::' in x] for inp, outp in TEST: res = mangle_signature(inp).strip().replace(u"\u00a0", " ") From 434da2a4fbd48e437d77b10a70e927ab83309e1c Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:51:57 +0200 Subject: [PATCH 060/207] Use next() function instead of iter.next(). --- sphinx/pycode/__init__.py | 3 ++- sphinx/util/pycompat.py | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py index cb9c08878..ef92297c7 100644 --- a/sphinx/pycode/__init__.py +++ b/sphinx/pycode/__init__.py @@ -18,6 +18,7 @@ from sphinx.errors import PycodeError from sphinx.pycode import nodes from sphinx.pycode.pgen2 import driver, token, tokenize, parse, literals from sphinx.util import get_module_source +from sphinx.util.pycompat import next from sphinx.util.docstrings import prepare_docstring, prepare_commentdoc @@ -279,7 +280,7 @@ class ModuleAnalyzer(object): result[fullname] = (dtype, startline, endline) expect_indent = False if tok in ('def', 'class'): - name = tokeniter.next()[1] + name = next(tokeniter)[1] namespace.append(name) fullname = '.'.join(namespace) stack.append((tok, fullname, spos[0], indent)) diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index 8787a144e..365cd703c 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -34,6 +34,14 @@ else: b = str +try: + next +except NameError: + # this is on Python 2, where the method is called "next" + def next(iterator): + return iterator.next() + + try: any = any all = all From 563f506d1b72188c711df57ad85954869e842550 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:08:44 +0200 Subject: [PATCH 061/207] Fix assignment. --- sphinx/util/pycompat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index 365cd703c..0725545da 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -35,7 +35,7 @@ else: try: - next + next = next except NameError: # this is on Python 2, where the method is called "next" def next(iterator): From 57272142991d7e26fa6bcadb60175a1bd6a23e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 7 Jun 2010 00:44:09 +0200 Subject: [PATCH 062/207] open file in binary mode to get byte strings on python3 --- sphinx/directives/code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py index 0647daf09..54d8edf19 100644 --- a/sphinx/directives/code.py +++ b/sphinx/directives/code.py @@ -119,7 +119,7 @@ class LiteralInclude(Directive): encoding = self.options.get('encoding', env.config.source_encoding) codec_info = codecs.lookup(encoding) try: - f = codecs.StreamReaderWriter(open(fn, 'U'), + f = codecs.StreamReaderWriter(open(fn, 'Ub'), codec_info[2], codec_info[3], 'strict') lines = f.readlines() f.close() From 817e1dd4cda3c23868632c7493c3b764d7bc34ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 7 Jun 2010 01:34:01 +0200 Subject: [PATCH 063/207] fixed file handling and parsing in intersphinx so it properly handles encodings --- sphinx/ext/intersphinx.py | 27 +++++++++++++++++++-------- tests/test_intersphinx.py | 17 ++++++++++------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index fb1f0e4ff..31de2315c 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -28,12 +28,20 @@ import time import zlib import urllib2 import posixpath +import codecs +import sys from os import path from docutils import nodes from sphinx.builders.html import INVENTORY_FILENAME +if sys.version_info >= (3, 0): + def b(s): + return s.encode('utf-8') +else: + b = str + handlers = [urllib2.ProxyHandler(), urllib2.HTTPRedirectHandler(), urllib2.HTTPHandler()] try: @@ -43,11 +51,14 @@ except NameError: urllib2.install_opener(urllib2.build_opener(*handlers)) +UTF8StreamReader = codecs.lookup('utf-8')[2] + def read_inventory_v1(f, uri, join): + f = UTF8StreamReader(f) invdata = {} line = f.next() - projname = line.rstrip()[11:].decode('utf-8') + projname = line.rstrip()[11:] line = f.next() version = line.rstrip()[11:] for line in f: @@ -70,25 +81,25 @@ def read_inventory_v2(f, uri, join, bufsize=16*1024): projname = line.rstrip()[11:].decode('utf-8') line = f.readline() version = line.rstrip()[11:].decode('utf-8') - line = f.readline() + line = f.readline().decode('utf-8') if 'zlib' not in line: raise ValueError def read_chunks(): decompressor = zlib.decompressobj() - for chunk in iter(lambda: f.read(bufsize), ''): + for chunk in iter(lambda: f.read(bufsize), b('')): yield decompressor.decompress(chunk) yield decompressor.flush() def split_lines(iter): - buf = '' + buf = b('') for chunk in iter: buf += chunk - lineend = buf.find('\n') + lineend = buf.find(b('\n')) while lineend != -1: yield buf[:lineend].decode('utf-8') buf = buf[lineend+1:] - lineend = buf.find('\n') + lineend = buf.find(b('\n')) assert not buf for line in split_lines(read_chunks()): @@ -111,13 +122,13 @@ def fetch_inventory(app, uri, inv): if inv.find('://') != -1: f = urllib2.urlopen(inv) else: - f = open(path.join(app.srcdir, inv)) + f = open(path.join(app.srcdir, inv), 'rb') except Exception, err: app.warn('intersphinx inventory %r not fetchable due to ' '%s: %s' % (inv, err.__class__, err)) return try: - line = f.readline().rstrip() + line = f.readline().rstrip().decode('utf-8') try: if line == '# Sphinx inventory version 1': invdata = read_inventory_v1(f, uri, join) diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py index 8b6547e54..4f70bd205 100644 --- a/tests/test_intersphinx.py +++ b/tests/test_intersphinx.py @@ -11,7 +11,10 @@ import zlib import posixpath -from cStringIO import StringIO +try: + from io import BytesIO +except ImportError: + from cStringIO import StringIO as BytesIO from docutils import nodes @@ -28,23 +31,23 @@ inventory_v1 = '''\ # Version: 1.0 module mod foo.html module.cls class foo.html -''' +'''.encode('utf-8') inventory_v2 = '''\ # Sphinx inventory version 2 # Project: foo # Version: 2.0 # The remainder of this file is compressed with zlib. -''' + zlib.compress('''\ +'''.encode('utf-8') + zlib.compress('''\ module1 py:module 0 foo.html#module-module1 Long Module desc module2 py:module 0 foo.html#module-$ - module1.func py:function 1 sub/foo.html#$ - CFunc c:function 2 cfunc.html#CFunc - -''') +'''.encode('utf-8')) def test_read_inventory_v1(): - f = StringIO(inventory_v1) + f = BytesIO(inventory_v1) f.readline() invdata = read_inventory_v1(f, '/util', posixpath.join) assert invdata['py:module']['module'] == \ @@ -54,12 +57,12 @@ def test_read_inventory_v1(): def test_read_inventory_v2(): - f = StringIO(inventory_v2) + f = BytesIO(inventory_v2) f.readline() invdata1 = read_inventory_v2(f, '/util', posixpath.join) # try again with a small buffer size to test the chunking algorithm - f = StringIO(inventory_v2) + f = BytesIO(inventory_v2) f.readline() invdata2 = read_inventory_v2(f, '/util', posixpath.join, bufsize=5) From 2737ec4dc9ab633f38765e9553a85043fe6fe49b Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:54:24 +0200 Subject: [PATCH 064/207] Use b() from pycompat. --- sphinx/ext/intersphinx.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 31de2315c..07ee24e38 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -26,21 +26,16 @@ import time import zlib +import codecs import urllib2 import posixpath -import codecs -import sys from os import path from docutils import nodes from sphinx.builders.html import INVENTORY_FILENAME +from sphinx.util.pycompat import b -if sys.version_info >= (3, 0): - def b(s): - return s.encode('utf-8') -else: - b = str handlers = [urllib2.ProxyHandler(), urllib2.HTTPRedirectHandler(), urllib2.HTTPHandler()] From bade03c8243cbdf7296126c3a1c54bccccc354ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 12 Jun 2010 15:16:57 +0200 Subject: [PATCH 065/207] Copy converted tests to build/lib/tests not build/lib/test --- tests/run.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run.py b/tests/run.py index 5fd30d62b..f384fe267 100755 --- a/tests/run.py +++ b/tests/run.py @@ -14,10 +14,10 @@ import sys from os import path, chdir if sys.version_info >= (3,): - print('Copying and converting sources to build/lib/test...') + print('Copying and converting sources to build/lib/tests...') from distutils.util import copydir_run_2to3 testroot = path.dirname(__file__) or '.' - newroot = path.join(testroot, path.pardir, 'build', 'lib', 'test') + newroot = path.join(testroot, path.pardir, 'build', 'lib', 'tests') copydir_run_2to3(testroot, newroot) # switch to the converted dir so nose tests the right tests chdir(newroot) From 79a958b867c2941d68fbb9bd594a1c26f511003c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 12 Jun 2010 20:21:14 +0200 Subject: [PATCH 066/207] Remove unnecessary code --- tests/path.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/path.py b/tests/path.py index dccdac3ab..28a8c22af 100644 --- a/tests/path.py +++ b/tests/path.py @@ -21,12 +21,9 @@ class path(str): Represents a path which behaves like a string. """ if sys.version_info < (3, 0): - def __new__(cls, s, encoding=FILESYSTEMENCODING, errors=None): + def __new__(cls, s, encoding=FILESYSTEMENCODING, errors='strict'): if isinstance(s, unicode): - if errors is None: - s = s.encode(encoding) - else: - s = s.encode(encoding, errors=errors) + s = s.encode(encoding, errors=errors) return str.__new__(cls, s) return str.__new__(cls, s) From f0c316f6c57632dbdd2a13cb7021db90854138f9 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:55:39 +0200 Subject: [PATCH 067/207] Pass document name as bytes. --- sphinx/builders/html.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 8d96c146c..c5f7312a4 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -35,7 +35,7 @@ from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \ movefile, ustrftime, copyfile from sphinx.util.nodes import inline_all_toctrees from sphinx.util.matching import patmatch, compile_matchers -from sphinx.util.pycompat import any +from sphinx.util.pycompat import any, b from sphinx.errors import SphinxError from sphinx.locale import _ from sphinx.search import js_index @@ -199,7 +199,7 @@ class StandaloneHTMLBuilder(Builder): """Utility: Render a lone doctree node.""" if node is None: return {'fragment': ''} - doc = new_document('') + doc = new_document(b('')) doc.append(node) if self._publisher is None: From ddefaff0b7144d81e3fcedc03d563becc99f90cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 13 Jun 2010 23:08:32 +0200 Subject: [PATCH 068/207] fix a unboundlocalerror occuring with python3 --- sphinx/ext/doctest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index 9d681f904..62fbfdff4 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -149,14 +149,14 @@ class TestCode(object): class SphinxDocTestRunner(doctest.DocTestRunner): def summarize(self, out, verbose=None): - io = StringIO.StringIO() + string_io = StringIO.StringIO() old_stdout = sys.stdout - sys.stdout = io + sys.stdout = string_io try: res = doctest.DocTestRunner.summarize(self, verbose) finally: sys.stdout = old_stdout - out(io.getvalue()) + out(string_io.getvalue()) return res def _DocTestRunner__patched_linecache_getlines(self, filename, From 4534657f3e37a8aa59e5135f9a9f6d18f1ab6aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Tue, 15 Jun 2010 23:16:33 +0200 Subject: [PATCH 069/207] update distribute_setup.py from http://python-distribute.org/distribute_setup.py --- distribute_setup.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/distribute_setup.py b/distribute_setup.py index 4f7bd08c0..37117b34e 100644 --- a/distribute_setup.py +++ b/distribute_setup.py @@ -46,7 +46,7 @@ except ImportError: args = [quote(arg) for arg in args] return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 -DEFAULT_VERSION = "0.6.12" +DEFAULT_VERSION = "0.6.13" DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" SETUPTOOLS_FAKED_VERSION = "0.6c11" @@ -227,7 +227,6 @@ def _no_sandbox(function): return __no_sandbox -@_no_sandbox def _patch_file(path, content): """Will backup the file then patch it""" existing_content = open(path).read() @@ -244,6 +243,7 @@ def _patch_file(path, content): f.close() return True +_patch_file = _no_sandbox(_patch_file) def _same_content(path, content): return open(path).read() == content @@ -254,7 +254,6 @@ def _rename_path(path): os.rename(path, new_name) return new_name -@_no_sandbox def _remove_flat_installation(placeholder): if not os.path.isdir(placeholder): log.warn('Unkown installation at %s', placeholder) @@ -288,13 +287,13 @@ def _remove_flat_installation(placeholder): 'Setuptools distribution', element) return True +_remove_flat_installation = _no_sandbox(_remove_flat_installation) def _after_install(dist): log.warn('After install bootstrap.') placeholder = dist.get_command_obj('install').install_purelib _create_fake_setuptools_pkg_info(placeholder) -@_no_sandbox def _create_fake_setuptools_pkg_info(placeholder): if not placeholder or not os.path.exists(placeholder): log.warn('Could not find the install location') @@ -322,7 +321,8 @@ def _create_fake_setuptools_pkg_info(placeholder): finally: f.close() -@_no_sandbox +_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info) + def _patch_egg_dir(path): # let's check if it's already patched pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') @@ -341,6 +341,7 @@ def _patch_egg_dir(path): f.close() return True +_patch_egg_dir = _no_sandbox(_patch_egg_dir) def _before_install(): log.warn('Before install bootstrap.') @@ -360,8 +361,8 @@ def _under_prefix(location): if len(args) > index: top_dir = args[index+1] return location.startswith(top_dir) - elif option == '--user' and USER_SITE is not None: - return location.startswith(USER_SITE) + if arg == '--user' and USER_SITE is not None: + return location.startswith(USER_SITE) return True @@ -420,6 +421,9 @@ def _fake_setuptools(): def _relaunch(): log.warn('Relaunching...') # we have to relaunch the process + # pip marker to avoid a relaunch bug + if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']: + sys.argv[0] = 'setup.py' args = [sys.executable] + sys.argv sys.exit(subprocess.call(args)) From bf14a7c362e97127ca6ab60d962e2731c0f337fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Wed, 16 Jun 2010 23:20:30 +0200 Subject: [PATCH 070/207] Encode strings after they have been formatted --- sphinx/builders/html.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index c5f7312a4..4e07acf78 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -727,10 +727,12 @@ class StandaloneHTMLBuilder(Builder): self.info(bold('dumping object inventory... '), nonl=True) f = open(path.join(self.outdir, INVENTORY_FILENAME), 'wb') try: - f.write('# Sphinx inventory version 2\n') - f.write('# Project: %s\n' % self.config.project.encode('utf-8')) - f.write('# Version: %s\n' % self.config.version.encode('utf-8')) - f.write('# The remainder of this file is compressed using zlib.\n') + f.write((u'# Sphinx inventory version 2\n' + u'# Project: %s\n' + u'# Version: %s\n' + u'# The remainder of this file is compressed using zlib.\n' + % (self.config.project, self.config.version))\ + .encode('utf-8')) compressor = zlib.compressobj(9) for domainname, domain in self.env.domains.iteritems(): for name, dispname, type, docname, anchor, prio in \ @@ -742,11 +744,9 @@ class StandaloneHTMLBuilder(Builder): if dispname == name: dispname = u'-' f.write(compressor.compress( - '%s %s:%s %s %s %s\n' % (name.encode('utf-8'), - domainname.encode('utf-8'), - type.encode('utf-8'), prio, - uri.encode('utf-8'), - dispname.encode('utf-8')))) + (u'%s %s:%s %s %s %s\n' % (name, domainname, type, prio, + uri, dispname))\ + .encode('utf-8'))) f.write(compressor.flush()) finally: f.close() From 7add1755985875eb79b2bc724cbbfde23d685c61 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 18:58:18 +0200 Subject: [PATCH 071/207] Fix code formatting. --- sphinx/builders/html.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 4e07acf78..0b39d38e7 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -731,8 +731,8 @@ class StandaloneHTMLBuilder(Builder): u'# Project: %s\n' u'# Version: %s\n' u'# The remainder of this file is compressed using zlib.\n' - % (self.config.project, self.config.version))\ - .encode('utf-8')) + % (self.config.project, self.config.version) + ).encode('utf-8')) compressor = zlib.compressobj(9) for domainname, domain in self.env.domains.iteritems(): for name, dispname, type, docname, anchor, prio in \ @@ -744,9 +744,9 @@ class StandaloneHTMLBuilder(Builder): if dispname == name: dispname = u'-' f.write(compressor.compress( - (u'%s %s:%s %s %s %s\n' % (name, domainname, type, prio, - uri, dispname))\ - .encode('utf-8'))) + (u'%s %s:%s %s %s %s\n' % (name, domainname, type, + prio, uri, dispname) + ).encode('utf-8'))) f.write(compressor.flush()) finally: f.close() From 9e56fac893192187c033fbdf5e008459bc4b3ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Thu, 17 Jun 2010 05:26:19 +0200 Subject: [PATCH 072/207] Decode templates using utf-8 as jinja2 requires that for python3. This change will very likely cause problems for some people --- sphinx/util/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index 2ef420ed1..ec48009f4 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -18,6 +18,7 @@ import tempfile import posixpath import traceback from os import path +from codecs import open import docutils from docutils.utils import relative_path @@ -140,8 +141,8 @@ def copy_static_entry(source, targetdir, builder, context={}, target = path.join(targetdir, path.basename(source)) if source.lower().endswith('_t') and builder.templates: # templated! - fsrc = open(source, 'rb') - fdst = open(target[:-2], 'wb') + fsrc = open(source, 'r', encoding='utf-8') + fdst = open(target[:-2], 'w', encoding='utf-8') fdst.write(builder.templates.render_string(fsrc.read(), context)) fsrc.close() fdst.close() From 24a1512293a09f865c16a28e4d42580a4589e1d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Thu, 17 Jun 2010 05:38:22 +0200 Subject: [PATCH 073/207] Removed duplicated code --- sphinx/builders/qthelp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py index ffc52334c..53c7a9b15 100644 --- a/sphinx/builders/qthelp.py +++ b/sphinx/builders/qthelp.py @@ -230,7 +230,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder): link = node['refuri'] title = escape(node.astext()).replace('"','"') item = section_template % {'title': title, 'ref': link} - item = ' '*4*indentlevel + item.encode('ascii', 'xmlcharrefreplace') + item = u' ' * 4 * indentlevel + item parts.append(item.encode('ascii', 'xmlcharrefreplace')) elif isinstance(node, nodes.bullet_list): for subnode in node: From 579528e0b3182e30ee00577b1a753d20533e6976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Thu, 17 Jun 2010 05:47:44 +0200 Subject: [PATCH 074/207] Fixed error caused by mixing of string types --- sphinx/builders/qthelp.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py index 53c7a9b15..e86f19217 100644 --- a/sphinx/builders/qthelp.py +++ b/sphinx/builders/qthelp.py @@ -130,8 +130,16 @@ class QtHelpBuilder(StandaloneHTMLBuilder): for indexname, indexcls, content, collapse in self.domain_indices: item = section_template % {'title': indexcls.localname, 'ref': '%s.html' % indexname} - sections.append(' '*4*4 + item) - sections = '\n'.join(sections) + sections.append((' ' * 4 * 4 + item).encode('utf-8')) + # sections may be unicode strings or byte strings, we have to make sure + # they are all byte strings before joining them + new_sections = [] + for section in sections: + if isinstance(section, unicode): + new_sections.append(section.encode('utf-8')) + else: + new_sections.append(section) + sections = u'\n'.encode('utf-8').join(new_sections) # keywords keywords = [] From b1f29495ab10503e8c942d4f49d4b195d325b23f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Thu, 17 Jun 2010 05:51:24 +0200 Subject: [PATCH 075/207] Don't mix string types when writing to a stream --- sphinx/builders/htmlhelp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py index 538f4c848..e3a58e724 100644 --- a/sphinx/builders/htmlhelp.py +++ b/sphinx/builders/htmlhelp.py @@ -258,7 +258,8 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder): def write_index(title, refs, subitems): def write_param(name, value): item = ' \n' % (name, value) - f.write(item.encode('ascii', 'xmlcharrefreplace')) + f.write(item.encode('ascii', 'xmlcharrefreplace') + .decode('ascii')) title = cgi.escape(title) f.write('
  • \n') write_param('Keyword', title) From 38d11bbe147fc0f1b3d8d0df0eb8558f189f2029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Thu, 17 Jun 2010 05:56:06 +0200 Subject: [PATCH 076/207] the sphinx.search.js_index is now able to load and dump data from binary streams --- sphinx/search.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sphinx/search.py b/sphinx/search.py index 729b63b2a..6d5a0614d 100644 --- a/sphinx/search.py +++ b/sphinx/search.py @@ -58,10 +58,13 @@ class _JavaScriptIndex(object): return jsdump.loads(data) def dump(self, data, f): - f.write(self.dumps(data)) + f.write(self.dumps(data).encode('utf-8')) def load(self, f): - return self.loads(f.read()) + data = f.read() + if isinstance(data, unicode): + return self.loads(data) + return self.loads(data.decode('utf-8')) js_index = _JavaScriptIndex() From 2ce553a71aa2a98789e008c0b77edbe2b259c5d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 19 Jun 2010 16:38:52 +0200 Subject: [PATCH 077/207] Fix test to respect the new .truncate() behavior --- tests/test_application.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_application.py b/tests/test_application.py index 3d287a57c..d1154863c 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -45,9 +45,11 @@ def test_output(): app = TestApp(status=status, warning=warnings) try: status.truncate(0) # __init__ writes to status + status.seek(0) app.info("Nothing here...") assert status.getvalue() == "Nothing here...\n" status.truncate(0) + status.seek(0) app.info("Nothing here...", True) assert status.getvalue() == "Nothing here..." From 1f5c4e6c9c2385498ae7e10f5aeea4844e142c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 19 Jun 2010 21:50:00 +0200 Subject: [PATCH 078/207] make doctest work with python2 and python3 --- tests/root/conf.py | 2 +- tests/root/doctest.txt | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/root/conf.py b/tests/root/conf.py index 2b6d6a9af..b47341899 100644 --- a/tests/root/conf.py +++ b/tests/root/conf.py @@ -22,7 +22,7 @@ copyright = '2010, Georg Brandl & Team' version = '0.6' release = '0.6alpha1' today_fmt = '%B %d, %Y' -#unused_docs = [] +# unused_docs = [] exclude_patterns = ['_build', '**/excluded.*'] keep_warnings = True pygments_style = 'sphinx' diff --git a/tests/root/doctest.txt b/tests/root/doctest.txt index 35cdd589c..6ac0b2863 100644 --- a/tests/root/doctest.txt +++ b/tests/root/doctest.txt @@ -30,7 +30,7 @@ Special directives .. testcode:: - print 1+1 + print(1+1) .. testoutput:: @@ -50,30 +50,30 @@ Special directives .. testsetup:: * - from math import floor + from math import factorial .. doctest:: - >>> floor(1.2) - 1.0 + >>> factorial(1) + 1 .. testcode:: - print floor(1.2) + print(factorial(1)) .. testoutput:: - 1.0 + 1 - >>> floor(1.2) - 1.0 + >>> factorial(1) + 1 * options for testcode/testoutput blocks .. testcode:: :hide: - print 'Output text.' + print('Output text.') .. testoutput:: :hide: @@ -85,36 +85,36 @@ Special directives .. testsetup:: group1 - from math import ceil + from math import trunc - ``ceil`` is now known in "group1", but not in others. + ``trunc`` is now known in "group1", but not in others. .. doctest:: group1 - >>> ceil(0.8) - 1.0 + >>> trunc(1.1) + 1 .. doctest:: group2 - >>> ceil(0.8) + >>> trunc(1.1) Traceback (most recent call last): ... - NameError: name 'ceil' is not defined + NameError: name 'trunc' is not defined Interleaving testcode/testoutput: .. testcode:: group1 - print ceil(0.8) + print(factorial(3)) .. testcode:: group2 - print floor(0.8) + print(factorial(4)) .. testoutput:: group1 - 1.0 + 6 .. testoutput:: group2 - 0.0 + 24 From 0780242572de30cb19b524898d37afd313fc66c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 19 Jun 2010 19:58:28 +0200 Subject: [PATCH 079/207] Fixed the coverage extension test as well as the coverage extension itself for python3 --- sphinx/ext/coverage.py | 5 ++++- tests/path.py | 27 +++++++++++++++++++++++++++ tests/test_coverage.py | 2 +- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py index 4924d30b0..f41820e2a 100644 --- a/sphinx/ext/coverage.py +++ b/sphinx/ext/coverage.py @@ -173,8 +173,11 @@ class CoverageBuilder(Builder): attrs = [] + for attr_name in dir(obj): + attr = getattr(obj, attr_name) for attr_name, attr in inspect.getmembers( - obj, inspect.ismethod): + obj, lambda x: inspect.ismethod(x) or \ + inspect.isfunction(x)): if attr_name[0] == '_': # starts with an underscore, ignore it continue diff --git a/tests/path.py b/tests/path.py index 28a8c22af..df96bce45 100644 --- a/tests/path.py +++ b/tests/path.py @@ -142,6 +142,33 @@ class path(str): finally: f.close() + def bytes(self): + """ + Returns the bytes in the file. + """ + f = open(self, mode='rb') + try: + return f.read() + finally: + f.close() + + def write_bytes(self, bytes, append=False): + """ + Writes the given `bytes` to the file. + + :param append: + If ``True`` given `bytes` are added at the end of the file. + """ + if append: + mode = 'ab' + else: + mode = 'wb' + f = open(self, mode=mode) + try: + f.write(bytes) + finally: + f.close() + def exists(self): """ Returns ``True`` if the path exist. diff --git a/tests/test_coverage.py b/tests/test_coverage.py index 1262ebf5b..cb8316358 100644 --- a/tests/test_coverage.py +++ b/tests/test_coverage.py @@ -33,7 +33,7 @@ def test_build(app): assert 'api.h' in c_undoc assert ' * Py_SphinxTest' in c_undoc - undoc_py, undoc_c = pickle.loads((app.outdir / 'undoc.pickle').text()) + undoc_py, undoc_c = pickle.loads((app.outdir / 'undoc.pickle').bytes()) assert len(undoc_c) == 1 # the key is the full path to the header file, which isn't testable assert undoc_c.values()[0] == [('function', 'Py_SphinxTest')] From 24d8ce473430ed65111df88428c7152013ba1fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 20 Jun 2010 18:50:22 +0200 Subject: [PATCH 080/207] make sure to encode strings passed to md5 --- sphinx/builders/html.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 0b39d38e7..5a3e9bb3d 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -146,8 +146,9 @@ class StandaloneHTMLBuilder(Builder): cfgdict = dict((name, self.config[name]) for (name, desc) in self.config.values.iteritems() if desc[1] == 'html') - self.config_hash = md5(str(cfgdict)).hexdigest() - self.tags_hash = md5(str(sorted(self.tags))).hexdigest() + self.config_hash = md5(unicode(cfgdict).encode('ascii')).hexdigest() + self.tags_hash = md5(unicode(sorted(self.tags)).encode('ascii')) \ + .hexdigest() old_config_hash = old_tags_hash = '' try: fp = open(path.join(self.outdir, '.buildinfo')) From eaa3cb4f1fef44737b7f59537efc3b28676e8f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 20 Jun 2010 18:54:19 +0200 Subject: [PATCH 081/207] Use utf-8 instead of ascii to encode strings for hashing --- sphinx/builders/html.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 5a3e9bb3d..16afd3479 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -146,8 +146,8 @@ class StandaloneHTMLBuilder(Builder): cfgdict = dict((name, self.config[name]) for (name, desc) in self.config.values.iteritems() if desc[1] == 'html') - self.config_hash = md5(unicode(cfgdict).encode('ascii')).hexdigest() - self.tags_hash = md5(unicode(sorted(self.tags)).encode('ascii')) \ + self.config_hash = md5(unicode(cfgdict).encode('utf-8')).hexdigest() + self.tags_hash = md5(unicode(sorted(self.tags)).encode('utf-8')) \ .hexdigest() old_config_hash = old_tags_hash = '' try: From 710a7d75a18e2db712e0f0689f5ce6d5cc74ba13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 20 Jun 2010 19:34:49 +0200 Subject: [PATCH 082/207] Fix warning for bytestrings with non-ascii content for python3 --- sphinx/config.py | 12 +++++++++--- tests/test_config.py | 9 +++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/sphinx/config.py b/sphinx/config.py index 07c3d63af..7ec5cfe80 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -11,12 +11,18 @@ import os import re +import sys from os import path from sphinx.errors import ConfigError from sphinx.util.osutil import make_filename -nonascii_re = re.compile(r'[\x80-\xff]') +nonascii_re = re.compile(ur'[\x80-\xff]'.encode('ascii')) + +try: + bytes +except NameError: + bytes = str class Config(object): @@ -187,10 +193,10 @@ class Config(object): # check all string values for non-ASCII characters in bytestrings, # since that can result in UnicodeErrors all over the place for name, value in self._raw_config.iteritems(): - if isinstance(value, str) and nonascii_re.search(value): + if isinstance(value, bytes) and nonascii_re.search(value): warn('the config value %r is set to a string with non-ASCII ' 'characters; this can lead to Unicode errors occurring. ' - 'Please use Unicode strings, e.g. u"Content".' % name) + 'Please use Unicode strings, e.g. %r.' % (name, u'Content')) def init_values(self): config = self._raw_config diff --git a/tests/test_config.py b/tests/test_config.py index 23d92e39c..ecf90f609 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -9,6 +9,7 @@ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import sys from util import * @@ -88,8 +89,12 @@ def test_errors_warnings(dir): raises_msg(ConfigError, 'conf.py', Config, dir, 'conf.py', {}, None) # test the warning for bytestrings with non-ascii content - write_file(dir / 'conf.py', - u'# -*- coding: latin-1\nproject = "fooä"\n', 'latin-1') + # bytestrings with non-ascii content are a syntax error in python3 so we + # skip the test there + if sys.version_info >= (3, 0): + return + write_file(dir / 'conf.py', u'# -*- coding: latin-1\nproject = "fooä"\n', + 'latin-1') cfg = Config(dir, 'conf.py', {}, None) warned = [False] def warn(msg): From fc1003839861c02f6181260c1236f75e36ad1d4b Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:13:25 +0200 Subject: [PATCH 083/207] Move bytes to pycompat. --- sphinx/config.py | 8 ++------ sphinx/util/pycompat.py | 5 +++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/sphinx/config.py b/sphinx/config.py index 7ec5cfe80..210bb9e2b 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -16,13 +16,9 @@ from os import path from sphinx.errors import ConfigError from sphinx.util.osutil import make_filename +from sphinx.util.pycompat import bytes, b -nonascii_re = re.compile(ur'[\x80-\xff]'.encode('ascii')) - -try: - bytes -except NameError: - bytes = str +nonascii_re = re.compile(b(r'[\x80-\xff]')) class Config(object): diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index 0725545da..624749fc3 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -41,6 +41,11 @@ except NameError: def next(iterator): return iterator.next() +try: + bytes = bytes +except NameError: + bytes = str + try: any = any From 20a21ed35a05cb1019affab4a6601ae7478853c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 20 Jun 2010 22:24:00 +0200 Subject: [PATCH 084/207] fix line length --- sphinx/config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sphinx/config.py b/sphinx/config.py index 210bb9e2b..273bb97d9 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -192,7 +192,8 @@ class Config(object): if isinstance(value, bytes) and nonascii_re.search(value): warn('the config value %r is set to a string with non-ASCII ' 'characters; this can lead to Unicode errors occurring. ' - 'Please use Unicode strings, e.g. %r.' % (name, u'Content')) + 'Please use Unicode strings, e.g. %r.' % (name, u'Content') + ) def init_values(self): config = self._raw_config From 98b6073a7e85f91db1cd54de1709ba5d763ffb21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 20 Jun 2010 22:39:38 +0200 Subject: [PATCH 085/207] Fixed warnings in python3 --- sphinx/environment.py | 2 +- tests/test_build_html.py | 5 +++++ tests/test_build_latex.py | 3 +++ tests/util.py | 7 ++++++- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/sphinx/environment.py b/sphinx/environment.py index 21994a746..fd171d443 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -80,7 +80,7 @@ class WarningStream(object): self.warnfunc = warnfunc def write(self, text): if text.strip(): - self.warnfunc(text, None, '') + self.warnfunc(text.strip(), None, '') class NoUri(Exception): diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 4dee513ae..65c1840ea 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -12,6 +12,7 @@ import os import re import htmlentitydefs +import sys from StringIO import StringIO try: @@ -60,6 +61,10 @@ def tail_check(check): return checker +if sys.version_info >= (3, 0): + ENV_WARNINGS = remove_unicode_literals(ENV_WARNINGS) + HTML_WARNINGS = remove_unicode_literals(HTML_WARNINGS) + HTML_XPATH = { 'images.html': [ (".//img[@src='_images/img.png']", ''), diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 4405395a0..6c1ccad9b 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -32,6 +32,9 @@ None:None: WARNING: no matching candidate for image URI u'foo.\\*' WARNING: invalid pair index entry u'' """ +if sys.version_info >= (3, 0): + LATEX_WARNINGS = remove_unicode_literals(LATEX_WARNINGS) + @with_app(buildername='latex', warning=latex_warnfile, cleanenv=True) def test_latex(app): diff --git a/tests/util.py b/tests/util.py index 2cf4a775b..950ea23f5 100644 --- a/tests/util.py +++ b/tests/util.py @@ -11,6 +11,7 @@ import sys import StringIO import tempfile import shutil +import re from codecs import open try: @@ -32,7 +33,7 @@ __all__ = [ 'raises', 'raises_msg', 'Struct', 'ListOutput', 'TestApp', 'with_app', 'gen_with_app', 'path', 'with_tempdir', 'write_file', - 'sprint', + 'sprint', 'remove_unicode_literals', ] @@ -206,3 +207,7 @@ def write_file(name, contents, encoding=None): def sprint(*args): sys.stderr.write(' '.join(map(str, args)) + '\n') + +_unicode_literals_re = re.compile(r'u(".*")|u(\'.*\')') +def remove_unicode_literals(s): + return _unicode_literals_re.sub(lambda x: x.group(1) or x.group(2), s) From 3002eb391f4dc3e4f478e693a4bebec65ab461ec Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:15:04 +0200 Subject: [PATCH 086/207] Make string contents nongreedy. --- tests/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/util.py b/tests/util.py index 950ea23f5..b81e15b6e 100644 --- a/tests/util.py +++ b/tests/util.py @@ -208,6 +208,6 @@ def write_file(name, contents, encoding=None): def sprint(*args): sys.stderr.write(' '.join(map(str, args)) + '\n') -_unicode_literals_re = re.compile(r'u(".*")|u(\'.*\')') +_unicode_literals_re = re.compile(r'u(".*?")|u(\'.*?\')') def remove_unicode_literals(s): return _unicode_literals_re.sub(lambda x: x.group(1) or x.group(2), s) From 37db093428112925a7dc86ce7b33a7cbe53227ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Tue, 22 Jun 2010 22:49:58 +0200 Subject: [PATCH 087/207] the test suite now runs on ubuntu, hopefully also debian and other system --- tests/run.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/run.py b/tests/run.py index f384fe267..59a3ffa5b 100755 --- a/tests/run.py +++ b/tests/run.py @@ -11,13 +11,14 @@ """ import sys -from os import path, chdir +from os import path, chdir, listdir if sys.version_info >= (3,): print('Copying and converting sources to build/lib/tests...') from distutils.util import copydir_run_2to3 testroot = path.dirname(__file__) or '.' - newroot = path.join(testroot, path.pardir, 'build', 'lib', 'tests') + newroot = path.join(testroot, path.pardir, 'build') + newroot = path.join(newroot, listdir(newroot)[0], 'tests') copydir_run_2to3(testroot, newroot) # switch to the converted dir so nose tests the right tests chdir(newroot) From a7ca488a8ece7ac83d02937d3ee3b97f481ddc1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 10 Jul 2010 19:47:32 +0200 Subject: [PATCH 088/207] Removed XMLParser._fixtext which fixes several errors in the test suite --- tests/etree13/ElementTree.py | 17 ++++------------- tests/test_build_html.py | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/tests/etree13/ElementTree.py b/tests/etree13/ElementTree.py index d37325049..e50ad640c 100644 --- a/tests/etree13/ElementTree.py +++ b/tests/etree13/ElementTree.py @@ -1425,13 +1425,6 @@ class XMLParser(object): err.position = value.lineno, value.offset raise err - def _fixtext(self, text): - # convert text string to ascii, if possible - try: - return text.encode("ascii") - except UnicodeError: - return text - def _fixname(self, key): # expand qname, and convert name string to ascii, if possible try: @@ -1440,30 +1433,28 @@ class XMLParser(object): name = key if "}" in name: name = "{" + name - self._names[key] = name = self._fixtext(name) + self._names[key] return name def _start(self, tag, attrib_in): fixname = self._fixname - fixtext = self._fixtext tag = fixname(tag) attrib = {} for key, value in attrib_in.items(): - attrib[fixname(key)] = fixtext(value) + attrib[fixname(key)] = value return self.target.start(tag, attrib) def _start_list(self, tag, attrib_in): fixname = self._fixname - fixtext = self._fixtext tag = fixname(tag) attrib = {} if attrib_in: for i in range(0, len(attrib_in), 2): - attrib[fixname(attrib_in[i])] = fixtext(attrib_in[i+1]) + attrib[fixname(attrib_in[i])] = attrib_in[i+1] return self.target.start(tag, attrib) def _data(self, text): - return self.target.data(self._fixtext(text)) + return self.target.data(text) def _end(self, tag): return self.target.end(self._fixname(tag)) diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 65c1840ea..5e3a20188 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -258,7 +258,7 @@ class NslessParser(ET.XMLParser): br = name.find('}') if br > 0: name = name[br+1:] - self._names[key] = name = self._fixtext(name) + self._names[key] = name return name From 839cc5aaeb166d5ef2f310459f742456a160db19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 11 Jul 2010 00:57:08 +0200 Subject: [PATCH 089/207] Revert changes from the last commit which caused problems with 2.x --- tests/etree13/ElementTree.py | 17 +++++++++++++---- tests/test_build_html.py | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/etree13/ElementTree.py b/tests/etree13/ElementTree.py index e50ad640c..d37325049 100644 --- a/tests/etree13/ElementTree.py +++ b/tests/etree13/ElementTree.py @@ -1425,6 +1425,13 @@ class XMLParser(object): err.position = value.lineno, value.offset raise err + def _fixtext(self, text): + # convert text string to ascii, if possible + try: + return text.encode("ascii") + except UnicodeError: + return text + def _fixname(self, key): # expand qname, and convert name string to ascii, if possible try: @@ -1433,28 +1440,30 @@ class XMLParser(object): name = key if "}" in name: name = "{" + name - self._names[key] + self._names[key] = name = self._fixtext(name) return name def _start(self, tag, attrib_in): fixname = self._fixname + fixtext = self._fixtext tag = fixname(tag) attrib = {} for key, value in attrib_in.items(): - attrib[fixname(key)] = value + attrib[fixname(key)] = fixtext(value) return self.target.start(tag, attrib) def _start_list(self, tag, attrib_in): fixname = self._fixname + fixtext = self._fixtext tag = fixname(tag) attrib = {} if attrib_in: for i in range(0, len(attrib_in), 2): - attrib[fixname(attrib_in[i])] = attrib_in[i+1] + attrib[fixname(attrib_in[i])] = fixtext(attrib_in[i+1]) return self.target.start(tag, attrib) def _data(self, text): - return self.target.data(text) + return self.target.data(self._fixtext(text)) def _end(self, tag): return self.target.end(self._fixname(tag)) diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 5e3a20188..65c1840ea 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -258,7 +258,7 @@ class NslessParser(ET.XMLParser): br = name.find('}') if br > 0: name = name[br+1:] - self._names[key] = name + self._names[key] = name = self._fixtext(name) return name From 23af2ea8755557677445276ea89b31119e1ae5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 11 Jul 2010 01:05:27 +0200 Subject: [PATCH 090/207] Provided a working fix for the remaining errors in the test suite --- tests/etree13/ElementTree.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/etree13/ElementTree.py b/tests/etree13/ElementTree.py index d37325049..f459c7f8f 100644 --- a/tests/etree13/ElementTree.py +++ b/tests/etree13/ElementTree.py @@ -1425,12 +1425,16 @@ class XMLParser(object): err.position = value.lineno, value.offset raise err - def _fixtext(self, text): - # convert text string to ascii, if possible - try: - return text.encode("ascii") - except UnicodeError: + if sys.version_info >= (3, 0): + def _fixtext(self, text): return text + else: + def _fixtext(self, text): + # convert text string to ascii, if possible + try: + return text.encode("ascii") + except UnicodeError: + return text def _fixname(self, key): # expand qname, and convert name string to ascii, if possible From 7acfe972a4a6dec95bdfed667a6efca943176b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 11 Jul 2010 11:32:16 +0200 Subject: [PATCH 091/207] Fixed test_env.test_images test for python3 --- tests/test_env.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test_env.py b/tests/test_env.py index 4ecbaac49..124ed08cd 100644 --- a/tests/test_env.py +++ b/tests/test_env.py @@ -8,6 +8,7 @@ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +import sys from util import * @@ -54,8 +55,10 @@ def test_images(): app._warning.reset() htmlbuilder = StandaloneHTMLBuilder(app) htmlbuilder.post_process_images(tree) - assert "no matching candidate for image URI u'foo.*'" in \ - app._warning.content[-1] + image_uri_message = "no matching candidate for image URI u'foo.*'" + if sys.version_info >= (3, 0): + image_uri_message = remove_unicode_literals(image_uri_message) + assert image_uri_message in app._warning.content[-1] assert set(htmlbuilder.images.keys()) == \ set(['subdir/img.png', 'img.png', 'subdir/simg.png', 'svgimg.svg']) assert set(htmlbuilder.images.values()) == \ @@ -64,8 +67,7 @@ def test_images(): app._warning.reset() latexbuilder = LaTeXBuilder(app) latexbuilder.post_process_images(tree) - assert "no matching candidate for image URI u'foo.*'" in \ - app._warning.content[-1] + assert image_uri_message in app._warning.content[-1] assert set(latexbuilder.images.keys()) == \ set(['subdir/img.png', 'subdir/simg.png', 'img.png', 'img.pdf', 'svgimg.pdf']) From ddeb627cef1d5ed566e9d6af242833b01f0590ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 11 Jul 2010 12:24:50 +0200 Subject: [PATCH 092/207] Don't use (in this case) unnecessary python2 unicode literals --- tests/root/literal.inc | 2 +- tests/test_build_html.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/root/literal.inc b/tests/root/literal.inc index d5b9890c9..694f15ed9 100644 --- a/tests/root/literal.inc +++ b/tests/root/literal.inc @@ -1,7 +1,7 @@ # Literally included file using Python highlighting # -*- coding: utf-8 -*- -foo = u"Including Unicode characters: üöä" +foo = "Including Unicode characters: üöä" class Foo: pass diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 65c1840ea..3ca2c757f 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -232,7 +232,7 @@ if pygments: (".//div[@class='inc-lines highlight-text']//pre", r'^class Foo:\n pass\nclass Bar:\n$'), (".//div[@class='inc-startend highlight-text']//pre", - ur'^foo = u"Including Unicode characters: üöä"\n$'), + ur'^foo = "Including Unicode characters: üöä"\n$'), (".//div[@class='inc-preappend highlight-text']//pre", r'(?m)^START CODE$'), (".//div[@class='inc-pyobj-dedent highlight-python']//span", From 5248e8d3158b79b552585827c22b71f482cfe086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 24 Jul 2010 13:04:30 +0200 Subject: [PATCH 093/207] Added Python 3.x support to the changelog again under a different section (1.1) --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index b247543f8..573b4edd6 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,8 @@ Release 1.0.1 (Jul 27, 2010) * Fix hyperrefs in object descriptions for LaTeX. + * Added Python 3.x support. + Release 1.0 (Jul 23, 2010) ========================== From 14ca77a1d4e1dd7f43a5f90d29e596f481bed29c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Tue, 27 Jul 2010 21:01:27 +0200 Subject: [PATCH 094/207] Fixed the JSONHTMLBuilder --- sphinx/builders/html.py | 49 ++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 16afd3479..064f9d2f1 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -754,6 +754,10 @@ class StandaloneHTMLBuilder(Builder): self.info('done') def dump_search_index(self): + # NOTE: If you change this code you have to change it in + # JSONHTMLBuilder.dump_search_index as well because the code is + # mostly copied from here for reasons explained in a comment in + # said method. self.info(bold('dumping search index... '), nonl=True) self.indexer.prune(self.env.all_docs) searchindexfn = path.join(self.outdir, self.searchindex_filename) @@ -938,6 +942,13 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder): return docname[:-5] # up to sep return docname + SEP + def dump_context(self, context, filename): + f = open(filename, 'wb') + try: + self.implementation.dump(context, f, 2) + finally: + f.close() + def handle_page(self, pagename, ctx, templatename='page.html', outfilename=None, event_arg=None): ctx['current_page_name'] = pagename @@ -951,11 +962,7 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder): ctx, event_arg) ensuredir(path.dirname(outfilename)) - f = open(outfilename, 'wb') - try: - self.implementation.dump(ctx, f, 2) - finally: - f.close() + self.dump_context(ctx, outfilename) # if there is a source file, copy the source file for the # "show source" link @@ -968,11 +975,7 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder): def handle_finish(self): # dump the global context outfilename = path.join(self.outdir, self.globalcontext_filename) - f = open(outfilename, 'wb') - try: - self.implementation.dump(self.globalcontext, f, 2) - finally: - f.close() + self.dump_context(self.globalcontext, outfilename) # super here to dump the search index StandaloneHTMLBuilder.handle_finish(self) @@ -1019,3 +1022,29 @@ class JSONHTMLBuilder(SerializingHTMLBuilder): 'The module simplejson (or json in Python >= 2.6) ' 'is not available. The JSONHTMLBuilder builder will not work.') SerializingHTMLBuilder.init(self) + + def dump_context(self, context, filename): + # json operates entirely on "unicode" but the filesystem doesn't so we + # have to specify an encoding. + f = codecs.open(filename, 'w', encoding='utf-8') + try: + self.implementation.dump(context, f, 2) + finally: + f.close() + + def dump_search_index(self): + # this code is nearly completely copied from the super class, in which + # this method was initially defined, the only difference is that we + # specify an encoding for the file. + self.info(bold('dumping search index...'), nonl=True) + self.indexer.prune(self.env.all_docs) + searchindexfn = path.join(self.outdir, self.searchindex_filename) + # first write to a temporary file, so that if dumping fails, + # the existing index won't be overwritten + f = codecs.open(searchindexfn + '.tmp', 'w', encoding='utf-8') + try: + self.indexer.dump(f, self.indexer_format) + finally: + f.close() + movefile(searchindexfn + '.tmp', searchindexfn) + self.info('done') From bd2eb1e085882bbe97d449ac1879de40b50f458b Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:24:48 +0200 Subject: [PATCH 095/207] Declare if serializers/indexers dump unicode or bytes. Removes duplication of methods. --- sphinx/builders/html.py | 47 +++++++++++++---------------------------- sphinx/search.py | 7 ++---- 2 files changed, 17 insertions(+), 37 deletions(-) diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 064f9d2f1..5a7d49cd0 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -63,6 +63,7 @@ class StandaloneHTMLBuilder(Builder): out_suffix = '.html' link_suffix = '.html' # defaults to matching out_suffix indexer_format = js_index + indexer_dumps_unicode = True supported_image_types = ['image/svg+xml', 'image/png', 'image/gif', 'image/jpeg'] searchindex_filename = 'searchindex.js' @@ -754,16 +755,15 @@ class StandaloneHTMLBuilder(Builder): self.info('done') def dump_search_index(self): - # NOTE: If you change this code you have to change it in - # JSONHTMLBuilder.dump_search_index as well because the code is - # mostly copied from here for reasons explained in a comment in - # said method. self.info(bold('dumping search index... '), nonl=True) self.indexer.prune(self.env.all_docs) searchindexfn = path.join(self.outdir, self.searchindex_filename) # first write to a temporary file, so that if dumping fails, # the existing index won't be overwritten - f = open(searchindexfn + '.tmp', 'wb') + if self.indexer_dumps_unicode: + f = codecs.open(searchindexfn + '.tmp', 'w', encoding='utf-8') + else: + f = open(searchindexfn + '.tmp', 'wb') try: self.indexer.dump(f, self.indexer_format) finally: @@ -920,6 +920,7 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder): #: implements a `dump`, `load`, `dumps` and `loads` functions #: (pickle, simplejson etc.) implementation = None + implementation_dumps_unicode = False #: the filename for the global context file globalcontext_filename = None @@ -943,8 +944,12 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder): return docname + SEP def dump_context(self, context, filename): - f = open(filename, 'wb') + if self.implementation_dumps_unicode: + f = codecs.open(filename, 'w', encoding='utf-8') + else: + f = open(filename, 'wb') try: + # XXX: the third argument is pickle-specific! self.implementation.dump(context, f, 2) finally: f.close() @@ -995,7 +1000,9 @@ class PickleHTMLBuilder(SerializingHTMLBuilder): A Builder that dumps the generated HTML into pickle files. """ implementation = pickle + implementation_dumps_unicode = False indexer_format = pickle + indexer_dumps_unicode = False name = 'pickle' out_suffix = '.fpickle' globalcontext_filename = 'globalcontext.pickle' @@ -1010,7 +1017,9 @@ class JSONHTMLBuilder(SerializingHTMLBuilder): A builder that dumps the generated HTML into JSON files. """ implementation = jsonimpl + implementation_dumps_unicode = True indexer_format = jsonimpl + indexer_dumps_unicode = True name = 'json' out_suffix = '.fjson' globalcontext_filename = 'globalcontext.json' @@ -1022,29 +1031,3 @@ class JSONHTMLBuilder(SerializingHTMLBuilder): 'The module simplejson (or json in Python >= 2.6) ' 'is not available. The JSONHTMLBuilder builder will not work.') SerializingHTMLBuilder.init(self) - - def dump_context(self, context, filename): - # json operates entirely on "unicode" but the filesystem doesn't so we - # have to specify an encoding. - f = codecs.open(filename, 'w', encoding='utf-8') - try: - self.implementation.dump(context, f, 2) - finally: - f.close() - - def dump_search_index(self): - # this code is nearly completely copied from the super class, in which - # this method was initially defined, the only difference is that we - # specify an encoding for the file. - self.info(bold('dumping search index...'), nonl=True) - self.indexer.prune(self.env.all_docs) - searchindexfn = path.join(self.outdir, self.searchindex_filename) - # first write to a temporary file, so that if dumping fails, - # the existing index won't be overwritten - f = codecs.open(searchindexfn + '.tmp', 'w', encoding='utf-8') - try: - self.indexer.dump(f, self.indexer_format) - finally: - f.close() - movefile(searchindexfn + '.tmp', searchindexfn) - self.info('done') diff --git a/sphinx/search.py b/sphinx/search.py index 6d5a0614d..729b63b2a 100644 --- a/sphinx/search.py +++ b/sphinx/search.py @@ -58,13 +58,10 @@ class _JavaScriptIndex(object): return jsdump.loads(data) def dump(self, data, f): - f.write(self.dumps(data).encode('utf-8')) + f.write(self.dumps(data)) def load(self, f): - data = f.read() - if isinstance(data, unicode): - return self.loads(data) - return self.loads(data.decode('utf-8')) + return self.loads(f.read()) js_index = _JavaScriptIndex() From 8cb5a023129a5203691611aea6fa45e6f9c1e268 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:27:45 +0200 Subject: [PATCH 096/207] Give a binary document name. --- tests/test_search.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_search.py b/tests/test_search.py index 0b5b158b8..c0750366c 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -13,6 +13,7 @@ from docutils import frontend, utils from docutils.parsers import rst from sphinx.search import IndexBuilder +from sphinx.util.pycompat import b settings = parser = None @@ -31,7 +32,7 @@ test that non-comments are indexed: fermion ''' def test_wordcollector(): - doc = utils.new_document('test data', settings) + doc = utils.new_document(b('test data'), settings) doc['file'] = 'dummy' parser.parse(FILE_CONTENTS, doc) From 6f277bb7bd05bf2d96411235650f91717459bdfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 16 May 2010 17:51:40 +0200 Subject: [PATCH 097/207] Stop modifying PYTHONPATH in the Makefile --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index 21a87e367..13228c788 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,5 @@ PYTHON ?= python3 -export PYTHONPATH = $(shell echo "$$PYTHONPATH"):./sphinx - .PHONY: all check clean clean-pyc clean-patchfiles clean-generated pylint \ reindent test From 7c292a43d8301e278c3664c9d8bf4ddaccd1eccc Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:31:05 +0200 Subject: [PATCH 098/207] Factor out a replace(). --- sphinx/environment.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/environment.py b/sphinx/environment.py index fd171d443..70690a8a6 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -383,14 +383,14 @@ class BuildEnvironment: If base is a path string, return absolute path under that. If suffix is not None, add it instead of config.source_suffix. """ + docname = docname.replace(SEP, path.sep) suffix = suffix or self.config.source_suffix if base is True: - return path.join(self.srcdir, - docname.replace(SEP, path.sep)) + suffix + return path.join(self.srcdir, docname) + suffix elif base is None: - return docname.replace(SEP, path.sep) + suffix + return docname + suffix else: - return path.join(base, docname.replace(SEP, path.sep)) + suffix + return path.join(base, docname) + suffix def find_files(self, config): """ From 0580c7c81a8b34a116d37ff4718ba632fb083858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Thu, 3 Jun 2010 17:33:50 +0200 Subject: [PATCH 099/207] test if decoding is required first --- sphinx/ext/autodoc.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index 1113f97a0..efb762e27 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -435,8 +435,11 @@ class Documenter(object): # set sourcename and add content from attribute documentation if self.analyzer: # prevent encoding errors when the file name is non-ASCII - filename = unicode(self.analyzer.srcname, - sys.getfilesystemencoding(), 'replace') + if not isinstance(self.analyzer.srcname, unicode): + filename = unicode(self.analyzer.srcname, + sys.getfilesystemencoding(), 'replace') + else: + filename = self.analyzer.srcname sourcename = u'%s:docstring of %s' % (filename, self.fullname) attr_docs = self.analyzer.find_attr_docs() From f16a3173b39fef4faea27ace659c7383cd9ecc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sun, 6 Jun 2010 23:57:37 +0200 Subject: [PATCH 100/207] pass paths as bytes to docutils --- sphinx/environment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/environment.py b/sphinx/environment.py index 70690a8a6..46ec60164 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -649,7 +649,7 @@ class BuildEnvironment: destination_class=NullOutput) pub.set_components(None, 'restructuredtext', None) pub.process_programmatic_settings(None, self.settings, None) - pub.set_source(None, src_path) + pub.set_source(None, src_path.encode(FILESYSTEMENCODING)) pub.set_destination(None, None) try: pub.publish() From 52afc7ab6b1bee163cb9ef43fe13f316769b805d Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:33:24 +0200 Subject: [PATCH 101/207] Introduce constant. --- sphinx/environment.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sphinx/environment.py b/sphinx/environment.py index 46ec60164..6ad28ec8a 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -11,6 +11,7 @@ import re import os +import sys import time import types import codecs @@ -43,6 +44,7 @@ from sphinx.util.pycompat import all, class_types from sphinx.errors import SphinxError, ExtensionError from sphinx.locale import _ +fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() orig_role_function = roles.role orig_directive_function = directives.directive @@ -649,7 +651,7 @@ class BuildEnvironment: destination_class=NullOutput) pub.set_components(None, 'restructuredtext', None) pub.process_programmatic_settings(None, self.settings, None) - pub.set_source(None, src_path.encode(FILESYSTEMENCODING)) + pub.set_source(None, src_path.encode(fs_encoding)) pub.set_destination(None, None) try: pub.publish() From 85ef01660227156305a3dba48f065be16458493c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 7 Jun 2010 00:07:38 +0200 Subject: [PATCH 102/207] only decode code if necessary --- sphinx/ext/viewcode.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 81881beb6..db04ac794 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -31,7 +31,11 @@ def doctree_read(app, doctree): env._viewcode_modules[modname] = False return analyzer.find_tags() - entry = analyzer.code.decode(analyzer.encoding), analyzer.tags, {} + if not isinstance(analyzer.code, unicode): + code = analyzer.code.decode(analyzer.encoding) + else: + code = analyzer.code + entry = code, analyzer.tags, {} env._viewcode_modules[modname] = entry elif entry is False: return From 5f5f9177906c05f7d9049fc6456e1386537edabc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Wed, 16 Jun 2010 23:05:56 +0200 Subject: [PATCH 103/207] only decode if possible --- sphinx/environment.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sphinx/environment.py b/sphinx/environment.py index 6ad28ec8a..bf255165e 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -630,6 +630,8 @@ class BuildEnvironment: class SphinxSourceClass(FileInput): def decode(self_, data): + if isinstance(data, unicode): + return data return data.decode(self_.encoding, 'sphinx') def read(self_): From 024ec6696fb72b6658c67891a53021e86bb4b893 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:35:35 +0200 Subject: [PATCH 104/207] Mode "Ub" does not exist. --- sphinx/config.py | 2 +- sphinx/directives/code.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/config.py b/sphinx/config.py index 273bb97d9..708da162e 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -167,7 +167,7 @@ class Config(object): try: try: os.chdir(dirname) - f = open(config_file, 'Ub') + f = open(config_file, 'rb') try: code = compile(f.read(), config_file, 'exec') finally: diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py index 54d8edf19..1808cdaba 100644 --- a/sphinx/directives/code.py +++ b/sphinx/directives/code.py @@ -119,7 +119,7 @@ class LiteralInclude(Directive): encoding = self.options.get('encoding', env.config.source_encoding) codec_info = codecs.lookup(encoding) try: - f = codecs.StreamReaderWriter(open(fn, 'Ub'), + f = codecs.StreamReaderWriter(open(fn, 'rb'), codec_info[2], codec_info[3], 'strict') lines = f.readlines() f.close() From b621cfaec1501409d1cc81a24340975f7b445ac3 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:36:57 +0200 Subject: [PATCH 105/207] Unify version_info checks. --- sphinx/util/pycompat.py | 2 +- tests/run.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index 624749fc3..229b54b45 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -27,7 +27,7 @@ except NameError: # the ubiquitous "bytes" helper function -if sys.version_info > (3, 0): +if sys.version_info >= (3, 0): def b(s): return s.encode('utf-8') else: diff --git a/tests/run.py b/tests/run.py index 59a3ffa5b..50567fbc5 100755 --- a/tests/run.py +++ b/tests/run.py @@ -13,7 +13,7 @@ import sys from os import path, chdir, listdir -if sys.version_info >= (3,): +if sys.version_info >= (3, 0): print('Copying and converting sources to build/lib/tests...') from distutils.util import copydir_run_2to3 testroot = path.dirname(__file__) or '.' From c967651712521e96e53966f9a1ad916e4670a1a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 19 Jun 2010 18:23:49 +0200 Subject: [PATCH 106/207] Implemented sphinx.ext.autodoc.MethodDocumenter.import_object for python3 --- sphinx/ext/autodoc.py | 57 +++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index efb762e27..eef181de4 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -251,6 +251,9 @@ class Documenter(object): self.retann = None # the object to document (set after import_object succeeds) self.object = None + self.object_name = None + # the parent/owner of the object to document + self.parent = None # the module analyzer to get at attribute docs, or None self.analyzer = None @@ -316,9 +319,13 @@ class Documenter(object): """ try: __import__(self.modname) + parent = None obj = self.module = sys.modules[self.modname] for part in self.objpath: + parent = obj obj = self.get_attr(obj, part) + self.object_name = part + self.parent = parent self.object = obj return True # this used to only catch SyntaxError, ImportError and AttributeError, @@ -1007,24 +1014,38 @@ class MethodDocumenter(ClassLevelDocumenter): return inspect.isroutine(member) and \ not isinstance(parent, ModuleDocumenter) - def import_object(self): - ret = ClassLevelDocumenter.import_object(self) - if isinstance(self.object, classmethod) or \ - (isinstance(self.object, MethodType) and - self.object.im_self is not None): - self.directivetype = 'classmethod' - # document class and static members before ordinary ones - self.member_order = self.member_order - 1 - elif isinstance(self.object, FunctionType) or \ - (isinstance(self.object, BuiltinFunctionType) and - hasattr(self.object, '__self__') and - self.object.__self__ is not None): - self.directivetype = 'staticmethod' - # document class and static members before ordinary ones - self.member_order = self.member_order - 1 - else: - self.directivetype = 'method' - return ret + if sys.version_info >= (3, 0): + def import_object(self): + ret = ClassLevelDocumenter.import_object(self) + obj_from_parent = self.parent.__dict__.get(self.object_name) + if isinstance(obj_from_parent, classmethod): + self.directivetype = 'classmethod' + self.member_order = self.member_order - 1 + elif isinstance(obj_from_parent, staticmethod): + self.directivetype = 'staticmethod' + self.member_order = self.member_order - 1 + else: + self.directivetype = 'method' + return ret + else: + def import_object(self): + ret = ClassLevelDocumenter.import_object(self) + if isinstance(self.object, classmethod) or \ + (isinstance(self.object, MethodType) and + self.object.im_self is not None): + self.directivetype = 'classmethod' + # document class and static members before ordinary ones + self.member_order = self.member_order - 1 + elif isinstance(self.object, FunctionType) or \ + (isinstance(self.object, BuiltinFunctionType) and + hasattr(self.object, '__self__') and + self.object.__self__ is not None): + self.directivetype = 'staticmethod' + # document class and static members before ordinary ones + self.member_order = self.member_order - 1 + else: + self.directivetype = 'method' + return ret def format_args(self): if inspect.isbuiltin(self.object) or \ From 625127fd639008a98be06e96f514c84b8613ba30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Fri, 28 May 2010 04:08:15 +0200 Subject: [PATCH 107/207] Fix SyntaxError in config generated by quickstart and the quickstart test --- sphinx/quickstart.py | 14 +++++++++++++- tests/test_quickstart.py | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 892bd641d..557f8c094 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -9,7 +9,7 @@ :license: BSD, see LICENSE for details. """ -import sys, os, time +import sys, os, time, re from os import path from codecs import open @@ -685,6 +685,18 @@ def do_prompt(d, key, text, default=None, validator=nonempty): d[key] = x +if sys.version_info >= (3, 0): + # remove Unicode literal prefixes + _unicode_string_re = re.compile(r"[uU]('.*?')") + def _convert_python_source(source): + return _unicode_string_re.sub('\\1', source) + + for f in ['QUICKSTART_CONF', 'EPUB_CONFIG', 'INTERSPHINX_CONFIG']: + globals()[f] = convert_python_source(globals()[f]) + + del _unicode_string_re, _convert_python_source + + def inner_main(args): d = {} texescape.init() diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index d0403d3b2..72ae764d6 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -117,8 +117,8 @@ def test_quickstart_all_answers(tempdir): 'Root path': tempdir, 'Separate source and build': 'y', 'Name prefix for templates': '.', - 'Project name': 'STASI\xe2\x84\xa2', - 'Author name': 'Wolfgang Sch\xc3\xa4uble & G\'Beckstein', + 'Project name': u'STASI™'.encode('utf-8'), + 'Author name': u'Wolfgang Schäuble & G\'Beckstein'.encode('utf-8'), 'Project version': '2.0', 'Project release': '2.0.1', 'Source file suffix': '.txt', From 43407189207a06ee11ce55ce80de0bbe1f72d491 Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Thu, 3 Jun 2010 15:14:08 +0200 Subject: [PATCH 108/207] Remove external refuris from toc.ncx. --- sphinx/builders/epub.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index 9767391e0..f99012bdd 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -195,6 +195,10 @@ class EpubBuilder(StandaloneHTMLBuilder): # XXX: is there a better way than checking the attribute # toctree-l[1-8] on the parent node? if isinstance(doctree, nodes.reference): + refuri = doctree['refuri'] + if refuri.startswith('http://') or refuri.startswith('https://') \ + or refuri.startswith('irc:') or refuri.startswith('mailto:'): + return result classes = doctree.parent.attributes['classes'] level = 1 for l in range(8, 0, -1): # or range(1, 8)? @@ -202,7 +206,7 @@ class EpubBuilder(StandaloneHTMLBuilder): level = l result.append({ 'level': level, - 'refuri': self.esc(doctree['refuri']), + 'refuri': self.esc(refuri), 'text': self.esc(doctree.astext()) }) else: From 55e322e22585b86ea8641d939e7019369f53ec9f Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Thu, 3 Jun 2010 15:32:46 +0200 Subject: [PATCH 109/207] Use smartypants for toc entries. --- sphinx/builders/epub.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index f99012bdd..db6ce05ad 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -20,6 +20,7 @@ from docutils.transforms import Transform from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.util.osutil import EEXIST +from sphinx.util.smartypants import sphinx_smarty_pants as ssp # (Fragment) templates from which the metainfo files content.opf, toc.ncx, @@ -207,7 +208,7 @@ class EpubBuilder(StandaloneHTMLBuilder): result.append({ 'level': level, 'refuri': self.esc(refuri), - 'text': self.esc(doctree.astext()) + 'text': ssp(self.esc(doctree.astext())) }) else: for elem in doctree.children: @@ -224,19 +225,20 @@ class EpubBuilder(StandaloneHTMLBuilder): self.refnodes.insert(0, { 'level': 1, 'refuri': self.esc(self.config.master_doc + '.html'), - 'text': self.esc(self.env.titles[self.config.master_doc].astext()) + 'text': ssp(self.esc( + self.env.titles[self.config.master_doc].astext())) }) for file, text in reversed(self.config.epub_pre_files): self.refnodes.insert(0, { 'level': 1, 'refuri': self.esc(file + '.html'), - 'text': self.esc(text) + 'text': ssp(self.esc(text)) }) for file, text in self.config.epub_post_files: self.refnodes.append({ 'level': 1, 'refuri': self.esc(file + '.html'), - 'text': self.esc(text) + 'text': ssp(self.esc(text)) }) From ef63485c6e6813b4cfd9ef74856c17b07919326c Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Thu, 3 Jun 2010 15:39:24 +0200 Subject: [PATCH 110/207] Added one more epub_exclude_file. --- doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index b268a13f0..e102c155d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -36,7 +36,7 @@ epub_scheme = 'url' epub_identifier = epub_publisher epub_pre_files = [('index', 'Welcome')] epub_exclude_files = ['_static/opensearch.xml', '_static/doctools.js', - '_static/jquery.js', '_static/searchtools.js', + '_static/jquery.js', '_static/searchtools.js', '_static/underscore.js', '_static/basic.css', 'search.html'] latex_documents = [('contents', 'sphinx.tex', 'Sphinx Documentation', From 87c3052bb4045fd9302ee469ccc09b818e3e7abd Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Thu, 3 Jun 2010 15:57:38 +0200 Subject: [PATCH 111/207] Added note for large floating divs to the documentation. --- doc/faq.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/faq.rst b/doc/faq.rst index 613283c5d..ff08c486d 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -134,6 +134,12 @@ some notes: and Bookworm_. For bookworm you can download the source from http://code.google.com/p/threepress/ and run your own local server. +* Large floating divs are not displayed properly. + If they cover more than one page, the div is only shown on the first page. + In that case you can copy the :file:`epub.css` from the + ``sphinx/themes/epub/static/`` directory to your local ``_static/`` + directory and remove the float settings. + .. _Epubcheck: http://code.google.com/p/epubcheck/ .. _Calibre: http://calibre-ebook.com/ .. _FBreader: http://www.fbreader.org/ From d54377153a8d2942dc9a9baf171dd8f5c40f2ff4 Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Mon, 7 Jun 2010 22:27:13 +0200 Subject: [PATCH 112/207] Only add refnodes with a class of 'toctree-l%d' to the toc.ncx file --- doc/config.rst | 4 ++-- doc/faq.rst | 4 ++++ sphinx/builders/epub.py | 17 ++++++++--------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/doc/config.rst b/doc/config.rst index d968ce551..e9c98f1c2 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -766,8 +766,8 @@ the `Dublin Core metadata `_. .. confval:: epub_post_files Additional files that should be inserted after the text generated by Sphinx. - It is a list of tuples containing the file name and the title. The default - value is ``[]``. + It is a list of tuples containing the file name and the title. This option + can be used to add an appendix. The default value is ``[]``. .. confval:: epub_exclude_files diff --git a/doc/faq.rst b/doc/faq.rst index ff08c486d..5869e3af8 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -140,6 +140,10 @@ some notes: ``sphinx/themes/epub/static/`` directory to your local ``_static/`` directory and remove the float settings. +* Files that are inserted outside of the ``toctree`` directive must be manually + included. This sometimes applies to appendixes, e.g. the glossary or + the indices. You can add them with the :confval:`epub_post_files` option. + .. _Epubcheck: http://code.google.com/p/epubcheck/ .. _Calibre: http://calibre-ebook.com/ .. _FBreader: http://www.fbreader.org/ diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index db6ce05ad..47984be6b 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -201,15 +201,14 @@ class EpubBuilder(StandaloneHTMLBuilder): or refuri.startswith('irc:') or refuri.startswith('mailto:'): return result classes = doctree.parent.attributes['classes'] - level = 1 - for l in range(8, 0, -1): # or range(1, 8)? - if (_toctree_template % l) in classes: - level = l - result.append({ - 'level': level, - 'refuri': self.esc(refuri), - 'text': ssp(self.esc(doctree.astext())) - }) + for level in range(8, 0, -1): # or range(1, 8)? + if (_toctree_template % level) in classes: + result.append({ + 'level': level, + 'refuri': self.esc(refuri), + 'text': ssp(self.esc(doctree.astext())) + }) + break else: for elem in doctree.children: result = self.get_refnodes(elem, result) From 13adb67063b12d4960f368e5247ae3423c22654a Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Mon, 7 Jun 2010 22:28:48 +0200 Subject: [PATCH 113/207] Correct handling of extensions for extra files --- doc/conf.py | 2 +- sphinx/builders/epub.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index e102c155d..299f321ac 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -34,7 +34,7 @@ epub_author = 'Georg Brandl' epub_publisher = 'http://sphinx.pocoo.org/' epub_scheme = 'url' epub_identifier = epub_publisher -epub_pre_files = [('index', 'Welcome')] +epub_pre_files = [('index.html', 'Welcome')] epub_exclude_files = ['_static/opensearch.xml', '_static/doctools.js', '_static/jquery.js', '_static/searchtools.js', '_static/underscore.js', '_static/basic.css', 'search.html'] diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index 47984be6b..fdfab7190 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -230,13 +230,13 @@ class EpubBuilder(StandaloneHTMLBuilder): for file, text in reversed(self.config.epub_pre_files): self.refnodes.insert(0, { 'level': 1, - 'refuri': self.esc(file + '.html'), + 'refuri': self.esc(file), 'text': ssp(self.esc(text)) }) for file, text in self.config.epub_post_files: self.refnodes.append({ 'level': 1, - 'refuri': self.esc(file + '.html'), + 'refuri': self.esc(file), 'text': ssp(self.esc(text)) }) From eb86c504b3a807e79badd2239297b44016b911f2 Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Mon, 7 Jun 2010 22:37:01 +0200 Subject: [PATCH 114/207] Disable VisibleLinksTransform because it may leak into the HTML generation. --- sphinx/builders/epub.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index fdfab7190..74c328ea7 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -125,7 +125,7 @@ _media_types = { class VisibleLinksTransform(Transform): """ - Add the link target of referances to the text, unless it is already + Add the link target of references to the text, unless it is already present in the description. """ @@ -171,7 +171,10 @@ class EpubBuilder(StandaloneHTMLBuilder): # the output files for epub must be .html only self.out_suffix = '.html' self.playorder = 0 - self.app.add_transform(VisibleLinksTransform) + # Disable transform until the issue with cached doctrees is solved. + # Building the html file after the epub file shows the + # visible links also in the HTML output. + #self.app.add_transform(VisibleLinksTransform) def get_theme_config(self): return self.config.epub_theme, {} From 85a854c859d8603f6a0ef087bc6a4bef6e8f0dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 21 Jun 2010 20:08:52 +0200 Subject: [PATCH 115/207] Added the tipfy documentation to the examples --- EXAMPLES | 1 + 1 file changed, 1 insertion(+) diff --git a/EXAMPLES b/EXAMPLES index c618b8bf9..af53d0e73 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -139,6 +139,7 @@ Documentation using a custom theme/integrated in a site * Self: http://selflanguage.org/ * SQLAlchemy: http://www.sqlalchemy.org/docs/ * tinyTiM: http://tinytim.sourceforge.net/docs/2.0/ +* tipfy: http://www.tipfy.org/docs/ * Werkzeug: http://werkzeug.pocoo.org/documentation/dev/ * WFront: http://discorporate.us/projects/WFront/ From 1261e372674e5c2d90b422bb09b90f0bf76b9354 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 22 Jun 2010 20:06:46 +0200 Subject: [PATCH 116/207] Better insert at the beginning of sys.path. --- sphinx/quickstart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 55ff31ddf..28dd3c91d 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -42,7 +42,7 @@ import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.append(os.path.abspath('.')) +#sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- From ea62fb7af38767c44a78798bca12593ef445cda8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Tue, 22 Jun 2010 20:37:11 +0200 Subject: [PATCH 117/207] Added the Spring Python documentation to the examples --- EXAMPLES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/EXAMPLES b/EXAMPLES index af53d0e73..4af66c9c3 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -109,6 +109,8 @@ Documentation using another builtin theme * pip: http://pip.openplans.org/ (nature) * Programmieren mit PyGTK und Glade (German): http://www.florian-diesch.de/doc/python-und-glade/online/ (agogo) +* Spring Python: http://springpython.webfactional.com/current/sphinx/index.html + (nature) * sqlparse: http://python-sqlparse.googlecode.com/svn/docs/api/index.html (agogo) * libLAS: http://liblas.org/ (nature) From 1c09b052fa8a6ee841b570b2a0344d4dab02156a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Tue, 22 Jun 2010 20:38:18 +0200 Subject: [PATCH 118/207] Added PyMQI documentation to the examples --- EXAMPLES | 1 + 1 file changed, 1 insertion(+) diff --git a/EXAMPLES b/EXAMPLES index 4af66c9c3..52fce0e8b 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -38,6 +38,7 @@ Documentation using the default theme * PyCuda: http://documen.tician.de/pycuda/ * Pyevolve: http://pyevolve.sourceforge.net/ * Pylo: http://documen.tician.de/pylo/ +* PyMQI: http://packages.python.org/pymqi/ * PyPubSub: http://pubsub.sourceforge.net/ * pyrticle: http://documen.tician.de/pyrticle/ * Python: http://docs.python.org/ From b2a237b8b4e613904965295129621d621cf28ecc Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Wed, 30 Jun 2010 21:32:18 +0200 Subject: [PATCH 119/207] Omit nodes without refuri attribute from toc.ncx. This fixes bug report on sphinx-dev. --- sphinx/builders/epub.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index 74c328ea7..a5f7a84d0 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -198,7 +198,7 @@ class EpubBuilder(StandaloneHTMLBuilder): """Collect section titles, their depth in the toc and the refuri.""" # XXX: is there a better way than checking the attribute # toctree-l[1-8] on the parent node? - if isinstance(doctree, nodes.reference): + if isinstance(doctree, nodes.reference) and hasattr(doctree, 'refuri'): refuri = doctree['refuri'] if refuri.startswith('http://') or refuri.startswith('https://') \ or refuri.startswith('irc:') or refuri.startswith('mailto:'): From fa120b01d5142d7e3a857d87eb5d76a7ae9b1cdb Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 2 Jul 2010 10:41:40 +0200 Subject: [PATCH 120/207] Update of Brazilian portuguese message catalog, by Roger Demetrescu. --- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js | 2 +- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo | Bin 8836 -> 10252 bytes sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po | 222 ++++++++++++---------- 3 files changed, 118 insertions(+), 106 deletions(-) diff --git a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js index dbfaab85f..312d0fc7a 100644 --- a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js +++ b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js @@ -1 +1 @@ -Documentation.addTranslations({"locale": "pt_BR", "plural_expr": "(n > 1)", "messages": {"Search Results": "Resultados da Pesquisa", "Preparing search...": "Preparando pesquisa...", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Sua pesquisa n\u00e3o encontrou nenhum documento. Por favor assegure-se de que todas as palavras foram digitadas corretamente e de que voc\u00ea tenha selecionado o m\u00ednimo de categorias.", "Search finished, found %s page(s) matching the search query.": "Pesquisa finalizada, foram encontrada(s) %s p\u00e1gina(s) que conferem com o crit\u00e9rio de pesquisa.", ", in ": ", em ", "Expand sidebar": "", "Permalink to this headline": "Link permanente para este t\u00edtulo", "Searching": "Pesquisando", "Collapse sidebar": "", "Permalink to this definition": "Link permanente para esta defini\u00e7\u00e3o", "Hide Search Matches": "Esconder Resultados da Pesquisa"}}); \ No newline at end of file +Documentation.addTranslations({"locale": "pt_BR", "plural_expr": "(n > 1)", "messages": {"Search Results": "Resultados da Pesquisa", "Preparing search...": "Preparando pesquisa...", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "Sua pesquisa n\u00e3o encontrou nenhum documento. Por favor assegure-se de que todas as palavras foram digitadas corretamente e de que voc\u00ea tenha selecionado o m\u00ednimo de categorias.", "Search finished, found %s page(s) matching the search query.": "Pesquisa finalizada, foram encontrada(s) %s p\u00e1gina(s) que conferem com o crit\u00e9rio de pesquisa.", ", in ": ", em ", "Expand sidebar": "Expandir painel lateral", "Permalink to this headline": "Link permanente para este t\u00edtulo", "Searching": "Pesquisando", "Collapse sidebar": "Recolher painel lateral", "Permalink to this definition": "Link permanente para esta defini\u00e7\u00e3o", "Hide Search Matches": "Esconder Resultados da Pesquisa"}}); \ No newline at end of file diff --git a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo index b644a1145202e2a8a398b14f873ae665beacd278..67c1ce549defc203511d37f64b4f4117ee3b9247 100644 GIT binary patch delta 4464 zcmZY9eT*Gd8OQOnYiVhhw!7PwzQDrS?aMCMZd)m|ZV7!a1uR{myu`NDv-i&Kj=gv0 zGIQ_lR$gv2g;Xp?GC@IJv{s@efXd}1Vj{syBfcS~iQpfQiV{eGn6!x+74iFXY388rffG3s>OR@f>^s=iuw8Ku%?TfM+tlnL_xNVLP6QJCJAQMx27f zr~v}hLMO%&GvVk!NLW9=77r?0z{;;(inA{cWgmuR$&3#>}9D{A+*%G<4&A zsJWg)vTJ^o-M@<3%eS-kQ>Yb~&cWe5E#L~bTO+KoTt z^mwR1=J1jh)`LAd|9xDj<5ihEvkrSu0p*agFlAIA2Qgg{YQjfQTTw&xe;(EE71UOp z$nH;~`nOW?8m}FzEY2+ALLJwlI&4R!dKYp4%flfV zeF>HNJ5ejS2Q~2hsDOWr+S8ZuLVOc7-gNS;1@>jG&Ab{lPStUtRQlP23M$frsEO}K z4g4^w2A)KV&!gTufs64yD-Z;dwM*lVtju*+JP4Dqh}(fepNgvMsq0FL`PD zU6%x9FS4=cqTHzEvKZSivd$L6e5K$m&8DJhxDw>bzFv1luRj@_(Or$gq8;@j&+ZQ^ zHs^xV!;E^dXY*mMQuKmy+;6v}lhCU<(=^M!@i5BA)(^^|EsuJ3D4eiEULhQ}F32;l zpWA198iDon+pEK}M>kha`=-sww)PoSJMI?>T54EyWk2T%h5gMihP4nLhQsMQ>2&>e zkcG$T{JAhFJ3sJ)5j*USlZ8e=<6+QSwysnnCq$RN8+mc1P__j>F87u9O&q$5>8fz@jifv#DI^ZX3!=KZ)72KC1YT^@g$+BzMmL<%JvA(1>2m2?wmX#><5T%8k1GOHsWx;TO56A0F`om)x=7Ky|Y};u8`JQlUfM z*`Z3Db4p)mgRq#!TPZeIo|QkZR8;@<@7Irn{boxPg=Wh{i8A#+9*v<+9Rqtd3iGa1 zKWa7*Z&apZzUpqS_;xJJ)gQGbO2(GFn3k9_`*>0))5!CJ+^Dm0h4IpQExCdliyEUh zU)5T3&Yy7B4FMaYlXG*0JQuC)X?BY^K|88Lu@{YbR!`mO^(fY6w{#jmVrQEzoS@T3 zONW`h>QCPsY~-5nleRu!_jrXgXT6rjHXwnP3HWuS#mljstU%|=rAbTA znahX$wI$~av~)IWNkcV?G1+_WUVFVCYlso;|3I@uR4vU;$Is1QPMpJTj9s;Ety?H2@u5sLJ zFLsq%&bypo%x1noW-y)ki(X`O>UB*0IN5&w`%BZ$VHoc*yQs_&ugFF7Jf(+akI|9! z8947HH`u)!{_oTpWmYwwmZIu6t8c!U)U+Q)hWJB6VS4&nB!9A-dv~hXwIse3aa=!4 zH&YJxc|qD1xnljWzMRSW?roDBpNZt|?tQbuQZ@;D9)%i> zrwmhYGIla1W@fn#)tE}dGpGsHxcY6V0nOMAKgJ$-9MkX;YTOMBVtZ!Q_(J4oMsQKT zGR(lKsCjBJi}lU(++n2m2@Ivzx2<{T#C zMI41!T)98H(S`$@0;Tx!lT2K=o!3sQu9WbBmvw71W706Ij zfRmA*nZ`xq=AtrJj|?@dF{V^(;-(G0jVd>z9)lLtz{98szeWXm#(4$RKfnR^#&pzK z59h*WO}Q&iapf>7&;_U?dbTt9SH(IiwBReK$X-S5xEZzJUR1whsE70{Dl^xS(=n-} z>ru=?1vCSR%`CutT#5?lbyUXoU;=)aM*cNHi>vt3bvTWBdcQ@rUqwxL8z06_gs)VO zLuDw8G?_Y7;4$Y5sPP++pV`hu{dc1R`A8kxa?^s!z-Oq)j^G+RiG?`5>-_=CQSEC` z3vEONx)pQrJ=6lnk)h@sDu7>5M|cC3!P}_yVm-;12IQe8Dnh*tBVGLysD&y~M^oio zgqm_sj31*+c}R31OckNNsc#Ha;Y|bYC+R08T zl&W2*$PS^7c`Bmo~XA*hWL>Z{|2T?~i0=4r;Pz#r#o~?-($0;~a z?|)+O{(xbqvmWUji}#*dmxfpw@I?m#WL8%dtohg$d)YTiy5*MyW1v4o0Q2)Ro7hz6;Y(J6M8RaH(@Os{cAvfG<0DpfdLss{bdh{vc`t z$5fuc&3D|W<0aHneGBz0B(SP>I1m-_NaXlTIch-<_5RnQb{y*y-;%U8(5~o#V3FOB z+|ABR&WSfAR|f3elmqri>QI~Bd3A0i;z!Jwr|Uy?;b62X?9C2E%vj%VsPh}VsJ)hU zJN{>vhXV2PZUupOWA`C}_y_5;12!*Xl=U(;Bn=%nXlSswxMc8<_cN!qvFAGtu*@}iJu|(c(Tg-zd5cPdwSIVEjTfBbhduj!@34KR>o~iy&)E2lKG8t-l=%^VQPh-G z%?X)Fek3?Iw8V>;(#EQ&Z%YgM+C6;_B}HeLr>bg0^SoL+GCgSDEqL7SOCMlM3rAAGUuKR;SiSd^HFC`i3gM&MxX# cl;+L#B3|7bFIW?r?bVoiTb$qBp6EB|AH0cfBLDyZ diff --git a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po index 44e2053a1..7df9013e7 100644 --- a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: Sphinx 0.5\n" "Report-Msgid-Bugs-To: roger.demetrescu@gmail.com\n" "POT-Creation-Date: 2008-11-09 19:46+0100\n" -"PO-Revision-Date: 2010-05-24 23:54+0200\n" +"PO-Revision-Date: 2010-06-20 18:34-0300\n" "Last-Translator: Roger Demetrescu \n" "Language-Team: pt_BR \n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" @@ -17,7 +17,8 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 0.9.4\n" -#: sphinx/environment.py:106 sphinx/writers/latex.py:184 +#: sphinx/environment.py:106 +#: sphinx/writers/latex.py:184 #: sphinx/writers/manpage.py:67 #, python-format msgid "%B %d, %Y" @@ -41,7 +42,8 @@ msgstr "Módulo" msgid "%b %d, %Y" msgstr "%d/%m/%Y" -#: sphinx/builders/html.py:285 sphinx/themes/basic/defindex.html:30 +#: sphinx/builders/html.py:285 +#: sphinx/themes/basic/defindex.html:30 msgid "General Index" msgstr "Índice Geral" @@ -70,9 +72,8 @@ msgid "Module author: " msgstr "Autor do módulo: " #: sphinx/directives/other.py:131 -#, fuzzy msgid "Code author: " -msgstr "Autor do módulo: " +msgstr "Autor do código: " #: sphinx/directives/other.py:133 msgid "Author: " @@ -85,18 +86,21 @@ msgstr "Veja também" #: sphinx/domains/__init__.py:253 #, python-format msgid "%s %s" -msgstr "" +msgstr "%s %s" -#: sphinx/domains/c.py:51 sphinx/domains/python.py:49 +#: sphinx/domains/c.py:51 +#: sphinx/domains/python.py:49 msgid "Parameters" msgstr "Parâmetros" -#: sphinx/domains/c.py:54 sphinx/domains/javascript.py:137 +#: sphinx/domains/c.py:54 +#: sphinx/domains/javascript.py:137 #: sphinx/domains/python.py:59 msgid "Returns" msgstr "Retorna" -#: sphinx/domains/c.py:56 sphinx/domains/python.py:61 +#: sphinx/domains/c.py:56 +#: sphinx/domains/python.py:61 msgid "Return type" msgstr "Tipo de retorno" @@ -125,12 +129,15 @@ msgstr "%s (tipo C)" msgid "%s (C variable)" msgstr "%s (variável C)" -#: sphinx/domains/c.py:171 sphinx/domains/cpp.py:1031 -#: sphinx/domains/javascript.py:166 sphinx/domains/python.py:497 +#: sphinx/domains/c.py:171 +#: sphinx/domains/cpp.py:1031 +#: sphinx/domains/javascript.py:166 +#: sphinx/domains/python.py:497 msgid "function" msgstr "função" -#: sphinx/domains/c.py:172 sphinx/domains/cpp.py:1032 +#: sphinx/domains/c.py:172 +#: sphinx/domains/cpp.py:1032 msgid "member" msgstr "membro" @@ -138,14 +145,14 @@ msgstr "membro" msgid "macro" msgstr "macro" -#: sphinx/domains/c.py:174 sphinx/domains/cpp.py:1033 +#: sphinx/domains/c.py:174 +#: sphinx/domains/cpp.py:1033 msgid "type" msgstr "tipo" #: sphinx/domains/c.py:175 -#, fuzzy msgid "variable" -msgstr "Variável" +msgstr "variável" #: sphinx/domains/cpp.py:876 #, python-format @@ -167,16 +174,19 @@ msgstr "%s (membro C++)" msgid "%s (C++ function)" msgstr "%s (função C++)" -#: sphinx/domains/cpp.py:1030 sphinx/domains/python.py:499 +#: sphinx/domains/cpp.py:1030 +#: sphinx/domains/python.py:499 msgid "class" msgstr "classe" -#: sphinx/domains/javascript.py:117 sphinx/domains/python.py:221 +#: sphinx/domains/javascript.py:117 +#: sphinx/domains/python.py:221 #, python-format msgid "%s() (built-in function)" msgstr "%s() (função interna)" -#: sphinx/domains/javascript.py:118 sphinx/domains/python.py:285 +#: sphinx/domains/javascript.py:118 +#: sphinx/domains/python.py:285 #, python-format msgid "%s() (%s method)" msgstr "%s() (método %s)" @@ -184,41 +194,44 @@ msgstr "%s() (método %s)" #: sphinx/domains/javascript.py:120 #, python-format msgid "%s (global variable or constant)" -msgstr "" +msgstr "%s (variável global ou constante)" -#: sphinx/domains/javascript.py:122 sphinx/domains/python.py:323 +#: sphinx/domains/javascript.py:122 +#: sphinx/domains/python.py:323 #, python-format msgid "%s (%s attribute)" msgstr "%s (atributo %s)" #: sphinx/domains/javascript.py:131 -#, fuzzy msgid "Arguments" msgstr "Parâmetros" #: sphinx/domains/javascript.py:134 msgid "Throws" -msgstr "" +msgstr "Gera" -#: sphinx/domains/javascript.py:167 sphinx/domains/python.py:498 +#: sphinx/domains/javascript.py:167 +#: sphinx/domains/python.py:498 msgid "data" -msgstr "" +msgstr "dado" -#: sphinx/domains/javascript.py:168 sphinx/domains/python.py:504 +#: sphinx/domains/javascript.py:168 +#: sphinx/domains/python.py:504 msgid "attribute" msgstr "atributo" #: sphinx/domains/python.py:53 -#, fuzzy msgid "Variables" -msgstr "Variável" +msgstr "Variáveis" #: sphinx/domains/python.py:56 msgid "Raises" msgstr "Levanta" -#: sphinx/domains/python.py:222 sphinx/domains/python.py:279 -#: sphinx/domains/python.py:291 sphinx/domains/python.py:304 +#: sphinx/domains/python.py:222 +#: sphinx/domains/python.py:279 +#: sphinx/domains/python.py:291 +#: sphinx/domains/python.py:304 #, python-format msgid "%s() (in module %s)" msgstr "%s() (no módulo %s)" @@ -228,7 +241,8 @@ msgstr "%s() (no módulo %s)" msgid "%s (built-in variable)" msgstr "%s (variável interna)" -#: sphinx/domains/python.py:226 sphinx/domains/python.py:317 +#: sphinx/domains/python.py:226 +#: sphinx/domains/python.py:317 #, python-format msgid "%s (in module %s)" msgstr "%s (no módulo %s)" @@ -259,14 +273,14 @@ msgid "%s() (%s static method)" msgstr "%s() (método estático %s)" #: sphinx/domains/python.py:308 -#, fuzzy, python-format +#, python-format msgid "%s() (%s.%s class method)" -msgstr "%s() (método %s.%s)" +msgstr "%s() (método de classe %s.%s)" #: sphinx/domains/python.py:311 -#, fuzzy, python-format +#, python-format msgid "%s() (%s class method)" -msgstr "%s() (método %s)" +msgstr "%s() (método de classe %s)" #: sphinx/domains/python.py:321 #, python-format @@ -283,9 +297,8 @@ msgid "%s (module)" msgstr "%s (módulo)" #: sphinx/domains/python.py:429 -#, fuzzy msgid "Python Module Index" -msgstr "Índice do Módulo" +msgstr "Índice de Módulos do Python" #: sphinx/domains/python.py:430 msgid "modules" @@ -295,47 +308,49 @@ msgstr "módulos" msgid "Deprecated" msgstr "Obsoleto" -#: sphinx/domains/python.py:500 sphinx/locale/__init__.py:162 +#: sphinx/domains/python.py:500 +#: sphinx/locale/__init__.py:162 msgid "exception" msgstr "exceção" #: sphinx/domains/python.py:501 msgid "method" -msgstr "" +msgstr "método" #: sphinx/domains/python.py:502 -#, fuzzy, python-format +#, python-format msgid "class method" -msgstr "%s() (método %s)" +msgstr "método de classe" #: sphinx/domains/python.py:503 msgid "static method" msgstr "método estático" -#: sphinx/domains/python.py:505 sphinx/locale/__init__.py:158 +#: sphinx/domains/python.py:505 +#: sphinx/locale/__init__.py:158 msgid "module" msgstr "módulo" #: sphinx/domains/rst.py:53 #, python-format msgid "%s (directive)" -msgstr "" +msgstr "%s (diretiva)" #: sphinx/domains/rst.py:55 -#, fuzzy, python-format +#, python-format msgid "%s (role)" -msgstr "%s (módulo)" +msgstr "%s (papel)" #: sphinx/domains/rst.py:103 msgid "directive" -msgstr "" +msgstr "diretiva" #: sphinx/domains/rst.py:104 -#, fuzzy msgid "role" -msgstr "módulo" +msgstr "papel" -#: sphinx/domains/std.py:68 sphinx/domains/std.py:84 +#: sphinx/domains/std.py:68 +#: sphinx/domains/std.py:84 #, python-format msgid "environment variable; %s" msgstr "váriavel de ambiente; %s" @@ -347,15 +362,15 @@ msgstr "%sopção de linha de comando; %s" #: sphinx/domains/std.py:328 msgid "glossary term" -msgstr "" +msgstr "Termo de glossário" #: sphinx/domains/std.py:329 msgid "grammar token" -msgstr "" +msgstr "token de gramática" #: sphinx/domains/std.py:330 msgid "reference label" -msgstr "" +msgstr "rótulo de referência" #: sphinx/domains/std.py:331 msgid "environment variable" @@ -363,13 +378,16 @@ msgstr "váriavel de ambiente" #: sphinx/domains/std.py:332 msgid "program option" -msgstr "" +msgstr "opção de programa" -#: sphinx/domains/std.py:360 sphinx/themes/basic/genindex-single.html:11 +#: sphinx/domains/std.py:360 +#: sphinx/themes/basic/genindex-single.html:11 #: sphinx/themes/basic/genindex-split.html:11 #: sphinx/themes/basic/genindex-split.html:14 -#: sphinx/themes/basic/genindex.html:11 sphinx/themes/basic/genindex.html:14 -#: sphinx/themes/basic/genindex.html:50 sphinx/themes/basic/layout.html:125 +#: sphinx/themes/basic/genindex.html:11 +#: sphinx/themes/basic/genindex.html:14 +#: sphinx/themes/basic/genindex.html:50 +#: sphinx/themes/basic/layout.html:125 #: sphinx/writers/latex.py:173 msgid "Index" msgstr "Índice" @@ -378,19 +396,20 @@ msgstr "Índice" msgid "Module Index" msgstr "Índice do Módulo" -#: sphinx/domains/std.py:362 sphinx/themes/basic/defindex.html:25 +#: sphinx/domains/std.py:362 +#: sphinx/themes/basic/defindex.html:25 msgid "Search Page" msgstr "Página de Pesquisa" #: sphinx/ext/autodoc.py:917 #, python-format msgid " Bases: %s" -msgstr "" +msgstr " Bases: %s" #: sphinx/ext/autodoc.py:950 #, python-format msgid "alias of :class:`%s`" -msgstr "" +msgstr "apelido de :class:`%s`" #: sphinx/ext/todo.py:41 msgid "Todo" @@ -407,29 +426,28 @@ msgstr "entrada original" #: sphinx/ext/viewcode.py:66 msgid "[source]" -msgstr "" +msgstr "[código fonte]" #: sphinx/ext/viewcode.py:109 msgid "[docs]" -msgstr "" +msgstr "[documentos]" #: sphinx/ext/viewcode.py:123 -#, fuzzy msgid "Module code" -msgstr "módulo" +msgstr "Código do módulo" #: sphinx/ext/viewcode.py:129 #, python-format msgid "

    Source code for %s

    " -msgstr "" +msgstr "

    Código fonte de %s

    " #: sphinx/ext/viewcode.py:156 msgid "Overview: module code" -msgstr "" +msgstr "Visão geral: código do módulo" #: sphinx/ext/viewcode.py:157 msgid "

    All modules for which code is available

    " -msgstr "" +msgstr "

    Todos os módulos onde este código está disponível

    " #: sphinx/locale/__init__.py:139 msgid "Attention" @@ -506,26 +524,31 @@ msgstr "comando" msgid "built-in function" msgstr "função interna" -#: sphinx/themes/agogo/layout.html:45 sphinx/themes/basic/globaltoc.html:10 +#: sphinx/themes/agogo/layout.html:45 +#: sphinx/themes/basic/globaltoc.html:10 #: sphinx/themes/basic/localtoc.html:11 msgid "Table Of Contents" msgstr "Tabela de Conteúdo" -#: sphinx/themes/agogo/layout.html:49 sphinx/themes/basic/layout.html:128 -#: sphinx/themes/basic/search.html:11 sphinx/themes/basic/search.html:14 +#: sphinx/themes/agogo/layout.html:49 +#: sphinx/themes/basic/layout.html:128 +#: sphinx/themes/basic/search.html:11 +#: sphinx/themes/basic/search.html:14 msgid "Search" msgstr "Pesquisar" -#: sphinx/themes/agogo/layout.html:52 sphinx/themes/basic/searchbox.html:15 +#: sphinx/themes/agogo/layout.html:52 +#: sphinx/themes/basic/searchbox.html:15 msgid "Go" msgstr "Ir" -#: sphinx/themes/agogo/layout.html:57 sphinx/themes/basic/searchbox.html:20 -#, fuzzy +#: sphinx/themes/agogo/layout.html:57 +#: sphinx/themes/basic/searchbox.html:20 msgid "Enter search terms or a module, class or function name." -msgstr "Informe o nome de um módulo, classe ou função." +msgstr "Digite os termos da busca ou o nome de um módulo, classe ou função." -#: sphinx/themes/agogo/layout.html:78 sphinx/themes/basic/sourcelink.html:14 +#: sphinx/themes/agogo/layout.html:78 +#: sphinx/themes/basic/sourcelink.html:14 msgid "Show Source" msgstr "Exibir Fonte" @@ -615,12 +638,8 @@ msgstr "Última atualização em %(last_updated)s." #: sphinx/themes/basic/layout.html:189 #, python-format -msgid "" -"Created using Sphinx " -"%(sphinx_version)s." -msgstr "" -"Criado com Sphinx " -"%(sphinx_version)s." +msgid "Created using Sphinx %(sphinx_version)s." +msgstr "Criado com Sphinx %(sphinx_version)s." #: sphinx/themes/basic/opensearch.xml:4 #, python-format @@ -647,10 +666,9 @@ msgstr "próximo capítulo" msgid "" "Please activate JavaScript to enable the search\n" " functionality." -msgstr "" +msgstr "Por favor ative o JavaScript para habilitar a funcionalidade de pesquisa." #: sphinx/themes/basic/search.html:23 -#, fuzzy msgid "" "From here you can search these documents. Enter your search\n" " words into the box below and click \"search\". Note that the search\n" @@ -658,11 +676,9 @@ msgid "" " containing fewer words won't appear in the result list." msgstr "" "A partir daqui você pode pesquisar estes documentos. Preencha suas \n" -" palavras de pesquisa na caixa abaixo e clique em \"pesquisar\". " -"Observe que a função de pesquisa\n" +" palavras de pesquisa na caixa abaixo e clique em \"pesquisar\". Observe que a função de pesquisa\n" " irá pesquisar automaticamente por todas as palavras.\n" -" Páginas contendo menos palavras não irão aparecer na lista de " -"resultado." +" Páginas contendo menos palavras não irão aparecer na lista de resultado." #: sphinx/themes/basic/search.html:30 msgid "search" @@ -713,12 +729,14 @@ msgstr "Alterações na API C" msgid "Other changes" msgstr "Outras alterações" -#: sphinx/themes/basic/static/doctools.js:154 sphinx/writers/html.py:482 +#: sphinx/themes/basic/static/doctools.js:154 +#: sphinx/writers/html.py:482 #: sphinx/writers/html.py:487 msgid "Permalink to this headline" msgstr "Link permanente para este título" -#: sphinx/themes/basic/static/doctools.js:160 sphinx/writers/html.py:87 +#: sphinx/themes/basic/static/doctools.js:160 +#: sphinx/writers/html.py:87 msgid "Permalink to this definition" msgstr "Link permanente para esta definição" @@ -739,51 +757,45 @@ msgid ", in " msgstr ", em " #: sphinx/themes/basic/static/searchtools.js:491 -msgid "" -"Your search did not match any documents. Please make sure that all words " -"are spelled correctly and that you've selected enough categories." -msgstr "" -"Sua pesquisa não encontrou nenhum documento. Por favor assegure-se de que" -" todas as palavras foram digitadas corretamente e de que você tenha " -"selecionado o mínimo de categorias." +msgid "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." +msgstr "Sua pesquisa não encontrou nenhum documento. Por favor assegure-se de que todas as palavras foram digitadas corretamente e de que você tenha selecionado o mínimo de categorias." #: sphinx/themes/basic/static/searchtools.js:493 #, python-format msgid "Search finished, found %s page(s) matching the search query." -msgstr "" -"Pesquisa finalizada, foram encontrada(s) %s página(s) que conferem com o " -"critério de pesquisa." +msgstr "Pesquisa finalizada, foram encontrada(s) %s página(s) que conferem com o critério de pesquisa." #: sphinx/themes/default/static/sidebar.js:66 msgid "Expand sidebar" -msgstr "" +msgstr "Expandir painel lateral" #: sphinx/themes/default/static/sidebar.js:79 #: sphinx/themes/default/static/sidebar.js:106 msgid "Collapse sidebar" -msgstr "" +msgstr "Recolher painel lateral" #: sphinx/themes/haiku/layout.html:26 msgid "Contents" -msgstr "" +msgstr "Conteúdo" #: sphinx/writers/latex.py:171 msgid "Release" msgstr "Versão" -#: sphinx/writers/latex.py:572 sphinx/writers/manpage.py:178 +#: sphinx/writers/latex.py:572 +#: sphinx/writers/manpage.py:178 msgid "Footnotes" -msgstr "" +msgstr "Notas de rodapé" #: sphinx/writers/latex.py:641 msgid "continued from previous page" -msgstr "" +msgstr "continuação da página anterior" #: sphinx/writers/latex.py:646 -#, fuzzy msgid "Continued on next page" -msgstr "Índice completo em uma página" +msgstr "Continua na próxima página" #: sphinx/writers/text.py:422 msgid "[image]" msgstr "[imagem]" + From 28fc52559c07f9287a1f198da27a6548e50f1344 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 2 Jul 2010 11:44:01 +0200 Subject: [PATCH 121/207] Activate oldcmarkup by default, but warn when the markup is used. --- CHANGES | 7 ++++--- sphinx/application.py | 4 +++- sphinx/ext/oldcmarkup.py | 11 +++++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 4be9eed82..fb5d0b3c7 100644 --- a/CHANGES +++ b/CHANGES @@ -15,9 +15,10 @@ Incompatible changes - JavaScript - reStructuredText -* The old markup for defining and linking to C directives will not work - anymore without activating the :mod:`~sphinx.ext.oldcmarkup` - extension. +* The old markup for defining and linking to C directives is now + deprecated. It will not work anymore in future versions without + activating the :mod:`~sphinx.ext.oldcmarkup` extension; in Sphinx + 1.0, it is activated by default. * Removed support for old dependency versions; requirements are now: diff --git a/sphinx/application.py b/sphinx/application.py index 3ffd86c26..97778d3fb 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -109,7 +109,9 @@ class Sphinx(object): if self.confdir is None: self.confdir = self.srcdir - # load all extension modules + # backwards compatibility: activate old C markup + self.setup_extension('sphinx.ext.oldcmarkup') + # load all user-given extension modules for extension in self.config.extensions: self.setup_extension(extension) # the config file itself can be an extension diff --git a/sphinx/ext/oldcmarkup.py b/sphinx/ext/oldcmarkup.py index 62f5ee28d..c2172b088 100644 --- a/sphinx/ext/oldcmarkup.py +++ b/sphinx/ext/oldcmarkup.py @@ -13,6 +13,10 @@ from docutils.parsers.rst import directives from sphinx.util.compat import Directive +_warned_oldcmarkup = False +WARNING_MSG = 'using old C markup; please migrate to new-style markup ' \ + '(e.g. c:function instead of cfunction), see ' \ + 'http://sphinx.pocoo.org/domains.html' class OldCDirective(Directive): has_content = True @@ -26,6 +30,9 @@ class OldCDirective(Directive): def run(self): env = self.state.document.settings.env + if not env.app._oldcmarkup_warned: + env.warn(env.docname, WARNING_MSG, self.lineno) + env.app._oldcmarkup_warned = True newname = 'c:' + self.name[1:] newdir = env.lookup_domain_element('directive', newname)[0] return newdir(newname, self.arguments, self.options, @@ -35,12 +42,16 @@ class OldCDirective(Directive): def old_crole(typ, rawtext, text, lineno, inliner, options={}, content=[]): env = inliner.document.settings.env + if not env.app._oldcmarkup_warned: + env.warn(env.docname, WARNING_MSG) + env.app._oldcmarkup_warned = True newtyp = 'c:' + typ[1:] newrole = env.lookup_domain_element('role', newtyp)[0] return newrole(newtyp, rawtext, text, lineno, inliner, options, content) def setup(app): + app._oldcmarkup_warned = False app.add_directive('cfunction', OldCDirective) app.add_directive('cmember', OldCDirective) app.add_directive('cmacro', OldCDirective) From 2cbaded7019ce7a1e641aaa5f444daf1375275dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Fri, 2 Jul 2010 16:44:05 +0200 Subject: [PATCH 122/207] Add test for oldcmarkup warning --- tests/test_build_html.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_build_html.py b/tests/test_build_html.py index fe249f44a..a1d993570 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -39,6 +39,9 @@ http://www.python.org/logo.png reading included file u'wrongenc.inc' seems to be wrong, try giving an \ :encoding: option %(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png +%(root)s/objects.txt:79: WARNING: using old C markup; please migrate to \ +new-style markup \(e.g. c:function instead of cfunction\), see \ +http://sphinx.pocoo.org/domains.html """ HTML_WARNINGS = ENV_WARNINGS + """\ From b57c71b78498d57c6e7270455525f0f6d5458e06 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 3 Jul 2010 10:28:28 +0200 Subject: [PATCH 123/207] Small logic fix to work around precedence bug in Jinja 2.1.x. --- sphinx/themes/basic/layout.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html index 1dac66938..e31e85443 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -14,7 +14,7 @@ {%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %} {%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %} {%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and - (not sidebars == []) %} + (sidebars != []) %} {%- set url_root = pathto('', 1) %} {%- if url_root == '#' %}{% set url_root = '' %}{% endif %} From e06a11bd644328ac36fc760c485922de6c9c3826 Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Thu, 8 Jul 2010 21:42:16 +0200 Subject: [PATCH 124/207] Replace colons with hyphens in id and href attributes for the epub builder. --- sphinx/builders/epub.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index a5f7a84d0..2f6ecab59 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -14,6 +14,7 @@ import os import codecs from os import path import zipfile +import re from docutils import nodes from docutils.transforms import Transform @@ -21,6 +22,7 @@ from docutils.transforms import Transform from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.util.osutil import EEXIST from sphinx.util.smartypants import sphinx_smarty_pants as ssp +from sphinx import addnodes # (Fragment) templates from which the metainfo files content.opf, toc.ncx, @@ -144,7 +146,6 @@ class VisibleLinksTransform(Transform): link['classes'].append(_css_link_target_class) ref.parent.insert(idx, link) - # The epub publisher class EpubBuilder(StandaloneHTMLBuilder): @@ -243,6 +244,33 @@ class EpubBuilder(StandaloneHTMLBuilder): 'text': ssp(self.esc(text)) }) + def fix_ids(self, tree): + """Replace colons with hyphens in href and id attributes. + Some readers crash because they interpret the part as a + transport protocol specification. + """ + refuri_pat = re.compile("([^#:]*)#([^:]*):(.*)") + refid_pat = re.compile("([^:]*):(.*)") + + for node in tree.traverse(nodes.reference): + if 'refuri' in node: + node['refuri'] = refuri_pat.sub("\\1#\\2-\\3", node['refuri']) + if 'refid' in node: + node['refid'] = refid_pat.sub("\\1-\\2", node['refid']) + for node in tree.traverse(addnodes.desc_signature): + ids = node.attributes['ids'] + newids = [] + for id in ids: + id = refid_pat.sub("\\1-\\2", id) + newids.append(id) + node.attributes['ids'] = newids + + def write_doc(self, docname, doctree): + """Write one document file. + This method is overwritten in order to fix the URIs. + """ + self.fix_ids(doctree) + return StandaloneHTMLBuilder.write_doc(self, docname, doctree) # Finish by building the epub file def handle_finish(self): From 8c64eddb8dcb74fe09b47991d2d1ab9a51f163c6 Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Thu, 8 Jul 2010 22:00:27 +0200 Subject: [PATCH 125/207] Re-added visible links; this time not as docutils.transform. --- sphinx/builders/epub.py | 45 +++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index 2f6ecab59..6965f2a9b 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -17,7 +17,6 @@ import zipfile import re from docutils import nodes -from docutils.transforms import Transform from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.util.osutil import EEXIST @@ -123,29 +122,6 @@ _media_types = { } -# The transform to show link targets - -class VisibleLinksTransform(Transform): - """ - Add the link target of references to the text, unless it is already - present in the description. - """ - - # This transform must run after the references transforms - default_priority = 680 - - def apply(self): - for ref in self.document.traverse(nodes.reference): - uri = ref.get('refuri', '') - if ( uri.startswith('http:') or uri.startswith('https:') or \ - uri.startswith('ftp:') ) and uri not in ref.astext(): - uri = _link_target_template % {'uri': uri} - if uri: - idx = ref.parent.index(ref) + 1 - link = nodes.inline(uri, uri) - link['classes'].append(_css_link_target_class) - ref.parent.insert(idx, link) - # The epub publisher class EpubBuilder(StandaloneHTMLBuilder): @@ -172,10 +148,6 @@ class EpubBuilder(StandaloneHTMLBuilder): # the output files for epub must be .html only self.out_suffix = '.html' self.playorder = 0 - # Disable transform until the issue with cached doctrees is solved. - # Building the html file after the epub file shows the - # visible links also in the HTML output. - #self.app.add_transform(VisibleLinksTransform) def get_theme_config(self): return self.config.epub_theme, {} @@ -265,11 +237,26 @@ class EpubBuilder(StandaloneHTMLBuilder): newids.append(id) node.attributes['ids'] = newids + def add_visible_links(self, tree): + """Append visible link targets after external links. + """ + for node in tree.traverse(nodes.reference): + uri = node.get('refuri', '') + if ( uri.startswith('http:') or uri.startswith('https:') or \ + uri.startswith('ftp:') ) and uri not in node.astext(): + uri = _link_target_template % {'uri': uri} + if uri: + idx = node.parent.index(node) + 1 + link = nodes.inline(uri, uri) + link['classes'].append(_css_link_target_class) + node.parent.insert(idx, link) + def write_doc(self, docname, doctree): """Write one document file. - This method is overwritten in order to fix the URIs. + This method is overwritten in order to fix a few things. """ self.fix_ids(doctree) + self.add_visible_links(doctree) return StandaloneHTMLBuilder.write_doc(self, docname, doctree) # Finish by building the epub file From d6a0ac11e18d885f0d228dbbe5d9e6b2c7c28095 Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Thu, 8 Jul 2010 23:14:44 +0200 Subject: [PATCH 126/207] Proper fix for missing refuri attribute; it's has_key, not hasattr. --- sphinx/builders/epub.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index 6965f2a9b..1142c766a 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -171,7 +171,7 @@ class EpubBuilder(StandaloneHTMLBuilder): """Collect section titles, their depth in the toc and the refuri.""" # XXX: is there a better way than checking the attribute # toctree-l[1-8] on the parent node? - if isinstance(doctree, nodes.reference) and hasattr(doctree, 'refuri'): + if isinstance(doctree, nodes.reference) and doctree.has_key('refuri'): refuri = doctree['refuri'] if refuri.startswith('http://') or refuri.startswith('https://') \ or refuri.startswith('irc:') or refuri.startswith('mailto:'): From 1d4f0c3f694adf54f3d19e1a8c0d7293fc1fa7c5 Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Sat, 10 Jul 2010 14:41:40 +0200 Subject: [PATCH 127/207] Better fix to replace colons with hyphens --- sphinx/builders/epub.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index 1142c766a..c8dafb5ef 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -221,20 +221,23 @@ class EpubBuilder(StandaloneHTMLBuilder): Some readers crash because they interpret the part as a transport protocol specification. """ - refuri_pat = re.compile("([^#:]*)#([^:]*):(.*)") - refid_pat = re.compile("([^:]*):(.*)") + # Replace colons only in local fragment identifiers. + # If the URI contains a colon before the #, + # it is an external link that should not change. + refuri_pat = re.compile("([^#:]*#)(.*)") for node in tree.traverse(nodes.reference): if 'refuri' in node: - node['refuri'] = refuri_pat.sub("\\1#\\2-\\3", node['refuri']) + m = refuri_pat.match(node['refuri']) + if m: + node['refuri'] = m.group(1) + m.group(2).replace(':', '-') if 'refid' in node: - node['refid'] = refid_pat.sub("\\1-\\2", node['refid']) + node['refid'] = node['refid'].replace(':', '-') for node in tree.traverse(addnodes.desc_signature): ids = node.attributes['ids'] newids = [] for id in ids: - id = refid_pat.sub("\\1-\\2", id) - newids.append(id) + newids.append(id.replace(':', '-')) node.attributes['ids'] = newids def add_visible_links(self, tree): From 7cbe0588a977adb79c3c7b1c64b2220122dfe313 Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Sat, 10 Jul 2010 16:33:43 +0200 Subject: [PATCH 128/207] Added new config parameter epub_tocdup. --- doc/config.rst | 6 ++++++ sphinx/builders/epub.py | 2 +- sphinx/config.py | 1 + sphinx/quickstart.py | 3 +++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/config.rst b/doc/config.rst index ee3a2ec58..5326387de 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -782,6 +782,12 @@ the `Dublin Core metadata `_. be an integer greater than zero. The default value is 3. Note: A deeply nested table of contents may be difficult to navigate. +.. confval:: epub_tocdup + + This flag determines if a toc entry is inserted again at the beginning of + it's nested toc listing. This allows easier navitation to the top of + a chapter, but can be confusing because it mixes entries of differnet + depth in one list. The default value is ``True``. .. _latex-options: diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index c8dafb5ef..5f16c274a 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -406,7 +406,7 @@ class EpubBuilder(StandaloneHTMLBuilder): navstack.append(navlist) navlist = [] level += 1 - if lastnode: + if lastnode and self.config.epub_tocdup: # Insert starting point in subtoc with same playOrder navlist.append(self.new_navpoint(lastnode, level, False)) navlist.append(self.new_navpoint(node, level)) diff --git a/sphinx/config.py b/sphinx/config.py index e1075ff6a..12c2a04ba 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -124,6 +124,7 @@ class Config(object): epub_post_files = ([], 'env'), epub_exclude_files = ([], 'env'), epub_tocdepth = (3, 'env'), + epub_tocdup = (True, 'env'), # LaTeX options latex_documents = ([], None), diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 28dd3c91d..d07472bc8 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -279,6 +279,9 @@ epub_copyright = u'%(copyright_str)s' # The depth of the table of contents in toc.ncx. #epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True ''' INTERSPHINX_CONFIG = ''' From d0900e8862d35823399802cbd4d39e114608210c Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 10 Jul 2010 16:50:32 +0200 Subject: [PATCH 129/207] #465: update version requirement. --- doc/intro.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/intro.rst b/doc/intro.rst index 33f97a3f8..1a39e266c 100644 --- a/doc/intro.rst +++ b/doc/intro.rst @@ -45,13 +45,15 @@ See the :ref:`pertinent section in the FAQ list `. Prerequisites ------------- -Sphinx needs at least **Python 2.4** to run. If you like to have source code -highlighting support, you must also install the Pygments_ library, which you can -do via setuptools' easy_install. Sphinx should work with docutils version 0.4 -or some (not broken) SVN trunk snapshot. +Sphinx needs at least **Python 2.4** to run, as well as the docutils_ and +Jinja2_ libraries. Sphinx should work with docutils version 0.5 or some +(not broken) SVN trunk snapshot. If you like to have source code highlighting +support, you must also install the Pygments_ library. .. _reStructuredText: http://docutils.sf.net/rst.html -.. _Pygments: http://pygments.org +.. _docutils: http://docutils.sf.net/ +.. _Jinja2: http://jinja.pocoo.org/2/ +.. _Pygments: http://pygments.org/ Usage From 400617e692b2a17148908e35cb25de920be76b77 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 10 Jul 2010 16:59:23 +0200 Subject: [PATCH 130/207] #461: elaborate how to use intersphinx. --- doc/ext/intersphinx.rst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/doc/ext/intersphinx.rst b/doc/ext/intersphinx.rst index 29b4057f1..bb2a5a8c4 100644 --- a/doc/ext/intersphinx.rst +++ b/doc/ext/intersphinx.rst @@ -9,7 +9,21 @@ .. versionadded:: 0.5 This extension can generate automatic links to the documentation of objects in -other projects. This works as follows: +other projects. + +Usage is simple: whenever Sphinx encounters a cross-reference that has no +matching target in the current documentation set, it looks for targets in the +documentation sets configured in :confval:`intersphinx_mapping`. A reference +like ``:py:class:`zipfile.ZipFile``` can then link to the Python documentation +for the ZipFile class, without you having to specify where it is located +exactly. + +When using the "new" format (see below), you can even force lookup in a foreign +set by prefixing the link target appropriately. A link like ``:ref:`comparison +manual ``` will then link to the label "comparisons" in the +doc set "python", if it exists. + +Behind the scenes, this works as follows: * Each Sphinx HTML build creates a file named :file:`objects.inv` that contains a mapping from object names to URIs relative to the HTML set's root. From 9f4c61b15415bcb219c3e238092421738b2a677e Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 11 Jul 2010 11:00:07 +0200 Subject: [PATCH 131/207] #391: do not report local links as "malformed" in the linkcheck builder. --- sphinx/builders/linkcheck.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index c9bc363d1..4a0bab633 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -16,7 +16,7 @@ from urllib2 import build_opener, HTTPError from docutils import nodes from sphinx.builders import Builder -from sphinx.util.console import purple, red, darkgreen +from sphinx.util.console import purple, red, darkgreen, darkgray # create an opener that will simulate a browser user-agent opener = build_opener() @@ -71,9 +71,12 @@ class CheckExternalLinksBuilder(Builder): break lineno = node.line + if len(uri) == 0 or uri[0:7] == 'mailto:' or uri[0:4] == 'ftp:': + return + + if lineno: + self.info('(line %3d) ' % lineno, nonl=1) if uri[0:5] == 'http:' or uri[0:6] == 'https:': - if lineno: - self.info('(line %3d) ' % lineno, nonl=1) self.info(uri, nonl=1) if uri in self.broken: @@ -98,15 +101,9 @@ class CheckExternalLinksBuilder(Builder): self.write_entry('redirected', docname, lineno, uri + ' to ' + s) self.redirected[uri] = (r, s) - elif len(uri) == 0 or uri[0:7] == 'mailto:' or uri[0:4] == 'ftp:': - return else: - self.warn(uri + ' - ' + red('malformed!')) - self.write_entry('malformed', docname, lineno, uri) - if self.app.quiet: - self.warn('malformed link: %s' % uri, - '%s:%s' % (self.env.doc2path(docname), lineno)) - self.app.statuscode = 1 + self.info(uri + ' - ' + darkgray('local')) + self.write_entry('local', docname, lineno, uri) if self.broken: self.app.statuscode = 1 From c8e1fd449db952db7996dc3f4c018cbf7dabc671 Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Wed, 14 Jul 2010 22:53:22 +0200 Subject: [PATCH 132/207] Replace colons with hyphens in genindex pages for the epub builder. --- sphinx/builders/epub.py | 45 ++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index 5f16c274a..f96868f01 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -121,6 +121,11 @@ _media_types = { '.ttf': 'application/x-font-ttf', } +# Regular expression to match colons only in local fragment identifiers. +# If the URI contains a colon before the #, +# it is an external link that should not change. +_refuri_re = re.compile("([^#:]*#)(.*)") + # The epub publisher @@ -221,14 +226,9 @@ class EpubBuilder(StandaloneHTMLBuilder): Some readers crash because they interpret the part as a transport protocol specification. """ - # Replace colons only in local fragment identifiers. - # If the URI contains a colon before the #, - # it is an external link that should not change. - refuri_pat = re.compile("([^#:]*#)(.*)") - for node in tree.traverse(nodes.reference): if 'refuri' in node: - m = refuri_pat.match(node['refuri']) + m = _refuri_re.match(node['refuri']) if m: node['refuri'] = m.group(1) + m.group(2).replace(':', '-') if 'refid' in node: @@ -256,12 +256,43 @@ class EpubBuilder(StandaloneHTMLBuilder): def write_doc(self, docname, doctree): """Write one document file. - This method is overwritten in order to fix a few things. + This method is overwritten in order to fix fragment identifiers + and to add visible external links. """ self.fix_ids(doctree) self.add_visible_links(doctree) return StandaloneHTMLBuilder.write_doc(self, docname, doctree) + def fix_genindex(self, tree): + """Fix href attributes for genindex pages. + """ + # XXX: modifies tree inline + # Logic modeled from themes/basic/genindex.html + for key, columns in tree: + for entryname, (links, subitems) in columns: + for (i, link) in enumerate(links): + m = _refuri_re.match(link) + if m: + links[i] = m.group(1) + m.group(2).replace(':', '-') + for subentryname, subentrylinks in subitems: + for (i, link) in enumerate(subentrylinks): + m = _refuri_re.match(link) + if m: + subentrylinks[i] = \ + m.group(1) + m.group(2).replace(':', '-') + + def handle_page(self, pagename, addctx, templatename='page.html', + outfilename=None, event_arg=None): + """Create a rendered page. + This method is overwritten for genindex pages in order to fix + href link attributes. + """ + if pagename.startswith('genindex'): + self.fix_genindex(addctx['genindexentries']) + StandaloneHTMLBuilder.handle_page(self, pagename, addctx, templatename, + outfilename, event_arg) + + # Finish by building the epub file def handle_finish(self): """Create the metainfo files and finally the epub.""" From 162cb22cbeb7f5e52b0986501aae0970baf7dfb4 Mon Sep 17 00:00:00 2001 From: Roland Meister Date: Wed, 14 Jul 2010 23:07:27 +0200 Subject: [PATCH 133/207] Moved href replacement of colons to hyphens to fix_fragment for the epub builder. --- sphinx/builders/epub.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py index f96868f01..0a647fb7e 100644 --- a/sphinx/builders/epub.py +++ b/sphinx/builders/epub.py @@ -221,6 +221,11 @@ class EpubBuilder(StandaloneHTMLBuilder): 'text': ssp(self.esc(text)) }) + def fix_fragment(self, match): + """Return a href attribute with colons replaced by hyphens. + """ + return match.group(1) + match.group(2).replace(':', '-') + def fix_ids(self, tree): """Replace colons with hyphens in href and id attributes. Some readers crash because they interpret the part as a @@ -230,7 +235,7 @@ class EpubBuilder(StandaloneHTMLBuilder): if 'refuri' in node: m = _refuri_re.match(node['refuri']) if m: - node['refuri'] = m.group(1) + m.group(2).replace(':', '-') + node['refuri'] = self.fix_fragment(m) if 'refid' in node: node['refid'] = node['refid'].replace(':', '-') for node in tree.traverse(addnodes.desc_signature): @@ -273,13 +278,12 @@ class EpubBuilder(StandaloneHTMLBuilder): for (i, link) in enumerate(links): m = _refuri_re.match(link) if m: - links[i] = m.group(1) + m.group(2).replace(':', '-') + links[i] = self.fix_fragment(m) for subentryname, subentrylinks in subitems: for (i, link) in enumerate(subentrylinks): m = _refuri_re.match(link) if m: - subentrylinks[i] = \ - m.group(1) + m.group(2).replace(':', '-') + subentrylinks[i] = self.fix_fragment(m) def handle_page(self, pagename, addctx, templatename='page.html', outfilename=None, event_arg=None): From 2b29038d0c17c4f4e178448bf6871de668aa0eee Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 17 Jul 2010 19:45:54 +0200 Subject: [PATCH 134/207] The behavior of :confval:`html_file_suffix` changed slightly: the empty string now means "no suffix" instead of "default suffix", use ``None`` for "default suffix". --- CHANGES | 3 +++ doc/config.rst | 4 ++-- sphinx/builders/html.py | 2 +- sphinx/quickstart.py | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index fb5d0b3c7..ef8b69c54 100644 --- a/CHANGES +++ b/CHANGES @@ -81,6 +81,9 @@ Features added - Added :confval:`html_show_copyright` config value. - Added :confval:`latex_show_pagerefs` and :confval:`latex_show_urls` config values. + - The behavior of :confval:`html_file_suffix` changed slightly: the + empty string now means "no suffix" instead of "default suffix", use + ``None`` for "default suffix". * New builders: diff --git a/doc/config.rst b/doc/config.rst index ee3a2ec58..b879e508a 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -626,8 +626,8 @@ that use Sphinx' HTMLWriter class. .. confval:: html_file_suffix - If nonempty, this is the file name suffix for generated HTML files. The - default is ``".html"``. + This is the file name suffix for generated HTML files. The default is + ``".html"``. .. versionadded:: 0.4 diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 6b3eada79..cd205910d 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -99,7 +99,7 @@ class StandaloneHTMLBuilder(Builder): self.init_templates() self.init_highlighter() self.init_translator_class() - if self.config.html_file_suffix: + if self.config.html_file_suffix is not None: self.out_suffix = self.config.html_file_suffix if self.config.html_link_suffix is not None: diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 28dd3c91d..eb0b0a08b 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -186,8 +186,8 @@ html_static_path = ['%(dot)sstatic'] # base URL from which the finished HTML is served. #html_use_opensearch = '' -# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = '%(project_fn)sdoc' From 115b31f6bbb8386a7b499370c4bef917d0237ee7 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 17 Jul 2010 19:52:16 +0200 Subject: [PATCH 135/207] Fix bug in LaTeX label writing: do not generate \phantomsections in \section{}. --- sphinx/writers/latex.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index ea12f0036..15e55b15e 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -963,8 +963,11 @@ class LaTeXTranslator(nodes.NodeVisitor): def add_target(id): # indexing uses standard LaTeX index markup, so the targets # will be generated differently - if not id.startswith('index-'): - self.body.append(self.hypertarget(id)) + if id.startswith('index-'): + return + # do not generate \phantomsection in \section{} + anchor = not self.in_title + self.body.append(self.hypertarget(id, anchor=anchor)) # postpone the labels until after the sectioning command parindex = node.parent.index(node) From e7405554a7fa53b5b50a15499e31786f8bc30863 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 17 Jul 2010 19:52:54 +0200 Subject: [PATCH 136/207] Adjust alignment. --- doc/Makefile | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index b873c7e5a..90fb5af25 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -16,21 +16,21 @@ ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) \ help: @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files called index.html in directories" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files called index.html in directories" @echo " singlehtml to make one big HTML file" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " pickle to make pickle files" - @echo " json to make json files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make Qt help files and project" - @echo " devhelp to make Devhelp files and project" - @echo " epub to make an epub file" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run pdflatex" - @echo " changes to make an overview over all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " pickle to make pickle files" + @echo " json to make json files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make Qt help files and project" + @echo " devhelp to make Devhelp files and project" + @echo " epub to make an epub file" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run pdflatex" + @echo " changes to make an overview over all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" clean: -rm -rf _build/* From 957ca34f0e5431ae7be5a3f276475281291277f2 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Tue, 20 Jul 2010 16:23:31 -0400 Subject: [PATCH 137/207] Include Text as well as Inline nodes in the content for function arguments --- sphinx/util/docfields.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index c975b9b50..de8fc8006 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -222,7 +222,9 @@ class DocFieldTransformer(object): if is_typefield: # filter out only inline nodes; others will result in invalid # markup being written out - content = filter(lambda n: isinstance(n, nodes.Inline), content) + content = filter( + lambda n: isinstance(n, nodes.Inline) or isinstance(n, nodes.Text), + content) if content: types.setdefault(typename, {})[fieldarg] = content continue From 23971336b785ea39dc246bd8902eea4e143cb6ef Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 21 Jul 2010 11:33:24 +0100 Subject: [PATCH 138/207] Fix :guilabel: unescaping, and make some tests actually run. --- .hgignore | 1 + sphinx/roles.py | 3 +- tests/root/markup.txt | 30 ++-- tests/test_build_html.py | 306 +++++++++++++++++++-------------------- 4 files changed, 172 insertions(+), 168 deletions(-) diff --git a/.hgignore b/.hgignore index 612c93310..70ea36a52 100644 --- a/.hgignore +++ b/.hgignore @@ -2,6 +2,7 @@ .*\.egg .*\.so .dir-locals.el +^\.tox \.DS_Store$ ^build/ ^dist/ diff --git a/sphinx/roles.py b/sphinx/roles.py index 0164d7576..d3f3c67e3 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -205,8 +205,9 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner, _amp_re = re.compile(r'(?', u'\N{TRIANGULAR BULLET}') + text = text.replace('-->', u'\N{TRIANGULAR BULLET}') spans = _amp_re.split(text) node = nodes.emphasis(rawtext=rawtext) diff --git a/tests/root/markup.txt b/tests/root/markup.txt index e286d26c3..a72285ed7 100644 --- a/tests/root/markup.txt +++ b/tests/root/markup.txt @@ -97,21 +97,23 @@ Inline markup *Generic inline markup* -* :command:`command` -* :dfn:`dfn` -* :guilabel:`guilabel with &accelerator` -* :kbd:`kbd` -* :mailheader:`mailheader` -* :makevar:`makevar` -* :manpage:`manpage` -* :mimetype:`mimetype` -* :newsgroup:`newsgroup` -* :program:`program` -* :regexp:`regexp` -* :menuselection:`File --> Close` +Adding \n to test unescaping. + +* :command:`command\\n` +* :dfn:`dfn\\n` +* :guilabel:`guilabel with &accelerator and \\n` +* :kbd:`kbd\\n` +* :mailheader:`mailheader\\n` +* :makevar:`makevar\\n` +* :manpage:`manpage\\n` +* :mimetype:`mimetype\\n` +* :newsgroup:`newsgroup\\n` +* :program:`program\\n` +* :regexp:`regexp\\n` +* :menuselection:`File --> Close\\n` * :menuselection:`&File --> &Print` -* :file:`a/{varpart}/b` -* :samp:`print {i}` +* :file:`a/{varpart}/b\\n` +* :samp:`print {i}\\n` *Linking inline markup* diff --git a/tests/test_build_html.py b/tests/test_build_html.py index a1d993570..bafee243a 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -52,182 +52,182 @@ HTML_WARNINGS = ENV_WARNINGS + """\ """ HTML_XPATH = { - 'images.html': { - ".//img[@src='_images/img.png']": '', - ".//img[@src='_images/img1.png']": '', - ".//img[@src='_images/simg.png']": '', - ".//object[@data='_images/svgimg.svg']": '', - ".//embed[@src='_images/svgimg.svg']": '', - }, - 'subdir/images.html': { - ".//img[@src='../_images/img1.png']": '', - ".//img[@src='../_images/rimg.png']": '', - }, - 'subdir/includes.html': { - ".//a[@href='../_downloads/img.png']": '', - ".//img[@src='../_images/img.png']": '', - ".//p": 'This is an include file.', - }, - 'includes.html': { - ".//pre": u'Max Strauß', - ".//a[@href='_downloads/img.png']": '', - ".//a[@href='_downloads/img1.png']": '', - ".//pre": u'"quotes"', - ".//pre": u"'included'", - }, - 'autodoc.html': { - ".//dt[@id='test_autodoc.Class']": '', - ".//dt[@id='test_autodoc.function']/em": r'\*\*kwds', - ".//dd/p": r'Return spam\.', - }, - 'extapi.html': { - ".//strong": 'from function: Foo', - ".//strong": 'from class: Bar', - }, - 'markup.html': { - ".//title": 'set by title directive', - ".//p/em": 'Section author: Georg Brandl', - ".//p/em": 'Module author: Georg Brandl', + 'images.html': [ + (".//img[@src='_images/img.png']", ''), + (".//img[@src='_images/img1.png']", ''), + (".//img[@src='_images/simg.png']", ''), + (".//object[@data='_images/svgimg.svg']", ''), + (".//embed[@src='_images/svgimg.svg']", ''), + ], + 'subdir/images.html': [ + (".//img[@src='../_images/img1.png']", ''), + (".//img[@src='../_images/rimg.png']", ''), + ], + 'subdir/includes.html': [ + (".//a[@href='../_downloads/img.png']", ''), + (".//img[@src='../_images/img.png']", ''), + (".//p", 'This is an include file.'), + ], + 'includes.html': [ + (".//pre", u'Max Strauß'), + (".//a[@href='_downloads/img.png']", ''), + (".//a[@href='_downloads/img1.png']", ''), + (".//pre", u'"quotes"'), + (".//pre", u"'included'"), + ], + 'autodoc.html': [ + (".//dt[@id='test_autodoc.Class']", ''), + (".//dt[@id='test_autodoc.function']/em", r'\*\*kwds'), + (".//dd/p", r'Return spam\.'), + ], + 'extapi.html': [ + (".//strong", 'from function: Foo'), + (".//strong", 'from class: Bar'), + ], + 'markup.html': [ + (".//title", 'set by title directive'), + (".//p/em", 'Section author: Georg Brandl'), + (".//p/em", 'Module author: Georg Brandl'), # created by the meta directive - ".//meta[@name='author'][@content='Me']": '', - ".//meta[@name='keywords'][@content='docs, sphinx']": '', + (".//meta[@name='author'][@content='Me']", ''), + (".//meta[@name='keywords'][@content='docs, sphinx']", ''), # a label created by ``.. _label:`` - ".//div[@id='label']": '', + (".//div[@id='label']", ''), # code with standard code blocks - ".//pre": '^some code$', + (".//pre", '^some code$'), # an option list - ".//span[@class='option']": '--help', + (".//span[@class='option']", '--help'), # admonitions - ".//p[@class='first admonition-title']": 'My Admonition', - ".//p[@class='last']": 'Note text.', - ".//p[@class='last']": 'Warning text.', + (".//p[@class='first admonition-title']", 'My Admonition'), + (".//p[@class='last']", 'Note text.'), + (".//p[@class='last']", 'Warning text.'), # inline markup - ".//li/strong": '^command$', - ".//li/strong": '^program$', - ".//li/em": '^dfn$', - ".//li/tt/span[@class='pre']": '^kbd$', - ".//li/em": u'File \N{TRIANGULAR BULLET} Close', - ".//li/tt/span[@class='pre']": '^a/$', - ".//li/tt/em/span[@class='pre']": '^varpart$', - ".//li/tt/em/span[@class='pre']": '^i$', - ".//a[@href='http://www.python.org/dev/peps/pep-0008']" - "[@class='pep reference external']/strong": 'PEP 8', - ".//a[@href='http://tools.ietf.org/html/rfc1.html']" - "[@class='rfc reference external']/strong": 'RFC 1', - ".//a[@href='objects.html#envvar-HOME']" - "[@class='reference internal']/tt/span[@class='pre']": 'HOME', - ".//a[@href='#with']" - "[@class='reference internal']/tt/span[@class='pre']": '^with$', - ".//a[@href='#grammar-token-try_stmt']" - "[@class='reference internal']/tt/span": '^statement$', - ".//a[@href='subdir/includes.html']" - "[@class='reference internal']/em": 'Including in subdir', - ".//a[@href='objects.html#cmdoption-python-c']" - "[@class='reference internal']/em": 'Python -c option', + (".//li/strong", r'^command\\n$'), + (".//li/strong", r'^program\\n$'), + (".//li/em", r'^dfn\\n$'), + (".//li/tt/span[@class='pre']", r'^kbd\\n$'), + (".//li/em", u'File \N{TRIANGULAR BULLET} Close'), + (".//li/tt/span[@class='pre']", '^a/$'), + (".//li/tt/em/span[@class='pre']", '^varpart$'), + (".//li/tt/em/span[@class='pre']", '^i$'), + (".//a[@href='http://www.python.org/dev/peps/pep-0008']" + "[@class='pep reference external']/strong", 'PEP 8'), + (".//a[@href='http://tools.ietf.org/html/rfc1.html']" + "[@class='rfc reference external']/strong", 'RFC 1'), + (".//a[@href='objects.html#envvar-HOME']" + "[@class='reference internal']/tt/span[@class='pre']", 'HOME'), + (".//a[@href='#with']" + "[@class='reference internal']/tt/span[@class='pre']", '^with$'), + (".//a[@href='#grammar-token-try_stmt']" + "[@class='reference internal']/tt/span", '^statement$'), + (".//a[@href='subdir/includes.html']" + "[@class='reference internal']/em", 'Including in subdir'), + (".//a[@href='objects.html#cmdoption-python-c']" + "[@class='reference internal']/em", 'Python -c option'), # abbreviations - ".//abbr[@title='abbreviation']": '^abbr$', + (".//abbr[@title='abbreviation']", '^abbr$'), # version stuff - ".//span[@class='versionmodified']": 'New in version 0.6', + (".//span[@class='versionmodified']", 'New in version 0.6'), # footnote reference - ".//a[@class='footnote-reference']": r'\[1\]', + (".//a[@class='footnote-reference']", r'\[1\]'), # created by reference lookup - ".//a[@href='contents.html#ref1']": '', + (".//a[@href='contents.html#ref1']", ''), # ``seealso`` directive - ".//div/p[@class='first admonition-title']": 'See also', + (".//div/p[@class='first admonition-title']", 'See also'), # a ``hlist`` directive - ".//table[@class='hlist']/tr/td/ul/li": '^This$', + (".//table[@class='hlist']/tr/td/ul/li", '^This$'), # a ``centered`` directive - ".//p[@class='centered']/strong": 'LICENSE', + (".//p[@class='centered']/strong", 'LICENSE'), # a glossary - ".//dl/dt[@id='term-boson']": 'boson', + (".//dl/dt[@id='term-boson']", 'boson'), # a production list - ".//pre/strong": 'try_stmt', - ".//pre/a[@href='#grammar-token-try1_stmt']/tt/span": 'try1_stmt', + (".//pre/strong", 'try_stmt'), + (".//pre/a[@href='#grammar-token-try1_stmt']/tt/span", 'try1_stmt'), # tests for ``only`` directive - ".//p": 'A global substitution.', - ".//p": 'In HTML.', - ".//p": 'In both.', - ".//p": 'Always present', - }, - 'objects.html': { - ".//dt[@id='mod.Cls.meth1']": '', - ".//dt[@id='errmod.Error']": '', - ".//a[@href='#mod.Cls'][@class='reference internal']": '', - ".//dl[@class='userdesc']": '', - ".//dt[@id='userdesc-myobj']": '', - ".//a[@href='#userdesc-myobj']": '', + (".//p", 'A global substitution.'), + (".//p", 'In HTML.'), + (".//p", 'In both.'), + (".//p", 'Always present'), + ], + 'objects.html': [ + (".//dt[@id='mod.Cls.meth1']", ''), + (".//dt[@id='errmod.Error']", ''), + (".//a[@href='#mod.Cls'][@class='reference internal']", ''), + (".//dl[@class='userdesc']", ''), + (".//dt[@id='userdesc-myobj']", ''), + (".//a[@href='#userdesc-myobj']", ''), # C references - ".//span[@class='pre']": 'CFunction()', - ".//a[@href='#Sphinx_DoSomething']": '', - ".//a[@href='#SphinxStruct.member']": '', - ".//a[@href='#SPHINX_USE_PYTHON']": '', - ".//a[@href='#SphinxType']": '', - ".//a[@href='#sphinx_global']": '', + (".//span[@class='pre']", 'CFunction()'), + (".//a[@href='#Sphinx_DoSomething']", ''), + (".//a[@href='#SphinxStruct.member']", ''), + (".//a[@href='#SPHINX_USE_PYTHON']", ''), + (".//a[@href='#SphinxType']", ''), + (".//a[@href='#sphinx_global']", ''), # reference from old C markup extension - ".//a[@href='#Sphinx_Func']": '', + (".//a[@href='#Sphinx_Func']", ''), # test global TOC created by toctree() - ".//ul[@class='current']/li[@class='toctree-l1 current']/a[@href='']": - 'Testing object descriptions', - ".//li[@class='toctree-l1']/a[@href='markup.html']": - 'Testing various markup', + (".//ul[@class='current']/li[@class='toctree-l1 current']/a[@href='']", + 'Testing object descriptions'), + (".//li[@class='toctree-l1']/a[@href='markup.html']", + 'Testing various markup'), # custom sidebar - ".//h4": 'Custom sidebar', - }, - 'contents.html': { - ".//meta[@name='hc'][@content='hcval']": '', - ".//meta[@name='hc_co'][@content='hcval_co']": '', - ".//meta[@name='testopt'][@content='testoverride']": '', - ".//td[@class='label']": r'\[Ref1\]', - ".//td[@class='label']": '', - ".//li[@class='toctree-l1']/a": 'Testing various markup', - ".//li[@class='toctree-l2']/a": 'Inline markup', - ".//title": 'Sphinx ', - ".//div[@class='footer']": 'Georg Brandl & Team', - ".//a[@href='http://python.org/']" - "[@class='reference external']": '', - ".//li/a[@href='genindex.html']/em": 'Index', - ".//li/a[@href='py-modindex.html']/em": 'Module Index', - ".//li/a[@href='search.html']/em": 'Search Page', + (".//h4", 'Custom sidebar'), + ], + 'contents.html': [ + (".//meta[@name='hc'][@content='hcval']", ''), + (".//meta[@name='hc_co'][@content='hcval_co']", ''), + (".//meta[@name='testopt'][@content='testoverride']", ''), + (".//td[@class='label']", r'\[Ref1\]'), + (".//td[@class='label']", ''), + (".//li[@class='toctree-l1']/a", 'Testing various markup'), + (".//li[@class='toctree-l2']/a", 'Inline markup'), + (".//title", 'Sphinx '), + (".//div[@class='footer']", 'Georg Brandl & Team'), + (".//a[@href='http://python.org/']" + "[@class='reference external']", ''), + (".//li/a[@href='genindex.html']/em", 'Index'), + (".//li/a[@href='py-modindex.html']/em", 'Module Index'), + (".//li/a[@href='search.html']/em", 'Search Page'), # custom sidebar only for contents - ".//h4": 'Contents sidebar', - }, - 'bom.html': { - ".//title": " File with UTF-8 BOM", - }, - 'extensions.html': { - ".//a[@href='http://python.org/dev/']": "http://python.org/dev/", - ".//a[@href='http://bugs.python.org/issue1000']": "issue 1000", - ".//a[@href='http://bugs.python.org/issue1042']": "explicit caption", - }, - '_static/statictmpl.html': { - ".//project": 'Sphinx ', - }, + (".//h4", 'Contents sidebar'), + ], + 'bom.html': [ + (".//title", " File with UTF-8 BOM"), + ], + 'extensions.html': [ + (".//a[@href='http://python.org/dev/']", "http://python.org/dev/"), + (".//a[@href='http://bugs.python.org/issue1000']", "issue 1000"), + (".//a[@href='http://bugs.python.org/issue1042']", "explicit caption"), + ], + '_static/statictmpl.html': [ + (".//project", 'Sphinx '), + ], } if pygments: - HTML_XPATH['includes.html'].update({ - ".//pre/span[@class='s']": u'üöä', - ".//div[@class='inc-pyobj1 highlight-text']//pre": - r'^class Foo:\n pass\n\s*$', - ".//div[@class='inc-pyobj2 highlight-text']//pre": - r'^ def baz\(\):\n pass\n\s*$', - ".//div[@class='inc-lines highlight-text']//pre": - r'^class Foo:\n pass\nclass Bar:\n$', - ".//div[@class='inc-startend highlight-text']//pre": - ur'^foo = u"Including Unicode characters: üöä"\n$', - ".//div[@class='inc-preappend highlight-text']//pre": - r'(?m)^START CODE$', - ".//div[@class='inc-pyobj-dedent highlight-python']//span": - r'def', - ".//div[@class='inc-tab3 highlight-text']//pre": - r'-| |-', - ".//div[@class='inc-tab8 highlight-python']//pre": - r'-| |-', - }) - HTML_XPATH['subdir/includes.html'].update({ - ".//pre/span": 'line 1', - ".//pre/span": 'line 2', - }) + HTML_XPATH['includes.html'].extend([ + (".//pre/span[@class='s']", u'üöä'), + (".//div[@class='inc-pyobj1 highlight-text']//pre", + r'^class Foo:\n pass\n\s*$'), + (".//div[@class='inc-pyobj2 highlight-text']//pre", + r'^ def baz\(\):\n pass\n\s*$'), + (".//div[@class='inc-lines highlight-text']//pre", + r'^class Foo:\n pass\nclass Bar:\n$'), + (".//div[@class='inc-startend highlight-text']//pre", + ur'^foo = u"Including Unicode characters: üöä"\n$'), + (".//div[@class='inc-preappend highlight-text']//pre", + r'(?m)^START CODE$'), + (".//div[@class='inc-pyobj-dedent highlight-python']//span", + r'def'), + (".//div[@class='inc-tab3 highlight-text']//pre", + r'-| |-'), + (".//div[@class='inc-tab8 highlight-python']//pre", + r'-| |-'), + ]) + HTML_XPATH['subdir/includes.html'].extend([ + (".//pre/span", 'line 1'), + (".//pre/span", 'line 2'), + ]) class NslessParser(ET.XMLParser): """XMLParser that throws away namespaces in tag names.""" @@ -292,7 +292,7 @@ def test_html(app): parser = NslessParser() parser.entity.update(htmlentitydefs.entitydefs) etree = ET.parse(os.path.join(app.outdir, fname), parser) - for path, check in paths.iteritems(): + for path, check in paths: yield check_xpath, etree, fname, path, check check_static_entries(app.builder.outdir) From 345f39160a0098b53e09852a14fd49b2626e0d8b Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 23 Jul 2010 10:37:44 +0100 Subject: [PATCH 139/207] Add tox.ini. --- tox.ini | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tox.ini diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..51779d871 --- /dev/null +++ b/tox.ini @@ -0,0 +1,6 @@ +[tox] +envlist=py26 + +[testenv] +deps=nose +commands=nosetests From e79ffd263d58140380108d24d4b2cf1e2369925b Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 23 Jul 2010 10:44:36 +0100 Subject: [PATCH 140/207] Do not use normpath when not necessary. --- sphinx/directives/code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py index aff4395fb..0647daf09 100644 --- a/sphinx/directives/code.py +++ b/sphinx/directives/code.py @@ -102,7 +102,7 @@ class LiteralInclude(Directive): rel_fn = filename[1:] else: docdir = path.dirname(env.doc2path(env.docname, base=None)) - rel_fn = path.normpath(path.join(docdir, filename)) + rel_fn = path.join(docdir, filename) try: fn = path.join(env.srcdir, rel_fn) except UnicodeDecodeError: From 7e341907927edafd4fa22ca0757205b504b183a7 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 23 Jul 2010 11:16:17 +0100 Subject: [PATCH 141/207] More toxy goodness. --- tox.ini | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 51779d871..95a877274 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,14 @@ [tox] -envlist=py26 +envlist=du06,du05 [testenv] deps=nose -commands=nosetests +commands= + nosetests + sphinx-build -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html + +[testenv:du05] +deps=docutils==0.5 + +[testenv:du06] +deps=docutils==0.6 From 0ed7290b2390f6758f1eb2f7f06416c435cf6124 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 23 Jul 2010 12:38:41 +0100 Subject: [PATCH 142/207] Make make check happy. --- Makefile | 3 ++- sphinx/util/docfields.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 90f7c3d46..7057a7152 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,8 @@ all: clean-pyc check test check: @$(PYTHON) utils/check_sources.py -i build -i dist -i sphinx/style/jquery.js \ -i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py -i .ropeproject \ - -i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py -i env . + -i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py \ + -i env -i .tox . clean: clean-pyc clean-patchfiles diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index de8fc8006..1ae49c6c5 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -223,7 +223,8 @@ class DocFieldTransformer(object): # filter out only inline nodes; others will result in invalid # markup being written out content = filter( - lambda n: isinstance(n, nodes.Inline) or isinstance(n, nodes.Text), + lambda n: isinstance(n, nodes.Inline) or + isinstance(n, nodes.Text), content) if content: types.setdefault(typename, {})[fieldarg] = content From 94b14dc39b11ebcce9f26ef6242428894e5d94ce Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 23 Jul 2010 12:42:03 +0100 Subject: [PATCH 143/207] Update for 1.0. --- CHANGES | 4 ++-- setup.py | 1 + sphinx/__init__.py | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index ef8b69c54..7ca8452b1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -Release 1.0 (in development) -============================ +Release 1.0 (Jul 23, 2010) +========================== Incompatible changes -------------------- diff --git a/setup.py b/setup.py index de805b7ef..183fcceb1 100644 --- a/setup.py +++ b/setup.py @@ -178,6 +178,7 @@ setup( 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', + 'Programming Language :: Python :: 2', 'Topic :: Documentation', 'Topic :: Text Processing', 'Topic :: Utilities', diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 37b6ecef7..4b43b29a2 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -12,8 +12,8 @@ import sys from os import path -__version__ = '1.0b2+' -__released__ = '1.0b2' # used when Sphinx builds its own docs +__version__ = '1.0' +__released__ = '1.0' # used when Sphinx builds its own docs package_dir = path.abspath(path.dirname(__file__)) From 0e2f523783b5f810bb9912cd554b95816ca42bec Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 23 Jul 2010 14:15:25 +0100 Subject: [PATCH 144/207] Reintroduce env.note_versionchange(). --- sphinx/directives/other.py | 7 +------ sphinx/environment.py | 6 ++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py index 5ce1ce1aa..332c40849 100644 --- a/sphinx/directives/other.py +++ b/sphinx/directives/other.py @@ -215,12 +215,7 @@ class VersionChange(Directive): else: ret = [node] env = self.state.document.settings.env - env.versionchanges.setdefault(node['version'], []).append( - (node['type'], env.temp_data['docname'], self.lineno, - # XXX: python domain specific - env.temp_data.get('py:module'), - env.temp_data.get('object'), - node.astext())) + env.note_versionchange(node['type'], node['version'], node, self.lineno) return ret diff --git a/sphinx/environment.py b/sphinx/environment.py index 315054966..972bfa3ef 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -733,6 +733,12 @@ class BuildEnvironment: def note_dependency(self, filename): self.dependencies.setdefault(self.docname, set()).add(filename) + def note_versionchange(self, type, version, node, lineno): + self.versionchanges.setdefault(version, []).append( + (type, self.temp_data['docname'], lineno, + self.temp_data.get('py:module'), + self.temp_data.get('object'), node.astext())) + # post-processing of read doctrees def filter_messages(self, doctree): From 690fc257e9a539a4c193ba8efe5587f7c102785c Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 23 Jul 2010 14:15:33 +0100 Subject: [PATCH 145/207] Add missing :cmember: role. --- sphinx/ext/oldcmarkup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/ext/oldcmarkup.py b/sphinx/ext/oldcmarkup.py index c2172b088..84ae61dd2 100644 --- a/sphinx/ext/oldcmarkup.py +++ b/sphinx/ext/oldcmarkup.py @@ -61,3 +61,4 @@ def setup(app): app.add_role('cfunc', old_crole) app.add_role('cmacro', old_crole) app.add_role('ctype', old_crole) + app.add_role('cmember', old_crole) From 5cfdac3e8ff4eca4be981dce9b5adfd77afec016 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 24 Jul 2010 11:30:21 +0100 Subject: [PATCH 147/207] Post-1.0 update. --- sphinx/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 4b43b29a2..8c1ebed56 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -12,7 +12,7 @@ import sys from os import path -__version__ = '1.0' +__version__ = '1.0+' __released__ = '1.0' # used when Sphinx builds its own docs package_dir = path.abspath(path.dirname(__file__)) From 023ce64f483a74c30bc042445022ddd4e627653a Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 24 Jul 2010 11:30:37 +0100 Subject: [PATCH 148/207] Fix hyperrefs in object descriptions for LaTeX. --- CHANGES | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES b/CHANGES index 7ca8452b1..8465dae09 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +Release 1.0.1 (in development) +============================== + +* Fix hyperrefs in object descriptions for LaTeX. + + Release 1.0 (Jul 23, 2010) ========================== From e9e91e82c3c7f1773631025d3579f5c0325dadd4 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 24 Jul 2010 11:32:46 +0100 Subject: [PATCH 149/207] Actually commit change of latex writer. --- sphinx/writers/latex.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 15e55b15e..5674b388c 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -250,7 +250,7 @@ class LaTeXTranslator(nodes.NodeVisitor): '\\label{%s}' % self.idescape(id) def hyperlink(self, id): - return '\\hyperref[%s]{' % (self.idescape(id)) + return '{\\hyperref[%s]{' % (self.idescape(id)) def hyperpageref(self, id): return '\\autopageref*{%s}' % (self.idescape(id)) @@ -1051,9 +1051,9 @@ class LaTeXTranslator(nodes.NodeVisitor): id = self.curfilestack[-1] + ':' + uri[1:] self.body.append(self.hyperlink(id)) if self.builder.config.latex_show_pagerefs: - self.context.append('} (%s)' % self.hyperpageref(id)) + self.context.append('}} (%s)' % self.hyperpageref(id)) else: - self.context.append('}') + self.context.append('}}') elif uri.startswith('%'): # references to documents or labels inside documents hashindex = uri.find('#') @@ -1067,12 +1067,12 @@ class LaTeXTranslator(nodes.NodeVisitor): if len(node) and hasattr(node[0], 'attributes') and \ 'std-term' in node[0].get('classes', []): # don't add a pageref for glossary terms - self.context.append('}') + self.context.append('}}') else: if self.builder.config.latex_show_pagerefs: - self.context.append('} (%s)' % self.hyperpageref(id)) + self.context.append('}} (%s)' % self.hyperpageref(id)) else: - self.context.append('}') + self.context.append('}}') elif uri.startswith('@token'): if self.in_production_list: self.body.append('\\token{') From e3f47a800ad157e5b61743a6d6d4e85de8c0dbd0 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 25 Jul 2010 14:50:47 +0200 Subject: [PATCH 150/207] Actually test the JSON builder. --- tests/test_build.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_build.py b/tests/test_build.py index f18ff1754..d571febd7 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -21,6 +21,10 @@ def teardown_module(): def test_pickle(app): app.builder.build_all() +@with_app(buildername='json') +def test_json(app): + app.builder.build_all() + @with_app(buildername='linkcheck') def test_linkcheck(app): app.builder.build_all() From ebb7a541419276c3207afd3a4ef2543ebac3dd48 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 25 Jul 2010 14:52:37 +0200 Subject: [PATCH 151/207] Add a custom json serializer implementation that forces translation proxies. Fixes building with the JSON builder. --- CHANGES | 2 ++ sphinx/builders/html.py | 16 ++++----------- sphinx/util/jsonimpl.py | 43 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 sphinx/util/jsonimpl.py diff --git a/CHANGES b/CHANGES index 8465dae09..c89621035 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ Release 1.0.1 (in development) ============================== +* Fix building with the JSON builder. + * Fix hyperrefs in object descriptions for LaTeX. diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index cd205910d..bbfe67e22 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -30,7 +30,7 @@ from docutils.frontend import OptionParser from docutils.readers.doctree import Reader as DoctreeReader from sphinx import package_dir, __version__ -from sphinx.util import copy_static_entry +from sphinx.util import jsonimpl, copy_static_entry from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \ movefile, ustrftime, copyfile from sphinx.util.nodes import inline_all_toctrees @@ -47,14 +47,6 @@ from sphinx.util.console import bold, darkgreen, brown from sphinx.writers.html import HTMLWriter, HTMLTranslator, \ SmartyPantsHTMLTranslator -try: - import json -except ImportError: - try: - import simplejson as json - except ImportError: - json = None - #: the filename for the inventory of objects INVENTORY_FILENAME = 'objects.inv' #: the filename for the "last build" file (for serializing builders) @@ -1007,15 +999,15 @@ class JSONHTMLBuilder(SerializingHTMLBuilder): """ A builder that dumps the generated HTML into JSON files. """ - implementation = json - indexer_format = json + implementation = jsonimpl + indexer_format = jsonimpl name = 'json' out_suffix = '.fjson' globalcontext_filename = 'globalcontext.json' searchindex_filename = 'searchindex.json' def init(self): - if json is None: + if jsonimpl.json is None: raise SphinxError( 'The module simplejson (or json in Python >= 2.6) ' 'is not available. The JSONHTMLBuilder builder will not work.') diff --git a/sphinx/util/jsonimpl.py b/sphinx/util/jsonimpl.py new file mode 100644 index 000000000..21f285d30 --- /dev/null +++ b/sphinx/util/jsonimpl.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +""" + sphinx.util.jsonimpl + ~~~~~~~~~~~~~~~~~~~~ + + JSON serializer implementation wrapper. + + :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import UserString + +try: + import json + JSONEncoder = json.JSONEncoder +except ImportError: + try: + import simplejson as json + JSONEncoder = json.JSONEncoder + except ImportError: + json = None + JSONEncoder = object + + +class SphinxJSONEncoder(JSONEncoder): + """JSONEncoder subclass that forces translation proxies.""" + def default(self, obj): + if isinstance(obj, UserString.UserString): + return unicode(obj) + return JSONEncoder.default(self, obj) + + +def dump(obj, fp, *args, **kwds): + kwds['cls'] = SphinxJSONEncoder + return json.dump(obj, fp, *args, **kwds) + +def dumps(obj, *args, **kwds): + kwds['cls'] = SphinxJSONEncoder + return json.dumps(obj, *args, **kwds) + +load = json.load +loads = json.loads From 611887a4f9df8e1c6418811ded1ccd50f0ab20f0 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Mon, 26 Jul 2010 19:31:07 +0200 Subject: [PATCH 152/207] Add docutils 0.7 target. --- tox.ini | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 95a877274..2d9d18f85 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=du06,du05 +envlist=du07,du06,du05 [testenv] deps=nose @@ -12,3 +12,6 @@ deps=docutils==0.5 [testenv:du06] deps=docutils==0.6 + +[testenv:du07] +deps=docutils==0.7 From bf71b0b2fad1a802d0cb4a23aa9dfa568fbd9393 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Mon, 26 Jul 2010 19:32:44 +0200 Subject: [PATCH 153/207] Fix some naming issues in intersphinx when given an explicit prefix. --- sphinx/ext/intersphinx.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 4fb3805f9..32226c2ac 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -191,10 +191,12 @@ def missing_reference(app, env, node, contnode): return objtypes = ['%s:%s' % (domain, objtype) for objtype in objtypes] to_try = [(env.intersphinx_inventory, target)] + in_set = None if ':' in target: # first part may be the foreign doc set name setname, newtarget = target.split(':', 1) if setname in env.intersphinx_named_inventory: + in_set = setname to_try.append((env.intersphinx_named_inventory[setname], newtarget)) for inventory, target in to_try: for objtype in objtypes: @@ -204,10 +206,13 @@ def missing_reference(app, env, node, contnode): newnode = nodes.reference('', '', internal=False, refuri=uri, reftitle='(in %s v%s)' % (proj, version)) if dispname == '-': - newnode.append(contnode) - else: - newnode.append(contnode.__class__(dispname, dispname)) + dispname = target + newnode.append(contnode.__class__(dispname, dispname)) return newnode + # at least get rid of the ':' in the target + if in_set is not None: + if len(contnode) and isinstance(contnode[0], nodes.Text): + contnode[0] = nodes.Text(newtarget, contnode[0].rawsource) def setup(app): From 0aafe2ac1ddd3078ff541a98fa44b3926072a3b0 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 13:20:58 +0200 Subject: [PATCH 154/207] Further fix for intersphinx labels, add test cases for that. --- CHANGES | 3 +++ sphinx/ext/intersphinx.py | 4 ++-- tests/test_intersphinx.py | 33 ++++++++++++++++++++++++++++++--- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index c89621035..608dcaa25 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Release 1.0.1 (in development) ============================== +* Fix display names for objects linked to by intersphinx with + explicit targets. + * Fix building with the JSON builder. * Fix hyperrefs in object descriptions for LaTeX. diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 32226c2ac..0a210879a 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -209,8 +209,8 @@ def missing_reference(app, env, node, contnode): dispname = target newnode.append(contnode.__class__(dispname, dispname)) return newnode - # at least get rid of the ':' in the target - if in_set is not None: + # at least get rid of the ':' in the target if no explicit title given + if in_set is not None and not node.get('refexplicit', True): if len(contnode) and isinstance(contnode[0], nodes.Text): contnode[0] = nodes.Text(newtarget, contnode[0].rawsource) diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py index 622243e60..8b6547e54 100644 --- a/tests/test_intersphinx.py +++ b/tests/test_intersphinx.py @@ -80,7 +80,10 @@ def test_read_inventory_v2(): def test_missing_reference(tempdir, app): inv_file = tempdir / 'inventory' write_file(inv_file, inventory_v2) - app.config.intersphinx_mapping = {'http://docs.python.org/': inv_file} + app.config.intersphinx_mapping = { + 'http://docs.python.org/': inv_file, + 'py3k': ('http://docs.python.org/py3k/', inv_file), + } app.config.intersphinx_cache_limit = 0 # load the inventory and check if it's done correctly @@ -91,7 +94,7 @@ def test_missing_reference(tempdir, app): ('foo', '2.0', 'http://docs.python.org/foo.html#module-module2', '-') # create fake nodes and check referencing - contnode = nodes.emphasis('foo') + contnode = nodes.emphasis('foo', 'foo') refnode = addnodes.pending_xref('') refnode['reftarget'] = 'module1.func' refnode['reftype'] = 'func' @@ -101,7 +104,7 @@ def test_missing_reference(tempdir, app): assert isinstance(rn, nodes.reference) assert rn['refuri'] == 'http://docs.python.org/sub/foo.html#module1.func' assert rn['reftitle'] == '(in foo v2.0)' - assert rn[0] is contnode + assert rn[0].astext() == 'module1.func' # create unresolvable nodes and check None return value refnode['reftype'] = 'foo' @@ -110,3 +113,27 @@ def test_missing_reference(tempdir, app): refnode['reftype'] = 'function' refnode['reftarget'] = 'foo.func' assert missing_reference(app, app.env, refnode, contnode) is None + + # check handling of prefixes + + # prefix given, target found: prefix is stripped + refnode['reftype'] = 'mod' + refnode['reftarget'] = 'py3k:module2' + rn = missing_reference(app, app.env, refnode, contnode) + assert rn[0].astext() == 'module2' + + # prefix given, target not found and nonexplicit title: prefix is stripped + refnode['reftarget'] = 'py3k:unknown' + refnode['refexplicit'] = False + contnode[0] = nodes.Text('py3k:unknown') + rn = missing_reference(app, app.env, refnode, contnode) + assert rn is None + assert contnode[0].astext() == 'unknown' + + # prefix given, target not found and explicit title: nothing is changed + refnode['reftarget'] = 'py3k:unknown' + refnode['refexplicit'] = True + contnode[0] = nodes.Text('py3k:unknown') + rn = missing_reference(app, app.env, refnode, contnode) + assert rn is None + assert contnode[0].astext() == 'py3k:unknown' From 8c0c728d1bee97e3c286784db062067175a24269 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 13:27:00 +0200 Subject: [PATCH 155/207] Fix building with SingleHTMLBuilder when there is no toctree. --- CHANGES | 2 ++ sphinx/builders/html.py | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 608dcaa25..6fbe98ebc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ Release 1.0.1 (in development) ============================== +* Fix building with SingleHTMLBuilder when there is no toctree. + * Fix display names for objects linked to by intersphinx with explicit targets. diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index bbfe67e22..8d96c146c 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -847,8 +847,14 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): def get_doc_context(self, docname, body, metatags): # no relation links... toc = self.env.get_toctree_for(self.config.master_doc, self, False) - self.fix_refuris(toc) - toc = self.render_partial(toc)['fragment'] + # if there is no toctree, toc is None + if toc: + self.fix_refuris(toc) + toc = self.render_partial(toc)['fragment'] + display_toc = True + else: + toc = '' + display_toc = False return dict( parents = [], prev = None, @@ -861,7 +867,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder): rellinks = [], sourcename = '', toc = toc, - display_toc = True, + display_toc = display_toc, ) def write(self, *ignored): From 954e8d0220866151ca2e57cf90885c008fc4ae35 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 14:28:31 +0200 Subject: [PATCH 156/207] #474: Fix javascript domain parsing of object names. --- CHANGES | 4 +++- sphinx/domains/javascript.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 6fbe98ebc..883d1e0bc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,9 @@ Release 1.0.1 (in development) ============================== -* Fix building with SingleHTMLBuilder when there is no toctree. +* #473: Fix a bug in parsing JavaScript object names. + +* #474: Fix building with SingleHTMLBuilder when there is no toctree. * Fix display names for objects linked to by intersphinx with explicit targets. diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py index 890af8e14..9934dba3a 100644 --- a/sphinx/domains/javascript.py +++ b/sphinx/domains/javascript.py @@ -31,6 +31,7 @@ class JSObject(ObjectDescription): display_prefix = None def handle_signature(self, sig, signode): + import pdb; pdb.set_trace() sig = sig.strip() if '(' in sig and sig[-1:] == ')': prefix, arglist = sig.split('(', 1) @@ -56,7 +57,7 @@ class JSObject(ObjectDescription): else: # just a function or constructor objectname = '' - fullname = '' + fullname = name signode['object'] = objectname signode['fullname'] = fullname From 2380957682d2bff6495ef7bca59f96d9ef62ed7c Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 14:36:47 +0200 Subject: [PATCH 157/207] #266: Add Bengali locale, thanks to Nasimul Haque. --- CHANGES | 2 + doc/config.rst | 1 + sphinx/locale/bn/LC_MESSAGES/sphinx.js | 1 + sphinx/locale/bn/LC_MESSAGES/sphinx.mo | Bin 0 -> 12509 bytes sphinx/locale/bn/LC_MESSAGES/sphinx.po | 698 +++++++++++++++++++++++++ 5 files changed, 702 insertions(+) create mode 100644 sphinx/locale/bn/LC_MESSAGES/sphinx.js create mode 100644 sphinx/locale/bn/LC_MESSAGES/sphinx.mo create mode 100644 sphinx/locale/bn/LC_MESSAGES/sphinx.po diff --git a/CHANGES b/CHANGES index 883d1e0bc..8781d0e2a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ Release 1.0.1 (in development) ============================== +* #266: Add Bengali language. + * #473: Fix a bug in parsing JavaScript object names. * #474: Fix building with SingleHTMLBuilder when there is no toctree. diff --git a/doc/config.rst b/doc/config.rst index 8084580c4..bf8ad3c2d 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -283,6 +283,7 @@ Project information Currently supported languages are: + * ``bn`` -- Bengali * ``ca`` -- Catalan * ``cs`` -- Czech * ``da`` -- Danish diff --git a/sphinx/locale/bn/LC_MESSAGES/sphinx.js b/sphinx/locale/bn/LC_MESSAGES/sphinx.js new file mode 100644 index 000000000..277cd3d03 --- /dev/null +++ b/sphinx/locale/bn/LC_MESSAGES/sphinx.js @@ -0,0 +1 @@ +Documentation.addTranslations({"locale": "bn", "plural_expr": "(n != 1)", "messages": {"Search Results": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8\u09c7\u09b0 \u09ab\u09b2\u09be\u09ab\u09b2", "Preparing search...": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8\u09c7\u09b0 \u09aa\u09cd\u09b0\u09b8\u09cd\u09a4\u09c1\u09a4\u09bf \u099a\u09b2\u099b\u09c7...", "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u0986\u09aa\u09a8\u09be\u09b0 \u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8\u09c7 \u0995\u09c7\u09be\u09a8 \u09ab\u09b2\u09be\u09ab\u09b2 \u09aa\u09be\u0993\u09df\u09be \u09af\u09be\u09df\u09a8\u09bf\u0964 \u0986\u09aa\u09a8\u09be\u09b0 \u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8\u09c7\u09b0 \u09b6\u09ac\u09cd\u09a6\u0997\u09c1\u09b2\u09c7\u09be\u09b0 \u09b8\u09a0\u09bf\u0995 \u09ac\u09be\u09a8\u09be\u09a8 \u0993 \u09ac\u09bf\u09ad\u09be\u0997 \u09a8\u09bf\u09b0\u09cd\u09ac\u09be\u099a\u09a8 \u09a8\u09bf\u09b6\u09cd\u099a\u09bf\u09a4 \u0995\u09b0\u09c1\u09a8\u0964", "Search finished, found %s page(s) matching the search query.": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8 \u09b6\u09c7\u09b7 \u09b9\u09df\u09c7\u099b\u09c7, \u09ab\u09b2\u09be\u09ab\u09b2\u09c7 %s-\u099f\u09bf \u09aa\u09be\u09a4\u09be \u09aa\u09be\u0993\u09df\u09be \u0997\u09c7\u099b\u09c7\u0964", ", in ": ", -", "Permalink to this headline": "\u098f\u0987 \u09b6\u09bf\u09b0\u09c7\u09be\u09a8\u09be\u09ae\u09c7\u09b0 \u09aa\u09be\u09b0\u09cd\u09ae\u09be\u09b2\u09bf\u0999\u09cd\u0995", "Searching": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8 \u099a\u09b2\u099b\u09c7", "Permalink to this definition": "\u098f\u0987 \u09b8\u0982\u099c\u09cd\u099e\u09be\u09b0 \u09aa\u09be\u09b0\u09cd\u09ae\u09be\u09b2\u09bf\u0999\u09cd\u0995", "Hide Search Matches": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8\u09c7\u09b0 \u09ae\u09cd\u09af\u09be\u099a\u0997\u09c1\u09b2\u09c7\u09be \u09b2\u09c1\u0995\u09be\u09a8"}}); \ No newline at end of file diff --git a/sphinx/locale/bn/LC_MESSAGES/sphinx.mo b/sphinx/locale/bn/LC_MESSAGES/sphinx.mo new file mode 100644 index 0000000000000000000000000000000000000000..9b60397e2f33f760d5a6e098877fe7eab7663ef8 GIT binary patch literal 12509 zcmchcZH!#idB;x(DZ$XZ010Uz?ZsrxI(XK*wgG1WgS|HIHe0-+p+Ljk*}JJEYL@Sl5P5b+w z=giE`?yPMZsc1d_d(L^z^Zq>N+{=&7I`uKfe~<9*eEuCcRin;-Yfg9WOoj#U1K=>Y z61*DZ&lLmCfFEVN8$1Vm5d1Ls6sY}&!CwWx1)c%^MOgmkCPf*%1tvcmXX z0E&J+sP(Hrt=|fs3r>N*2L2u>K3@et2_6DJ0lpsQe+-K5-@!}455x2~z-z#(z)4W{ zHNcO7&w;4oz72j5{4Tf&{6QF>gHf{QQy?te#o%e+rJ(3HfxiM?8`gJ(_1i%4kHHP# zZczF@2g<(JK*{|Pcr*A@P<%EbOmeOQ&jW7&F9Rn*>HQR_eFs4IKKu=e-}4_bJ--9W zKW~DkfIki6pMeVb|A5+mDnS#!4}sG2oPeJJwf}1H0&ooE&&~3KitfHJel(1q2Bq%{ zpz`8dVf;N%^8N;tsy_tfub+XE|8Jo7{Q^`zo=&jkpH-mbYz7H|+W~F?e;bruUk5S4 zy$D_iz6y%|??L(RZBX&~4^aE1l*VU*T0aL=-kt|)eGnACE5Iwj8$tQ~0nqyygq1rC zO8-{^z7A^t8z6t~hx~~C=ivLncR|_z-=OxLa+c|F2KW%;v%yv1Q(^wkLFx59@KfO5 zf#N5lVc}MQl6O9+xb=hb+W;szH-g$f3aTCwQ2W0GO8x_&;_yhoeW3Oo0>$qLC_fzq zRrjxg^4CuS{&QG=8`QpcLHYd`Vf_q*OU_vV&jaPRPlNLBC7}Ge6%^mQK-K9KC_V21 zkCD%R2ujZzNNVNp=RoOmJLv5R_yD+?`9A{JfPV_|=l+Qw(W`05KNo_i=&lC)z%lS* z@OQysumLLXejM<>KvZz&;zY$~4Jf`l!FAvlK*{|&2&sDwTo3*&SOCw)D9POnivD-N zE#M=dJD}|OBF_7D@Ef4=;T2GM@&+h9eh$jd zry)E7KMpeGE(14!JHZ>l2g3MGP;yU)iRym~cqjNd5L4Vspz8mxz^&lh;1l4bC?Wbc z0{$a7cM5q9ZexBooBF{&12=*H04i>M7%>X21(i2@!B2w^gW`7tl>M)RlJ_s*W#D>> z{0?vzsPXHd=(HJ?+$vE0eJd!vCqS)#5rl<%8kD^6fJ5M4gOry007SCy69I=o>3auw zE%-GM7rCE+gv=+ybHFD_itXTQpyK(li|kz43~GE2DE@~)TAO>T71x3FB zlz(mr<1FBVpzPfT%CE;j#pho^-2=`av^d=XN=^zY9!EhJMbVZxOS0jpFLP0UsS>%q z{>f4~sl+qM>MU9{GZAOgmq&g56KOHaOL>`D*S96=n^+U|-RAnn+fP~4-;xByRI~TF;|=I?0lV1gp=$D07?h9K-;(xsLa1 z!w}Z-pnRMTRb z4y3iIwJSI6^iv_&w*L9Hiw4|Qd9dcTCe>QvgSg-^LPjy^xHfa!P_q_gNn9&VM?B7C zWJ45(s#+6LpQ)CIBXyJkx2;x7Ywnsf%`0i1WbT?;IulJNwIrHL>pn+XJiC)(ATo(i zwZyKVc}2U^+JwTMr%Iz}Jl#W*mDAmpa^+HSSG3YNt{jMVAQH0Jr(96pb7?ENyHqYm z#Cbuo1$`!E9*e|Cg1p>;Xq1>_o<)&(#ifd3F`4YfH>TO{v~p1%#nmdFQg&)@Ey?QT zoZ`sx0e4Lurlrb6vPXeVDPAAvYki8BqwBTet}UnIl-YJ`Sz#`9*OexcXs5+sdz=?> z8FQ7~T|ZMzYk90Ezu*5xt17K#zAKrdDr{EbvS@rRA`uCsW=ln8RI|C#G8=X`#gtjS zI^h$}*A^`||9qHHzqqM1UW@4gp%7h{s$qa%t(wEQoXjR=w;|S!(A}I?{ue$WReJZQA-!6 zlXybS(~XwnoM_MZGqE+`gk&M%tc+rgu30=0-4M^lJBzhaRVva0eGMzXmNH$Lg(CUf zfE%qPRSq$d#ApTv{M>9Qt!Kf`(K)C;x#Y7!38m*<(G>gmG1*6+W)zp8puEaJL z?v}X33GQx5yn0|>uaRi#UiO?h%aH(!4s%=cncO0{#V2TMTO_At(+MZOHSfO6=V*Vn znx;wC$()Ya(cSf=hN*$??h>w7H(q#wur>BUgKxvGeFJk#?hY=T z!P9lzdr*JehFo-s5&%6Dqp~3YVrq?Ay@%Yds$>91+k`=ck z>fVLz*;Hwwu%$kg6~@wG&d;ngGcX-fURO`e#HI28SH2aaH;)zkO@RJc*oxrcXx-r8 zXA46^g~5%{(51ucHeNh9G&l%h;TB@6t5KV7Xs|GNSz+B}(a?tB^&2i8WakRC`odT( zu4J@9-Mw~5ZoM2`C&|$jJ=NI6w#rnUlr4-UF`e_|HjS3+wYXfkhGt8DtyKLmyK>#- zkv(47Ux_ZbG8$UFV*B;mw{?7o^Hzk5QelifH%w~n$=6oPafwSW(XVAmeq}wMENtx1 z$)w4oR@hc4rW169;b`M{DPLg+E!A4sGB?c25VwbDaNx58m#lEj#&ga2`;@9P1)s!U$0V!WTM=`}_p!&vxbxE#T?3pT`nN*nGsOTJ{|Al=}+J z2FnLg$5c4tnI1g>?TN*31TA8T9>&!#9d0)ExBQAKVM(?wm=}F`*;~ZS+=u4RK;K1% zvwBS*HFFoZ2lo-y$Clxwcfb?LY`s1E2rUrWnSXCmmkrI51Zq2_%U!{ZQd@o`TMl}A z_hX60HH7*P$QjGV6TE?XR*>Q-vI&MT*ms<_(Vp~NExO)Z`R2faFgZ3|BI+mKMw zkkp5_WsZs6$HGxRg=jdL4$$4t#zu4g_nVEEy;?zu`@H2w^>VZEG*rs!X5(=dh8bBV zAe{}^*s6Ez(9EH>Zpb~*oPWSe+>7Vh?|&5Pms#|>uuBzf;&6t_*R+N8H@(~!JR@05 z|jy0b-;1=aryZSrZd85`V_;R9HUewY2%(Bg_wTdsg`k0@`bW5sd{qT5g1`&3j6PQ;|u6DU** zF2d%$ixg-C!^5j2EuLp!xn%)4tiI6ID>Y$77*0IKG#!o;owE$OdTv_+788`itb14C z0bf(roQ_2OzN_E^j%gnuh#|xgdwtA~F-zN_DX^fb?Q%hANXS49V*3@}maLC-Qh`=O z3?NeTvp(6wC#;bpXhIZ28Nhq2wv8uCUh@zQO$Eam7Z~>AV2tW? z3>Ku0&+rflyR6uDvR@ilA9~!|B-61Ls(YiA$FX81bjFHkhJtQK4S_nny_xg4KsK34 z+|}%Q)9S%KClqp&hF&L3Z&TWVh6P@>u5HoKp~F6JX{$s|?0%)vH-p!4xlSi#D|$S~ z01-a0{LY6XN9vgs9Syx$ZId76&PBPwta+)y6Q|StaI-A#h<4uNa##2&Py9$S8 zbRa+QEQ*UEDSyZhjxsP}`UE7_nbEY%6%h4yMUUAf-|&2B79IJ5v zo@H&XeW|pjAZuED6qVjg-N`1v;xuU$vt6iquhNK7;RrJ9R3OY4MTnWDo(}dti&#co za-I0Ak+9u#U*L^-oy=4f3vkr2XA+3wJ_eSfPy_RezB_vbe1cf|x5YwBGC(`;1z2L3p8^LvNG!d=L1I@r6_dU(FVXk7 zsYg;_2*G#;$r#3IWeV_%w>4#X=c5(^{!;7Xv_B)fWim#G(z2GImn8wRNG5*OGR zI#0I8Axpg@q=Aju@@#JsDl$uE`AsXgetqgtbCHP|i(KuvAhVMm@RuXL4Q z`aSxjlXq@`Pk1?jqnF&!Euy>Ga$pj3oi_e<5k!WgbeR>qr;vcwZjScY3`y_zqR@pp zzCzU=3C%1)^#`8n!3tRUtbR(4u>PK2De3<{Qx;!|kC!=KnhFDf%KEP0Gd3GKA%0$z zzDUUj-NKjNz>g=+QlN7+Y~5el*DPfS9{Gm2`=&=Dk!o!P6-DM)J>=)~g32mm3zX55 zC9=jA$aRu~DTso5p;i4^BmDpLm%CkQ>Mgj_E%=`!d-uI}N;a^4%{gRVxz23L@B zx(Y0L1JuMmPhpNY%-$1x5Qf5BiTm-;g0HDvq9C&()t#Ta(vtuu)S_3jd3{@Izulmy zTJ54!3~8nud%Hgsbg{G=w-a7fy5E~6;~3y3oa2K(&lKg$(9U){ME1e!1azxiEb4uA z@tFM`mMmKP>xzHxSvJx@S|@~WHV`t!UOU3gN8$9#SOutkQzA$Zm0@7fO(EsE^0GD#!gVS?iUZ literal 0 HcmV?d00001 diff --git a/sphinx/locale/bn/LC_MESSAGES/sphinx.po b/sphinx/locale/bn/LC_MESSAGES/sphinx.po new file mode 100644 index 000000000..d5141c797 --- /dev/null +++ b/sphinx/locale/bn/LC_MESSAGES/sphinx.po @@ -0,0 +1,698 @@ +# Translations template for Sphinx. +# Copyright (C) 2009 ORGANIZATION +# This file is distributed under the same license as the Sphinx project. +# FIRST AUTHOR , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: Sphinx 1.0pre/[?1034h2e1ab15e035e\n" +"Report-Msgid-Bugs-To: nasim.haque@gmail.com\n" +"POT-Creation-Date: 2009-11-08 16:28+0100\n" +"PO-Revision-Date: 2009-11-10 13:42+0100\n" +"Last-Translator: Nasimul Haque \n" +"Language-Team: Nasimul Haque \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.4\n" + +#: sphinx/environment.py:130 +#: sphinx/writers/latex.py:184 +#, python-format +msgid "%B %d, %Y" +msgstr "%B %d, %Y" + +#: sphinx/environment.py:348 +#: sphinx/themes/basic/genindex-single.html:2 +#: sphinx/themes/basic/genindex-split.html:2 +#: sphinx/themes/basic/genindex-split.html:5 +#: sphinx/themes/basic/genindex.html:2 +#: sphinx/themes/basic/genindex.html:5 +#: sphinx/themes/basic/genindex.html:48 +#: sphinx/themes/basic/layout.html:134 +#: sphinx/writers/latex.py:190 +msgid "Index" +msgstr "ইনডেক্স" + +#: sphinx/environment.py:349 +#: sphinx/writers/latex.py:189 +msgid "Module Index" +msgstr "মডিউল ইনডেক্স" + +#: sphinx/environment.py:350 +#: sphinx/themes/basic/defindex.html:16 +msgid "Search Page" +msgstr "অনুসন্ধান পাতা" + +#: sphinx/roles.py:167 +#, python-format +msgid "Python Enhancement Proposals!PEP %s" +msgstr "পাইথন উন্নয়ন পরামর্শ!PEP %s" + +#: sphinx/builders/changes.py:70 +msgid "Builtins" +msgstr "বিল্টইন সমূহ" + +#: sphinx/builders/changes.py:72 +msgid "Module level" +msgstr "মডিউল লেভেল" + +#: sphinx/builders/html.py:224 +#, python-format +msgid "%b %d, %Y" +msgstr "%b %d, %Y" + +#: sphinx/builders/html.py:243 +#: sphinx/themes/basic/defindex.html:21 +msgid "General Index" +msgstr "সাধারণ ইনডেক্স" + +#: sphinx/builders/html.py:243 +msgid "index" +msgstr "ইনডেক্স" + +#: sphinx/builders/html.py:247 +#: sphinx/builders/htmlhelp.py:220 +#: sphinx/builders/qthelp.py:133 +#: sphinx/themes/basic/defindex.html:19 +#: sphinx/themes/basic/modindex.html:2 +#: sphinx/themes/basic/modindex.html:13 +#: sphinx/themes/scrolls/modindex.html:2 +#: sphinx/themes/scrolls/modindex.html:13 +msgid "Global Module Index" +msgstr "গ্লোবাল মডিউল ইনডেক্স" + +#: sphinx/builders/html.py:248 +msgid "modules" +msgstr "মডিউল সমূহ" + +#: sphinx/builders/html.py:304 +msgid "next" +msgstr "পরবর্তী" + +#: sphinx/builders/html.py:313 +msgid "previous" +msgstr "পূর্ববর্তী" + +#: sphinx/builders/latex.py:162 +msgid " (in " +msgstr "(-" + +#: sphinx/directives/__init__.py:78 +#: sphinx/directives/__init__.py:79 +#: sphinx/directives/__init__.py:80 +#: sphinx/directives/__init__.py:81 +msgid "Raises" +msgstr "রেইজেস" + +#: sphinx/directives/__init__.py:82 +#: sphinx/directives/__init__.py:83 +#: sphinx/directives/__init__.py:84 +msgid "Variable" +msgstr "ভ্যারিয়েবল" + +#: sphinx/directives/__init__.py:85 +#: sphinx/directives/__init__.py:86 +#: sphinx/directives/__init__.py:92 +#: sphinx/directives/__init__.py:93 +msgid "Returns" +msgstr "রিটার্নস" + +#: sphinx/directives/__init__.py:94 +msgid "Return type" +msgstr "রিটার্ন টাইপ" + +#: sphinx/directives/__init__.py:169 +msgid "Parameter" +msgstr "প্যারামিটার" + +#: sphinx/directives/__init__.py:173 +msgid "Parameters" +msgstr "প্যারামিটার" + +#: sphinx/directives/other.py:127 +msgid "Section author: " +msgstr "অনুচ্ছেদ লেখক:" + +#: sphinx/directives/other.py:129 +msgid "Module author: " +msgstr "মডিউল লেখক:" + +#: sphinx/directives/other.py:131 +msgid "Author: " +msgstr "লেখক:" + +#: sphinx/directives/other.py:233 +msgid "See also" +msgstr "আরও দেখুন" + +#: sphinx/domains/c.py:124 +#, python-format +msgid "%s (C function)" +msgstr "%s (C ফাংশন)" + +#: sphinx/domains/c.py:126 +#, python-format +msgid "%s (C member)" +msgstr "%s (C মেম্বার)" + +#: sphinx/domains/c.py:128 +#, python-format +msgid "%s (C macro)" +msgstr "%s (C ম্যাক্রো)" + +#: sphinx/domains/c.py:130 +#, python-format +msgid "%s (C type)" +msgstr "%s (C টাইপ)" + +#: sphinx/domains/c.py:132 +#, python-format +msgid "%s (C variable)" +msgstr "%s (C ভ্যারিয়েবল)" + +#: sphinx/domains/c.py:162 +msgid "C function" +msgstr "C ফাংশন" + +#: sphinx/domains/c.py:163 +msgid "C member" +msgstr "C মেম্বার" + +#: sphinx/domains/c.py:164 +msgid "C macro" +msgstr "C ম্যাক্রো" + +#: sphinx/domains/c.py:165 +msgid "C type" +msgstr "C টাইপ" + +#: sphinx/domains/c.py:166 +msgid "C variable" +msgstr "C ভ্যারিয়েবল" + +#: sphinx/domains/python.py:186 +#, python-format +msgid "%s() (built-in function)" +msgstr "%s() (বিল্ট-ইন ফাংশন)" + +#: sphinx/domains/python.py:187 +#: sphinx/domains/python.py:244 +#: sphinx/domains/python.py:256 +#: sphinx/domains/python.py:269 +#, python-format +msgid "%s() (in module %s)" +msgstr "%s() (%s মডিউলে)" + +#: sphinx/domains/python.py:190 +#, python-format +msgid "%s (built-in variable)" +msgstr "%s (বিল্ট-ইন ভ্যারিয়েবল)" + +#: sphinx/domains/python.py:191 +#: sphinx/domains/python.py:282 +#, python-format +msgid "%s (in module %s)" +msgstr "%s (%s মডিউলে)" + +#: sphinx/domains/python.py:207 +#, python-format +msgid "%s (built-in class)" +msgstr "%s (বিল্ট-ইন ক্লাস)" + +#: sphinx/domains/python.py:208 +#, python-format +msgid "%s (class in %s)" +msgstr "%s (%s ক্লাসে)" + +#: sphinx/domains/python.py:248 +#, python-format +msgid "%s() (%s.%s method)" +msgstr "%s (%s.%s মেথড)" + +#: sphinx/domains/python.py:250 +#, python-format +msgid "%s() (%s method)" +msgstr "%s() (%s মেথড)" + +#: sphinx/domains/python.py:260 +#, python-format +msgid "%s() (%s.%s static method)" +msgstr "%s (%s.%s স্ট্যাটিক মেথড)" + +#: sphinx/domains/python.py:263 +#, python-format +msgid "%s() (%s static method)" +msgstr "%s() (%s স্ট্যাটিক মেথড)" + +#: sphinx/domains/python.py:273 +#, python-format +msgid "%s() (%s.%s class method)" +msgstr "%s() (%s.%s ক্লাস মেথড)" + +#: sphinx/domains/python.py:276 +#, python-format +msgid "%s() (%s class method)" +msgstr "%s() (%s ক্লাস মেথড)" + +#: sphinx/domains/python.py:286 +#, python-format +msgid "%s (%s.%s attribute)" +msgstr "%s (%s.%s এ্যট্রিবিউট)" + +#: sphinx/domains/python.py:288 +#, python-format +msgid "%s (%s attribute)" +msgstr "%s (%s এ্যট্রিবিউট)" + +#: sphinx/domains/python.py:334 +msgid "Platforms: " +msgstr "প্লাটফরম:" + +#: sphinx/domains/python.py:340 +#, python-format +msgid "%s (module)" +msgstr "%s (মডিউল)" + +#: sphinx/domains/python.py:396 +msgid "function" +msgstr "ফাংশন" + +#: sphinx/domains/python.py:397 +msgid "data" +msgstr "ডাটা" + +#: sphinx/domains/python.py:398 +msgid "class" +msgstr "ক্লাস" + +#: sphinx/domains/python.py:399 +#: sphinx/locale/__init__.py:161 +msgid "exception" +msgstr "এক্সেপশন" + +#: sphinx/domains/python.py:400 +msgid "method" +msgstr "মেথড" + +#: sphinx/domains/python.py:401 +msgid "attribute" +msgstr "এ্যট্রিবিউট" + +#: sphinx/domains/python.py:402 +#: sphinx/locale/__init__.py:157 +msgid "module" +msgstr "মডিউল" + +#: sphinx/domains/std.py:67 +#: sphinx/domains/std.py:83 +#, python-format +msgid "environment variable; %s" +msgstr "এনভায়রনমেন্ট ভ্যারিয়েবল; %s" + +#: sphinx/domains/std.py:156 +#, python-format +msgid "%scommand line option; %s" +msgstr "%sকমান্ড লাইন অপশন; %s" + +#: sphinx/domains/std.py:324 +msgid "glossary term" +msgstr "শব্দকোষ" + +#: sphinx/domains/std.py:325 +msgid "grammar token" +msgstr "ব্যকরণ টোকেন" + +#: sphinx/domains/std.py:326 +msgid "environment variable" +msgstr "এনভায়রনমেন্ট ভ্যারিয়েবল" + +#: sphinx/domains/std.py:327 +msgid "program option" +msgstr "প্রোগ্রাম অপশন" + +#: sphinx/ext/autodoc.py:892 +#, python-format +msgid " Bases: %s" +msgstr "বেস: %s" + +#: sphinx/ext/autodoc.py:925 +#, python-format +msgid "alias of :class:`%s`" +msgstr ":class:`%s` এর উপনাম" + +#: sphinx/ext/todo.py:40 +msgid "Todo" +msgstr "অসমাপ্ত কাজ" + +#: sphinx/ext/todo.py:98 +#, python-format +msgid "(The original entry is located in %s, line %d and can be found " +msgstr "(%s, %d লাইনে মূল অন্তর্ভুক্তিটি রয়েছে, যা পাওয়া যাবে" + +#: sphinx/ext/todo.py:104 +msgid "here" +msgstr "এখানে" + +#: sphinx/locale/__init__.py:138 +msgid "Attention" +msgstr "দৃষ্টি আকর্ষণ" + +#: sphinx/locale/__init__.py:139 +msgid "Caution" +msgstr "সতর্কীকরণ" + +#: sphinx/locale/__init__.py:140 +msgid "Danger" +msgstr "বিপজ্জনক" + +#: sphinx/locale/__init__.py:141 +msgid "Error" +msgstr "ভুল (এরর)" + +#: sphinx/locale/__init__.py:142 +msgid "Hint" +msgstr "আভাস" + +#: sphinx/locale/__init__.py:143 +msgid "Important" +msgstr "গুরুত্বপূর্ণ" + +#: sphinx/locale/__init__.py:144 +msgid "Note" +msgstr "নোট" + +#: sphinx/locale/__init__.py:145 +msgid "See Also" +msgstr "আরও দেখুন" + +#: sphinx/locale/__init__.py:146 +msgid "Tip" +msgstr "পরামর্শ" + +#: sphinx/locale/__init__.py:147 +msgid "Warning" +msgstr "সতর্কতা" + +#: sphinx/locale/__init__.py:151 +#, python-format +msgid "New in version %s" +msgstr "%s ভার্সনে নতুন" + +#: sphinx/locale/__init__.py:152 +#, python-format +msgid "Changed in version %s" +msgstr "%s ভার্সনে পরিবর্তিত" + +#: sphinx/locale/__init__.py:153 +#, python-format +msgid "Deprecated since version %s" +msgstr "%s ভার্সন থেকে ডেপ্রিকেটেড" + +#: sphinx/locale/__init__.py:158 +msgid "keyword" +msgstr "কিওয়ার্ড" + +#: sphinx/locale/__init__.py:159 +msgid "operator" +msgstr "অপারেটর" + +#: sphinx/locale/__init__.py:160 +msgid "object" +msgstr "অবজেক্ট" + +#: sphinx/locale/__init__.py:162 +msgid "statement" +msgstr "স্ট্যাটমেন্ট" + +#: sphinx/locale/__init__.py:163 +msgid "built-in function" +msgstr "বিল্ট-ইন ফাংশন" + +#: sphinx/themes/basic/defindex.html:2 +msgid "Overview" +msgstr "ভুমিকা" + +#: sphinx/themes/basic/defindex.html:11 +msgid "Indices and tables:" +msgstr "ইনডেক্স ও টেবিল সমূহ:" + +#: sphinx/themes/basic/defindex.html:14 +msgid "Complete Table of Contents" +msgstr "পূর্ণাঙ্গ সূচীপত্র" + +#: sphinx/themes/basic/defindex.html:15 +msgid "lists all sections and subsections" +msgstr "সকল অনুচ্ছেদ সমূহের তালিকা" + +#: sphinx/themes/basic/defindex.html:17 +msgid "search this documentation" +msgstr "এই সহায়িকাতে অনুসন্ধা করুন" + +#: sphinx/themes/basic/defindex.html:20 +msgid "quick access to all modules" +msgstr "সকল মডিউলে দ্রুত প্রবেশ" + +#: sphinx/themes/basic/defindex.html:22 +msgid "all functions, classes, terms" +msgstr "সকল ফাংশন, ক্লাস, টার্ম" + +#: sphinx/themes/basic/genindex-single.html:5 +#, python-format +msgid "Index – %(key)s" +msgstr "ইনডেক্স – %(key)s" + +#: sphinx/themes/basic/genindex-single.html:44 +#: sphinx/themes/basic/genindex-split.html:14 +#: sphinx/themes/basic/genindex-split.html:27 +#: sphinx/themes/basic/genindex.html:54 +msgid "Full index on one page" +msgstr "এক পাতায় সম্পূর্ণ ইনডেক্স" + +#: sphinx/themes/basic/genindex-split.html:7 +msgid "Index pages by letter" +msgstr "বর্ণানুসারে ইনডেক্স পাতা" + +#: sphinx/themes/basic/genindex-split.html:15 +msgid "can be huge" +msgstr "খুব বড় হতে পারে" + +#: sphinx/themes/basic/layout.html:10 +msgid "Navigation" +msgstr "নেভিগেশন" + +#: sphinx/themes/basic/layout.html:42 +msgid "Table Of Contents" +msgstr "সূচীপত্র" + +#: sphinx/themes/basic/layout.html:48 +msgid "Previous topic" +msgstr "পূর্ববর্তী টপিক" + +#: sphinx/themes/basic/layout.html:50 +msgid "previous chapter" +msgstr "পূর্ববর্তী অধ্যায়" + +#: sphinx/themes/basic/layout.html:53 +msgid "Next topic" +msgstr "পরবর্তী টপিক" + +#: sphinx/themes/basic/layout.html:55 +msgid "next chapter" +msgstr "পরবর্তী অধ্যায়" + +#: sphinx/themes/basic/layout.html:60 +msgid "This Page" +msgstr "এই পাতা" + +#: sphinx/themes/basic/layout.html:63 +msgid "Show Source" +msgstr "সোর্স দেখুন" + +#: sphinx/themes/basic/layout.html:73 +msgid "Quick search" +msgstr "দ্রুত অনুসন্ধান" + +#: sphinx/themes/basic/layout.html:76 +msgid "Go" +msgstr "যান" + +#: sphinx/themes/basic/layout.html:81 +msgid "Enter search terms or a module, class or function name." +msgstr "অনুসন্ধানের জন্য টার্ম, মডিউল, ক্লাস অথবা ফাংশনের নাম দিন।" + +#: sphinx/themes/basic/layout.html:122 +#, python-format +msgid "Search within %(docstitle)s" +msgstr "%(docstitle)s এর মধ্যে খুঁজুন" + +#: sphinx/themes/basic/layout.html:131 +msgid "About these documents" +msgstr "এই ডকুমেন্ট সম্পর্কে" + +#: sphinx/themes/basic/layout.html:137 +#: sphinx/themes/basic/search.html:2 +#: sphinx/themes/basic/search.html:5 +msgid "Search" +msgstr "অনুসন্ধান" + +#: sphinx/themes/basic/layout.html:140 +msgid "Copyright" +msgstr "কপিরাইট" + +#: sphinx/themes/basic/layout.html:187 +#: sphinx/themes/scrolls/layout.html:83 +#, python-format +msgid "© Copyright %(copyright)s." +msgstr "© কপিরাইট %(copyright)s." + +#: sphinx/themes/basic/layout.html:189 +#: sphinx/themes/scrolls/layout.html:85 +#, python-format +msgid "© Copyright %(copyright)s." +msgstr "© কপিরাইট %(copyright)s." + +#: sphinx/themes/basic/layout.html:193 +#: sphinx/themes/scrolls/layout.html:89 +#, python-format +msgid "Last updated on %(last_updated)s." +msgstr "%(last_updated)s সর্বশেষ পরিবর্তন করা হয়েছে।" + +#: sphinx/themes/basic/layout.html:196 +#: sphinx/themes/scrolls/layout.html:92 +#, python-format +msgid "Created using Sphinx %(sphinx_version)s." +msgstr "Sphinx %(sphinx_version)s দিয়ে তৈরী।" + +#: sphinx/themes/basic/modindex.html:36 +#: sphinx/themes/scrolls/modindex.html:37 +msgid "Deprecated" +msgstr "ডেপ্রিকেটেড" + +#: sphinx/themes/basic/opensearch.xml:4 +#, python-format +msgid "Search %(docstitle)s" +msgstr "%(docstitle)s-এ খুঁজুন" + +#: sphinx/themes/basic/search.html:9 +msgid "" +"Please activate JavaScript to enable the search\n" +" functionality." +msgstr "" +"অনুসন্ধান করার জন্য অনুগ্রহপূর্বক জাভাস্ক্রিপ্ট \n" +" সক্রিয় করুন।" + +#: sphinx/themes/basic/search.html:14 +msgid "" +"From here you can search these documents. Enter your search\n" +" words into the box below and click \"search\". Note that the search\n" +" function will automatically search for all of the words. Pages\n" +" containing fewer words won't appear in the result list." +msgstr "" +"এখান থেকে এই নথিগুলোতে আপনি অনুসন্ধান করতে পারবেন। \n" +" আপনার কাঙ্ক্ষিত শব্দসমূহ নিচের বাক্সে লিখুন এবং \"অনুসন্ধান\" বাটনে ক্লিক করুন।\n" +" উল্লেখ্য, সকল শব্দসমূহের উপস্থিতি নিয়ে অনুসন্ধান করা হবে। যেসব পাতায় সকল\n" +" শব্দ নেই সেগুলো বাদ দেয়া হবে।" + +#: sphinx/themes/basic/search.html:21 +msgid "search" +msgstr "খুঁজুন" + +#: sphinx/themes/basic/search.html:25 +#: sphinx/themes/basic/static/searchtools.js:473 +msgid "Search Results" +msgstr "অনুসন্ধানের ফলাফল" + +#: sphinx/themes/basic/search.html:27 +msgid "Your search did not match any results." +msgstr "আপনার অনুসন্ধানে কোন ফলাফল পাওয়া যায়নি।" + +#: sphinx/themes/basic/changes/frameset.html:5 +#: sphinx/themes/basic/changes/versionchanges.html:12 +#, python-format +msgid "Changes in Version %(version)s — %(docstitle)s" +msgstr "%(version)s — %(docstitle)s-এ পরিবর্তন সমূহ" + +#: sphinx/themes/basic/changes/rstsource.html:5 +#, python-format +msgid "%(filename)s — %(docstitle)s" +msgstr "%(filename)s — %(docstitle)s" + +#: sphinx/themes/basic/changes/versionchanges.html:17 +#, python-format +msgid "Automatically generated list of changes in version %(version)s" +msgstr "স্বয়ংক্রিয়ভাবে তৈরী %(version)s-এ পরিবর্তন সমূহের তালিকা।" + +#: sphinx/themes/basic/changes/versionchanges.html:18 +msgid "Library changes" +msgstr "লাইব্রেরির পরিবর্তন" + +#: sphinx/themes/basic/changes/versionchanges.html:23 +msgid "C API changes" +msgstr "C API পরিবর্তন" + +#: sphinx/themes/basic/changes/versionchanges.html:25 +msgid "Other changes" +msgstr "অন্যান্য পরিবর্তন" + +#: sphinx/themes/basic/static/doctools.js:138 +#: sphinx/writers/html.py:462 +#: sphinx/writers/html.py:467 +msgid "Permalink to this headline" +msgstr "এই শিরোনামের পার্মালিঙ্ক" + +#: sphinx/themes/basic/static/doctools.js:144 +#: sphinx/writers/html.py:80 +msgid "Permalink to this definition" +msgstr "এই সংজ্ঞার পার্মালিঙ্ক" + +#: sphinx/themes/basic/static/doctools.js:173 +msgid "Hide Search Matches" +msgstr "অনুসন্ধানের ম্যাচগুলো লুকান" + +#: sphinx/themes/basic/static/searchtools.js:274 +msgid "Searching" +msgstr "অনুসন্ধান চলছে" + +#: sphinx/themes/basic/static/searchtools.js:279 +msgid "Preparing search..." +msgstr "অনুসন্ধানের প্রস্তুতি চলছে..." + +#: sphinx/themes/basic/static/searchtools.js:352 +msgid ", in " +msgstr ", -" + +#: sphinx/themes/basic/static/searchtools.js:475 +msgid "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." +msgstr "আপনার অনুসন্ধানে কোন ফলাফল পাওয়া যায়নি। আপনার অনুসন্ধানের শব্দগুলোর সঠিক বানান ও বিভাগ নির্বাচন নিশ্চিত করুন।" + +#: sphinx/themes/basic/static/searchtools.js:477 +#, python-format +msgid "Search finished, found %s page(s) matching the search query." +msgstr "অনুসন্ধান শেষ হয়েছে, ফলাফলে %s-টি পাতা পাওয়া গেছে।" + +#: sphinx/writers/latex.py:187 +msgid "Release" +msgstr "রিলিজ" + +#: sphinx/writers/latex.py:579 +msgid "Footnotes" +msgstr "পাদটীকা" + +#: sphinx/writers/latex.py:647 +msgid "continued from previous page" +msgstr "পূর্ববর্তী পাতা হতে চলমান" + +#: sphinx/writers/latex.py:652 +msgid "Continued on next page" +msgstr "পরবর্তী পাতাতে চলমান" + +#: sphinx/writers/text.py:166 +#, python-format +msgid "Platform: %s" +msgstr "প্লাটফরম: %s" + +#: sphinx/writers/text.py:428 +msgid "[image]" +msgstr "[ছবি]" + From 9c568c68aac9a84e5115d10764f460008e77096a Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 14:41:45 +0200 Subject: [PATCH 158/207] Remove debug statement. --- sphinx/domains/javascript.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py index 9934dba3a..582e2adc6 100644 --- a/sphinx/domains/javascript.py +++ b/sphinx/domains/javascript.py @@ -31,7 +31,6 @@ class JSObject(ObjectDescription): display_prefix = None def handle_signature(self, sig, signode): - import pdb; pdb.set_trace() sig = sig.strip() if '(' in sig and sig[-1:] == ')': prefix, arglist = sig.split('(', 1) From 3a61b58b3f8621a02f53ac30d00e7272b6aca595 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 14:45:17 +0200 Subject: [PATCH 159/207] #470: Fix generated target names for reST domain objects; they are not in the same namespace. --- CHANGES | 3 +++ sphinx/domains/rst.py | 7 ++++--- sphinx/environment.py | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 8781d0e2a..1da078655 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Release 1.0.1 (in development) ============================== +* #470: Fix generated target names for reST domain objects; they + are not in the same namespace. + * #266: Add Bengali language. * #473: Fix a bug in parsing JavaScript object names. diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py index 04092eab0..98cab2241 100644 --- a/sphinx/domains/rst.py +++ b/sphinx/domains/rst.py @@ -29,8 +29,9 @@ class ReSTMarkup(ObjectDescription): def add_target_and_index(self, name, sig, signode): if name not in self.state.document.ids: - signode['names'].append(name) - signode['ids'].append(name) + targetname = name + '-' + self.objtype + signode['names'].append(targetname) + signode['ids'].append(targetname) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) @@ -47,7 +48,7 @@ class ReSTMarkup(ObjectDescription): indextext = self.get_index_text(self.objtype, name) if indextext: self.indexnode['entries'].append(('single', indextext, - name, name)) + targetname, targetname)) def get_index_text(self, objectname, name): if self.objtype == 'directive': diff --git a/sphinx/environment.py b/sphinx/environment.py index 972bfa3ef..5edcb4d90 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -63,7 +63,7 @@ default_settings = { # This is increased every time an environment attribute is added # or changed to properly invalidate pickle files. -ENV_VERSION = 36 +ENV_VERSION = 37 default_substitutions = set([ From 93f531ae1a6e05f6d67e830b26620c70cb53c452 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 14:57:32 +0200 Subject: [PATCH 160/207] Fix fix. --- sphinx/domains/rst.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py index 98cab2241..61809f330 100644 --- a/sphinx/domains/rst.py +++ b/sphinx/domains/rst.py @@ -28,8 +28,8 @@ class ReSTMarkup(ObjectDescription): """ def add_target_and_index(self, name, sig, signode): - if name not in self.state.document.ids: - targetname = name + '-' + self.objtype + targetname = name + '-' + self.objtype + if targetname not in self.state.document.ids: signode['names'].append(targetname) signode['ids'].append(targetname) signode['first'] = (not self.names) From 4a400034d9d255d0c8da7d824d8038c2d90a71b2 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 17:52:57 +0200 Subject: [PATCH 161/207] This apparently fixes a failing test in Gentoo. --- tests/test_build_html.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_build_html.py b/tests/test_build_html.py index bafee243a..41ebf0556 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -37,7 +37,7 @@ ENV_WARNINGS = """\ http://www.python.org/logo.png %(root)s/includes.txt:\\d*: \\(WARNING/2\\) Encoding 'utf-8-sig' used for \ reading included file u'wrongenc.inc' seems to be wrong, try giving an \ -:encoding: option +:encoding: option\n? %(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png %(root)s/objects.txt:79: WARNING: using old C markup; please migrate to \ new-style markup \(e.g. c:function instead of cfunction\), see \ From fb0e13e0ecaa170c33ea277b3ba8c6892863d459 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 17:58:01 +0200 Subject: [PATCH 162/207] Fix handling of non-text field types. --- sphinx/util/docfields.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index 1ae49c6c5..9eafde0ac 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -141,9 +141,12 @@ class TypedField(GroupedField): par = nodes.paragraph() par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong) if fieldarg in types: - typename = u''.join(n.astext() for n in types[fieldarg]) par += nodes.Text(' (') - par += self.make_xref(self.typerolename, domain, typename) + if len(fieldtype) == 1 and isinstance(fieldtype[0], nodes.Text): + typename = u''.join(n.astext() for n in types[fieldarg]) + par += self.make_xref(self.typerolename, domain, typename) + else: + par += fieldtype par += nodes.Text(')') par += nodes.Text(' -- ') par += content From e8f2d8f8e4a3301cdfd57f338b967f89323c9636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Mon, 26 Jul 2010 05:16:00 +0200 Subject: [PATCH 163/207] Changed documentation URL by request --- EXAMPLES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXAMPLES b/EXAMPLES index 52fce0e8b..44c511e9e 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -12,7 +12,7 @@ interesting examples. Documentation using the default theme ------------------------------------- -* APSW: http://apsw.googlecode.com/svn/publish/index.html +* APSW: http://apidoc.apsw.googlecode.com/hg/index.html * ASE: https://wiki.fysik.dtu.dk/ase/ * boostmpi: http://documen.tician.de/boostmpi/ * Calibre: http://calibre.kovidgoyal.net/user_manual/ From 3b64ec2a2e6468cbf1b6b3cc56035f7fdb0249cb Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 19:07:51 +0200 Subject: [PATCH 164/207] Now that the expected warnings are regexes, diffing them with the actual output makes no sense anymore. --- tests/test_build_html.py | 5 ++--- tests/test_build_latex.py | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 41ebf0556..5f4dea0ff 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -11,7 +11,6 @@ import os import re -import difflib import htmlentitydefs from StringIO import StringIO @@ -285,8 +284,8 @@ def test_html(app): html_warnings_exp = HTML_WARNINGS % {'root': re.escape(app.srcdir)} assert re.match(html_warnings_exp + '$', html_warnings), \ 'Warnings don\'t match:\n' + \ - '\n'.join(difflib.ndiff(html_warnings_exp.splitlines(), - html_warnings.splitlines())) + '--- Expected (regex):\n' + html_warnings_exp + \ + '--- Got:\n' + html_warnings for fname, paths in HTML_XPATH.iteritems(): parser = NslessParser() diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 6a20746b6..4405395a0 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -12,7 +12,6 @@ import os import re import sys -import difflib from StringIO import StringIO from subprocess import Popen, PIPE @@ -42,8 +41,9 @@ def test_latex(app): latex_warnings_exp = LATEX_WARNINGS % {'root': app.srcdir} assert re.match(latex_warnings_exp + '$', latex_warnings), \ 'Warnings don\'t match:\n' + \ - '\n'.join(difflib.ndiff(latex_warnings_exp.splitlines(), - latex_warnings.splitlines())) + '--- Expected (regex):\n' + latex_warnings_exp + \ + '--- Got:\n' + latex_warnings + # file from latex_additional_files assert (app.outdir / 'svgimg.svg').isfile() From e081cf4d3b0f9fb55aff0bacc6e06c28add77a74 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 19:08:09 +0200 Subject: [PATCH 165/207] Add a missing assignment. --- sphinx/util/docfields.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index 9eafde0ac..c8e58f48a 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -142,6 +142,7 @@ class TypedField(GroupedField): par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong) if fieldarg in types: par += nodes.Text(' (') + fieldtype = types[fieldarg] if len(fieldtype) == 1 and isinstance(fieldtype[0], nodes.Text): typename = u''.join(n.astext() for n in types[fieldarg]) par += self.make_xref(self.typerolename, domain, typename) From 5a28ae4686116a7814909d825aabb5512c407358 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 19:19:29 +0200 Subject: [PATCH 166/207] Add some tests for docfields. --- tests/root/objects.txt | 5 +++++ tests/test_build_html.py | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/root/objects.txt b/tests/root/objects.txt index ca3d0eb76..334827de2 100644 --- a/tests/root/objects.txt +++ b/tests/root/objects.txt @@ -43,6 +43,11 @@ Testing object descriptions .. class:: TimeInt + :param moo: |test| + :type moo: |test| + +.. |test| replace:: Moo + .. class:: Time(hour, minute, isdst) :param hour: The year. diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 5f4dea0ff..4dee513ae 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -36,9 +36,9 @@ ENV_WARNINGS = """\ http://www.python.org/logo.png %(root)s/includes.txt:\\d*: \\(WARNING/2\\) Encoding 'utf-8-sig' used for \ reading included file u'wrongenc.inc' seems to be wrong, try giving an \ -:encoding: option\n? +:encoding: option\\n? %(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png -%(root)s/objects.txt:79: WARNING: using old C markup; please migrate to \ +%(root)s/objects.txt:84: WARNING: using old C markup; please migrate to \ new-style markup \(e.g. c:function instead of cfunction\), see \ http://sphinx.pocoo.org/domains.html """ @@ -50,6 +50,16 @@ HTML_WARNINGS = ENV_WARNINGS + """\ %(root)s/markup.txt:: WARNING: invalid pair index entry u'keyword; ' """ +def tail_check(check): + rex = re.compile(check) + def checker(nodes): + for node in nodes: + if node.tail and rex.search(node.tail): + return True + assert False, '%r not found in tail of any nodes %s' % (check, nodes) + return checker + + HTML_XPATH = { 'images.html': [ (".//img[@src='_images/img.png']", ''), @@ -171,6 +181,10 @@ HTML_XPATH = { 'Testing various markup'), # custom sidebar (".//h4", 'Custom sidebar'), + # docfields + (".//td[@class='field-body']/ul/li/strong", '^moo$'), + (".//td[@class='field-body']/ul/li/strong", + tail_check(r'\(Moo\) .* Moo')), ], 'contents.html': [ (".//meta[@name='hc'][@content='hcval']", ''), From 6262c275a750d36402ba430f3f01ffaca18b3098 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 19:40:19 +0200 Subject: [PATCH 167/207] Prepare 1.0.1 release. --- CHANGES | 4 ++-- sphinx/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 1da078655..4d02c7a52 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -Release 1.0.1 (in development) -============================== +Release 1.0.1 (Jul 27, 2010) +============================ * #470: Fix generated target names for reST domain objects; they are not in the same namespace. diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 8c1ebed56..289410075 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -12,8 +12,8 @@ import sys from os import path -__version__ = '1.0+' -__released__ = '1.0' # used when Sphinx builds its own docs +__version__ = '1.0.1' +__released__ = '1.0.1' # used when Sphinx builds its own docs package_dir = path.abspath(path.dirname(__file__)) From 3d6dd4d1e7a56921943c191ed87316bd5aded7e9 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 19:52:25 +0200 Subject: [PATCH 169/207] Post-release updates. --- CHANGES | 3 +++ sphinx/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 4d02c7a52..48d03e785 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +Release 1.0.2 (in development) +============================== + Release 1.0.1 (Jul 27, 2010) ============================ diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 289410075..50aa28cd6 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -12,7 +12,7 @@ import sys from os import path -__version__ = '1.0.1' +__version__ = '1.0.1+' __released__ = '1.0.1' # used when Sphinx builds its own docs package_dir = path.abspath(path.dirname(__file__)) From a1fd9830e57944b980629ad3bf5b11771dc0af32 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 27 Jul 2010 20:44:32 +0200 Subject: [PATCH 170/207] Dont fail when no json impl is found. --- sphinx/util/jsonimpl.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sphinx/util/jsonimpl.py b/sphinx/util/jsonimpl.py index 21f285d30..b83661a7e 100644 --- a/sphinx/util/jsonimpl.py +++ b/sphinx/util/jsonimpl.py @@ -39,5 +39,8 @@ def dumps(obj, *args, **kwds): kwds['cls'] = SphinxJSONEncoder return json.dumps(obj, *args, **kwds) -load = json.load -loads = json.loads +def load(*args, **kwds): + return json.load(*args, **kwds) + +def loads(*args, **kwds): + return json.loads(*args, **kwds) From 13017eecc8fc203695b5587afcac6a7dbf5b6cb6 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 14:53:39 +0200 Subject: [PATCH 171/207] Go to #pocoo. --- doc/_templates/indexsidebar.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/_templates/indexsidebar.html b/doc/_templates/indexsidebar.html index a268ec6ef..85b8fba95 100644 --- a/doc/_templates/indexsidebar.html +++ b/doc/_templates/indexsidebar.html @@ -23,6 +23,6 @@ are also available.

    -

    or come to the #python-docs channel on FreeNode.

    +

    or come to the #pocoo channel on FreeNode.

    You can also open an issue at the tracker.

    From 2d0c9a0e7155bb71a8bc76fd6d5f2d2145c9cdbd Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:43:30 +0200 Subject: [PATCH 172/207] Move item to the correct section. --- CHANGES | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 573b4edd6..f1fb982b8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Release 1.1 (in development) ============================ +* Added Python 3.x support. + + Release 1.0.2 (in development) ============================== @@ -23,8 +26,6 @@ Release 1.0.1 (Jul 27, 2010) * Fix hyperrefs in object descriptions for LaTeX. - * Added Python 3.x support. - Release 1.0 (Jul 23, 2010) ========================== From c683c6ed833766c63c20fc33c830a8db5604979a Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:49:06 +0200 Subject: [PATCH 173/207] Add some changes not picked up in the transplantation process. --- Makefile | 2 +- README | 12 ++++++++++++ doc/intro.rst | 8 ++++---- tests/test_build_html.py | 9 +++++---- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 13228c788..fc1140f33 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PYTHON ?= python3 +PYTHON ?= python .PHONY: all check clean clean-pyc clean-patchfiles clean-generated pylint \ reindent test diff --git a/README b/README index bb2dea9d6..e31d6b936 100644 --- a/README +++ b/README @@ -26,6 +26,18 @@ Then, direct your browser to ``_build/html/index.html``. Or read them online at . +Testing +======= + +To run the tests with the interpreter available as ``python``, use:: + + make test + +If you want to use a different interpreter, e.g. ``python3``, use:: + + PYTHON=python3 make test + + Contributing ============ diff --git a/doc/intro.rst b/doc/intro.rst index 1a39e266c..c85fbbad3 100644 --- a/doc/intro.rst +++ b/doc/intro.rst @@ -45,10 +45,10 @@ See the :ref:`pertinent section in the FAQ list `. Prerequisites ------------- -Sphinx needs at least **Python 2.4** to run, as well as the docutils_ and -Jinja2_ libraries. Sphinx should work with docutils version 0.5 or some -(not broken) SVN trunk snapshot. If you like to have source code highlighting -support, you must also install the Pygments_ library. +Sphinx needs at least **Python 2.4** or **Python 3.1** to run, as well as the +docutils_ and Jinja2_ libraries. Sphinx should work with docutils version 0.5 +or some (not broken) SVN trunk snapshot. If you like to have source code +highlighting support, you must also install the Pygments_ library. .. _reStructuredText: http://docutils.sf.net/rst.html .. _docutils: http://docutils.sf.net/ diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 3ca2c757f..0c59d9cca 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -51,6 +51,11 @@ HTML_WARNINGS = ENV_WARNINGS + """\ %(root)s/markup.txt:: WARNING: invalid pair index entry u'keyword; ' """ +if sys.version_info >= (3, 0): + ENV_WARNINGS = remove_unicode_literals(ENV_WARNINGS) + HTML_WARNINGS = remove_unicode_literals(HTML_WARNINGS) + + def tail_check(check): rex = re.compile(check) def checker(nodes): @@ -61,10 +66,6 @@ def tail_check(check): return checker -if sys.version_info >= (3, 0): - ENV_WARNINGS = remove_unicode_literals(ENV_WARNINGS) - HTML_WARNINGS = remove_unicode_literals(HTML_WARNINGS) - HTML_XPATH = { 'images.html': [ (".//img[@src='_images/img.png']", ''), From 7866ce29c69e6a843c4bf0d5472e29f15e70ae87 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:58:17 +0200 Subject: [PATCH 174/207] Keep sphinx/__init__.py executable with Python 3. --- sphinx/__init__.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 31c61a86a..1ea2e7bf7 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -9,6 +9,9 @@ :license: BSD, see LICENSE for details. """ +# Keep this file executable as-is in Python 3! +# (Otherwise getting the version out of it from setup.py is impossible.) + import sys from os import path @@ -35,13 +38,14 @@ if '+' in __version__ or 'pre' in __version__: def main(argv=sys.argv): if sys.version_info[:3] < (2, 4, 0): - print >>sys.stderr, \ - 'Error: Sphinx requires at least Python 2.4 to run.' + sys.stderr.write('Error: Sphinx requires at least ' + 'Python 2.4 to run.\n') return 1 try: from sphinx import cmdline - except ImportError, err: + except ImportError: + err = sys.exc_info()[1] errstr = str(err) if errstr.lower().startswith('no module named'): whichmod = errstr[16:] @@ -54,14 +58,14 @@ def main(argv=sys.argv): whichmod = 'roman module (which is distributed with Docutils)' hint = ('This can happen if you upgraded docutils using\n' 'easy_install without uninstalling the old version' - 'first.') + 'first.\n') else: whichmod += ' module' - print >>sys.stderr, ('Error: The %s cannot be found. ' - 'Did you install Sphinx and its dependencies ' - 'correctly?' % whichmod) + sys.stderr.write('Error: The %s cannot be found. ' + 'Did you install Sphinx and its dependencies ' + 'correctly?\n' % whichmod) if hint: - print >> sys.stderr, hint + sys.stderr.write(hint) return 1 raise return cmdline.main(argv) From 829a05e1ddf9bcf06911804b292a287a7ad7ff27 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 19:58:47 +0200 Subject: [PATCH 175/207] Ignore distribute files. --- .hgignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgignore b/.hgignore index 40c00aac7..b68cccf91 100644 --- a/.hgignore +++ b/.hgignore @@ -16,3 +16,4 @@ \.DS_Store$ ~$ ^utils/.*3\.py$ +^distribute- From 67ffb9bf5477b6d9489157ba761065f9218b937b Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 20:24:35 +0200 Subject: [PATCH 176/207] Fix raw_input which is not converted by 2to3 if not called. --- sphinx/quickstart.py | 8 ++++++-- tests/test_quickstart.py | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 557f8c094..92a5bea2a 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -22,7 +22,11 @@ from sphinx.util.console import purple, bold, red, turquoise, \ from sphinx.util import texescape # function to get input from terminal -- overridden by the test suite -term_input = raw_input +try: + # this raw_input is not converted by 2to3 + term_input = raw_input +except NameError: + term_input = input PROMPT_PREFIX = '> ' @@ -692,7 +696,7 @@ if sys.version_info >= (3, 0): return _unicode_string_re.sub('\\1', source) for f in ['QUICKSTART_CONF', 'EPUB_CONFIG', 'INTERSPHINX_CONFIG']: - globals()[f] = convert_python_source(globals()[f]) + globals()[f] = _convert_python_source(globals()[f]) del _unicode_string_re, _convert_python_source diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index 72ae764d6..541959bd3 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -36,8 +36,13 @@ def mock_raw_input(answers, needanswer=False): return '' return raw_input +try: + real_raw_input = raw_input +except NameError: + real_raw_input = input + def teardown_module(): - qs.term_input = raw_input + qs.term_input = real_raw_input qs.TERM_ENCODING = getattr(sys.stdin, 'encoding', None) coloron() From 27b4265a2f002e317872149eb5e8a28df407f005 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 28 Jul 2010 20:30:05 +0200 Subject: [PATCH 177/207] Update phony targets list. --- Makefile | 4 ++-- sphinx/ext/oldcmarkup.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index fc1140f33..09aa3c962 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ PYTHON ?= python -.PHONY: all check clean clean-pyc clean-patchfiles clean-generated pylint \ - reindent test +.PHONY: all check clean clean-pyc clean-patchfiles clean-backupfiles \ + clean-generated pylint reindent test covertest build convert-utils DONT_CHECK = -i build -i dist -i sphinx/style/jquery.js \ -i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py \ diff --git a/sphinx/ext/oldcmarkup.py b/sphinx/ext/oldcmarkup.py index 84ae61dd2..3aa53fd86 100644 --- a/sphinx/ext/oldcmarkup.py +++ b/sphinx/ext/oldcmarkup.py @@ -31,6 +31,7 @@ class OldCDirective(Directive): def run(self): env = self.state.document.settings.env if not env.app._oldcmarkup_warned: + print 'XXXYYY' env.warn(env.docname, WARNING_MSG, self.lineno) env.app._oldcmarkup_warned = True newname = 'c:' + self.name[1:] From cb26c7807943853a3393a7e8deba57131762342f Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 29 Jul 2010 09:27:46 +0200 Subject: [PATCH 178/207] Describe the "deprecated" directive. --- doc/markup/para.rst | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/doc/markup/para.rst b/doc/markup/para.rst index be06f6365..ecc6b4a6b 100644 --- a/doc/markup/para.rst +++ b/doc/markup/para.rst @@ -42,15 +42,25 @@ units as well as normal text: Example:: .. versionadded:: 2.5 - The `spam` parameter. + The *spam* parameter. Note that there must be no blank line between the directive head and the explanation; this is to make these blocks visually continuous in the markup. .. rst:directive:: .. versionchanged:: version - Similar to :rst:dir:`versionadded`, but describes when and what changed in the named - feature in some way (new parameters, changed side effects, etc.). + Similar to :rst:dir:`versionadded`, but describes when and what changed in + the named feature in some way (new parameters, changed side effects, etc.). + +.. rst:directive:: .. deprecated:: vesion + + Similar to :rst:dir:`versionchanged`, but describes when the feature was + deprecated. An explanation can also be given, for example to inform the + reader what should be used instead. Example:: + + .. deprecated:: 3.1 + Use :func:`spam` instead. + -------------- From 86cd745dc1f5338804fa5adf24447a9427c09fb8 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Fri, 30 Jul 2010 16:59:47 +0200 Subject: [PATCH 179/207] Run 2to3 on config files which contain Python 2.x unicode literals. --- sphinx/config.py | 27 +++++++++++------ sphinx/quickstart.py | 8 ++++- sphinx/util/pycompat.py | 67 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 87 insertions(+), 15 deletions(-) diff --git a/sphinx/config.py b/sphinx/config.py index 708da162e..efa9f7407 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -13,13 +13,20 @@ import os import re import sys from os import path +try: + from distutils.util import run_2to3 +except ImportError: + run_2to3 = None from sphinx.errors import ConfigError from sphinx.util.osutil import make_filename -from sphinx.util.pycompat import bytes, b +from sphinx.util.pycompat import bytes, b, should_run_2to3, run_2to3 nonascii_re = re.compile(b(r'[\x80-\xff]')) +CONFIG_SYNTAX_ERROR = "There is a syntax error in your configuration file: %s" +if sys.version_info >= (3, 0): + CONFIG_SYNTAX_ERROR += "\nDid you change the syntax from 2.x to 3.x?" class Config(object): """Configuration file abstraction.""" @@ -167,15 +174,17 @@ class Config(object): try: try: os.chdir(dirname) - f = open(config_file, 'rb') - try: - code = compile(f.read(), config_file, 'exec') - finally: - f.close() - exec code in config + if should_run_2to3(config_file): + code = run_2to3(config_file) + else: + f = open(config_file, 'rb') + try: + code = f.read() + finally: + f.close() + exec compile(code, config_file, 'exec') in config except SyntaxError, err: - raise ConfigError('There is a syntax error in your ' - 'configuration file: ' + str(err)) + raise ConfigError(CONFIG_SYNTAX_ERROR % err) finally: os.chdir(olddir) diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index 92a5bea2a..7e38a742a 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -31,7 +31,13 @@ except NameError: PROMPT_PREFIX = '> ' -QUICKSTART_CONF = '''\ +if sys.version_info >= (3, 0): + # prevents that the file is checked for being written in Python 2.x syntax + QUICKSTART_CONF = '#!/usr/bin/env python3\n' +else: + QUICKSTART_CONF = '' + +QUICKSTART_CONF += '''\ # -*- coding: utf-8 -*- # # %(project)s documentation build configuration file, created by diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index 229b54b45..2ec71e72b 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -12,6 +12,7 @@ import sys import codecs import encodings +import re try: from types import ClassType @@ -20,11 +21,6 @@ except ImportError: # Python 3 class_types = (type,) -try: - base_exception = BaseException -except NameError: - base_exception = Exception - # the ubiquitous "bytes" helper function if sys.version_info >= (3, 0): @@ -34,6 +30,66 @@ else: b = str +encoding_re = re.compile(b(r'coding[=:]\s*([-\w.]+)')) +unicode_literal_re = re.compile(ur""" +(?: + "(?:[^"\]]*(?:\\.[^"\\]*)*)"| + '(?:[^'\]]*(?:\\.[^'\\]*)*)' +) +""", re.VERBOSE) + + +try: + from lib2to3.refactor import RefactoringTool, get_fixers_from_package +except ImportError: + _run_2to3 = None + def should_run_2to3(filepath): + return False +else: + def should_run_2to3(filepath): + # th default source code encoding for python 2.x + encoding = 'ascii' + # only the first match of the encoding cookie counts + encoding_set = False + f = open(filepath, 'rb') + try: + for i, line in enumerate(f): + if line.startswith(b('#')): + if i == 0 and b('python3') in line: + return False + if not encoding_set: + encoding_match = encoding_re.match(line) + if encoding_match: + encoding = encoding_match.group(1) + encodin_set = True + elif line.strip(): + try: + line = line.decode(encoding) + except UnicodeDecodeError: + # I'm not sure this will work but let's try it anyway + return True + if unicode_literal_re.search(line) is not None: + return True + finally: + f.close() + return False + + def run_2to3(filepath): + sys.path.append('..') + fixers = get_fixers_from_package('lib2to3.fixes') + fixers.extend(get_fixers_from_package('custom_fixers')) + refactoring_tool = RefactoringTool(fixers) + source = refactoring_tool._read_python_source(filepath)[0] + ast = refactoring_tool.refactor_string(source, 'conf.py') + return unicode(ast) + + +try: + base_exception = BaseException +except NameError: + base_exception = Exception + + try: next = next except NameError: @@ -41,6 +97,7 @@ except NameError: def next(iterator): return iterator.next() + try: bytes = bytes except NameError: From 0e84c758229f0a71a52b33c5e19d2e0b7d8b0ef1 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 31 Jul 2010 19:47:15 +0200 Subject: [PATCH 180/207] Improve support for automatic 2to3 conversion of config files. It now kicks in whenever the original file raises SyntaxErrors on compiling. --- sphinx/config.py | 37 +++++++++++++---------- sphinx/util/pycompat.py | 65 +++++++++++------------------------------ tests/test_config.py | 6 ++++ 3 files changed, 45 insertions(+), 63 deletions(-) diff --git a/sphinx/config.py b/sphinx/config.py index efa9f7407..6c27f85f0 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -13,14 +13,10 @@ import os import re import sys from os import path -try: - from distutils.util import run_2to3 -except ImportError: - run_2to3 = None from sphinx.errors import ConfigError from sphinx.util.osutil import make_filename -from sphinx.util.pycompat import bytes, b, should_run_2to3, run_2to3 +from sphinx.util.pycompat import bytes, b, convert_with_2to3 nonascii_re = re.compile(b(r'[\x80-\xff]')) @@ -172,17 +168,28 @@ class Config(object): config['tags'] = tags olddir = os.getcwd() try: + # we promise to have the config dir as current dir while the + # config file is executed + os.chdir(dirname) + # get config source + f = open(config_file, 'rb') try: - os.chdir(dirname) - if should_run_2to3(config_file): - code = run_2to3(config_file) - else: - f = open(config_file, 'rb') - try: - code = f.read() - finally: - f.close() - exec compile(code, config_file, 'exec') in config + source = f.read() + finally: + f.close() + try: + # compile to a code object, handle syntax errors + try: + code = compile(source, config_file, 'exec') + except SyntaxError: + if convert_with_2to3: + # maybe the file uses 2.x syntax; try to refactor to + # 3.x syntax using 2to3 + source = convert_with_2to3(config_file) + code = compile(source, config_file, 'exec') + else: + raise + exec code in config except SyntaxError, err: raise ConfigError(CONFIG_SYNTAX_ERROR % err) finally: diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index 2ec71e72b..5f23bbe18 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -30,58 +30,26 @@ else: b = str -encoding_re = re.compile(b(r'coding[=:]\s*([-\w.]+)')) -unicode_literal_re = re.compile(ur""" -(?: - "(?:[^"\]]*(?:\\.[^"\\]*)*)"| - '(?:[^'\]]*(?:\\.[^'\\]*)*)' -) -""", re.VERBOSE) +# Support for running 2to3 over config files - -try: - from lib2to3.refactor import RefactoringTool, get_fixers_from_package -except ImportError: - _run_2to3 = None - def should_run_2to3(filepath): - return False +if sys.version_info < (3, 0): + # no need to refactor on 2.x versions + convert_with_2to3 = None else: - def should_run_2to3(filepath): - # th default source code encoding for python 2.x - encoding = 'ascii' - # only the first match of the encoding cookie counts - encoding_set = False - f = open(filepath, 'rb') - try: - for i, line in enumerate(f): - if line.startswith(b('#')): - if i == 0 and b('python3') in line: - return False - if not encoding_set: - encoding_match = encoding_re.match(line) - if encoding_match: - encoding = encoding_match.group(1) - encodin_set = True - elif line.strip(): - try: - line = line.decode(encoding) - except UnicodeDecodeError: - # I'm not sure this will work but let's try it anyway - return True - if unicode_literal_re.search(line) is not None: - return True - finally: - f.close() - return False - - def run_2to3(filepath): - sys.path.append('..') + def convert_with_2to3(filepath): + from lib2to3.refactor import RefactoringTool, get_fixers_from_package + from lib2to3.pgen2.parse import ParseError fixers = get_fixers_from_package('lib2to3.fixes') - fixers.extend(get_fixers_from_package('custom_fixers')) refactoring_tool = RefactoringTool(fixers) source = refactoring_tool._read_python_source(filepath)[0] - ast = refactoring_tool.refactor_string(source, 'conf.py') - return unicode(ast) + try: + tree = refactoring_tool.refactor_string(source, 'conf.py') + except ParseError, err: + # do not propagate lib2to3 exceptions + lineno, offset = err.context[1] + # try to match ParseError details with SyntaxError details + raise SyntaxError(err.msg, (filepath, lineno, offset, err.value)) + return unicode(tree) try: @@ -93,7 +61,8 @@ except NameError: try: next = next except NameError: - # this is on Python 2, where the method is called "next" + # this is on Python 2, where the method is called "next" (it is refactored + # to __next__ by 2to3, but in that case never executed) def next(iterator): return iterator.next() diff --git a/tests/test_config.py b/tests/test_config.py index ecf90f609..7fce4495b 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -88,6 +88,12 @@ def test_errors_warnings(dir): write_file(dir / 'conf.py', u'project = \n', 'ascii') raises_msg(ConfigError, 'conf.py', Config, dir, 'conf.py', {}, None) + # test the automatic conversion of 2.x only code in configs + write_file(dir / 'conf.py', u'\n\nproject = u"Jägermeister"\n', 'utf-8') + cfg = Config(dir, 'conf.py', {}, None) + cfg.init_values() + assert cfg.project == u'Jägermeister' + # test the warning for bytestrings with non-ascii content # bytestrings with non-ascii content are a syntax error in python3 so we # skip the test there From 1e010aa858ba7e53f26cdbc0ef7b6f6fb5de4302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Mon, 2 Aug 2010 13:30:59 +0200 Subject: [PATCH 181/207] Fix ASCII diagram --- sphinx/ext/inheritance_diagram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index b930d8cab..a12bad256 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -""" +r""" sphinx.ext.inheritance_diagram ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From bf159679697f9940298ca99582b71314b4d144a1 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 10:14:10 +0200 Subject: [PATCH 182/207] #486: Fix removal of ``!`` for all cross-reference roles. --- CHANGES | 3 +++ sphinx/roles.py | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 48d03e785..dce6e713a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Release 1.0.2 (in development) ============================== +* #486: Fix removal of ``!`` for all cross-reference roles. + + Release 1.0.1 (Jul 27, 2010) ============================ diff --git a/sphinx/roles.py b/sphinx/roles.py index d3f3c67e3..bacdad5b6 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -105,9 +105,9 @@ class XRefRole(object): classes = ['xref', domain, '%s-%s' % (domain, role)] # if the first character is a bang, don't cross-reference at all if text[0:1] == '!': - text = utils.unescape(text) + text = utils.unescape(text)[1:] if self.fix_parens: - text, tgt = self._fix_parens(env, False, text[1:], "") + text, tgt = self._fix_parens(env, False, text, "") innernode = self.innernodeclass(rawtext, text, classes=classes) return self.result_nodes(inliner.document, env, innernode, is_ref=False) From 01c501054e4e42e2c614c7a244f8b769938909f8 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 11:58:43 +0200 Subject: [PATCH 183/207] #480: Fix handling of target naming in intersphinx. --- CHANGES | 2 ++ doc/conf.py | 2 ++ doc/ext/intersphinx.rst | 6 ++-- sphinx/ext/intersphinx.py | 17 +++++++++-- tests/test_intersphinx.py | 60 +++++++++++++++++++++++---------------- 5 files changed, 57 insertions(+), 30 deletions(-) diff --git a/CHANGES b/CHANGES index dce6e713a..cb80d72c6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ Release 1.0.2 (in development) ============================== +* #480: Fix handling of target naming in intersphinx. + * #486: Fix removal of ``!`` for all cross-reference roles. diff --git a/doc/conf.py b/doc/conf.py index 299f321ac..21e8d2f54 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -8,6 +8,8 @@ import sphinx extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.autosummary', 'sphinx.ext.extlinks'] +#intersphinx_mapping = {'python': ('http://docs.python.org/dev', None)} + master_doc = 'contents' templates_path = ['_templates'] exclude_patterns = ['_build'] diff --git a/doc/ext/intersphinx.rst b/doc/ext/intersphinx.rst index bb2a5a8c4..7997472a7 100644 --- a/doc/ext/intersphinx.rst +++ b/doc/ext/intersphinx.rst @@ -84,7 +84,7 @@ linking: To add links to modules and objects in the Python standard library documentation, use:: - intersphinx_mapping = {'python': ('http://docs.python.org/', None)} + intersphinx_mapping = {'python': ('http://docs.python.org/3.2', None)} This will download the corresponding :file:`objects.inv` file from the Internet and generate links to the pages under the given URI. The downloaded @@ -94,12 +94,12 @@ linking: A second example, showing the meaning of a non-``None`` value of the second tuple item:: - intersphinx_mapping = {'python': ('http://docs.python.org/', + intersphinx_mapping = {'python': ('http://docs.python.org/3.2', 'python-inv.txt')} This will read the inventory from :file:`python-inv.txt` in the source directory, but still generate links to the pages under - ``http://docs.python.org/``. It is up to you to update the inventory file as + ``http://docs.python.org/3.2``. It is up to you to update the inventory file as new objects are added to the Python documentation. .. confval:: intersphinx_cache_limit diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 0a210879a..055fc9cd9 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -205,9 +205,20 @@ def missing_reference(app, env, node, contnode): proj, version, uri, dispname = inventory[objtype][target] newnode = nodes.reference('', '', internal=False, refuri=uri, reftitle='(in %s v%s)' % (proj, version)) - if dispname == '-': - dispname = target - newnode.append(contnode.__class__(dispname, dispname)) + if node.get('refexplicit'): + # use whatever title was given + newnode.append(contnode) + elif dispname == '-': + # use whatever title was given, but strip prefix + title = contnode.astext() + if in_set and title.startswith(in_set+':'): + newnode.append(contnode.__class__(title[len(in_set)+1:], + title[len(in_set)+1:])) + else: + newnode.append(contnode) + else: + # else use the given display name (used for :ref:) + newnode.append(contnode.__class__(dispname, dispname)) return newnode # at least get rid of the ':' in the target if no explicit title given if in_set is not None and not node.get('refexplicit', True): diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py index 8b6547e54..3b50cc78c 100644 --- a/tests/test_intersphinx.py +++ b/tests/test_intersphinx.py @@ -94,46 +94,58 @@ def test_missing_reference(tempdir, app): ('foo', '2.0', 'http://docs.python.org/foo.html#module-module2', '-') # create fake nodes and check referencing - contnode = nodes.emphasis('foo', 'foo') - refnode = addnodes.pending_xref('') - refnode['reftarget'] = 'module1.func' - refnode['reftype'] = 'func' - refnode['refdomain'] = 'py' - rn = missing_reference(app, app.env, refnode, contnode) + def fake_node(domain, type, target, content, **attrs): + contnode = nodes.emphasis(content, content) + node = addnodes.pending_xref('') + node['reftarget'] = target + node['reftype'] = type + node['refdomain'] = domain + node.attributes.update(attrs) + node += contnode + return node, contnode + + def reference_check(*args, **kwds): + node, contnode = fake_node(*args, **kwds) + return missing_reference(app, app.env, node, contnode) + + # check resolution when a target is found + rn = reference_check('py', 'func', 'module1.func', 'foo') assert isinstance(rn, nodes.reference) assert rn['refuri'] == 'http://docs.python.org/sub/foo.html#module1.func' assert rn['reftitle'] == '(in foo v2.0)' - assert rn[0].astext() == 'module1.func' + assert rn[0].astext() == 'foo' # create unresolvable nodes and check None return value - refnode['reftype'] = 'foo' - assert missing_reference(app, app.env, refnode, contnode) is None - - refnode['reftype'] = 'function' - refnode['reftarget'] = 'foo.func' - assert missing_reference(app, app.env, refnode, contnode) is None + assert reference_check('py', 'foo', 'module1.func', 'foo') is None + assert reference_check('py', 'func', 'foo', 'foo') is None + assert reference_check('py', 'func', 'foo', 'foo') is None # check handling of prefixes # prefix given, target found: prefix is stripped - refnode['reftype'] = 'mod' - refnode['reftarget'] = 'py3k:module2' - rn = missing_reference(app, app.env, refnode, contnode) + rn = reference_check('py', 'mod', 'py3k:module2', 'py3k:module2') assert rn[0].astext() == 'module2' + # prefix given, but not in title: nothing stripped + rn = reference_check('py', 'mod', 'py3k:module2', 'module2') + assert rn[0].astext() == 'module2' + + # prefix given, but explicit: nothing stripped + rn = reference_check('py', 'mod', 'py3k:module2', 'py3k:module2', + refexplicit=True) + assert rn[0].astext() == 'py3k:module2' + # prefix given, target not found and nonexplicit title: prefix is stripped - refnode['reftarget'] = 'py3k:unknown' - refnode['refexplicit'] = False - contnode[0] = nodes.Text('py3k:unknown') - rn = missing_reference(app, app.env, refnode, contnode) + node, contnode = fake_node('py', 'mod', 'py3k:unknown', 'py3k:unknown', + refexplicit=False) + rn = missing_reference(app, app.env, node, contnode) assert rn is None assert contnode[0].astext() == 'unknown' # prefix given, target not found and explicit title: nothing is changed - refnode['reftarget'] = 'py3k:unknown' - refnode['refexplicit'] = True - contnode[0] = nodes.Text('py3k:unknown') - rn = missing_reference(app, app.env, refnode, contnode) + node, contnode = fake_node('py', 'mod', 'py3k:unknown', 'py3k:unknown', + refexplicit=True) + rn = missing_reference(app, app.env, node, contnode) assert rn is None assert contnode[0].astext() == 'py3k:unknown' From 29547f798172a34e00fded1da2f9dc0b0f31bc09 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 12:02:27 +0200 Subject: [PATCH 184/207] #488: Fix crash when json-py is installed, which provides a ``json`` module but is incompatible to simplejson. --- CHANGES | 3 +++ sphinx/util/jsonimpl.py | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index cb80d72c6..60c55e7a9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Release 1.0.2 (in development) ============================== +* #488: Fix crash when json-py is installed, which provides a + ``json`` module but is incompatible to simplejson. + * #480: Fix handling of target naming in intersphinx. * #486: Fix removal of ``!`` for all cross-reference roles. diff --git a/sphinx/util/jsonimpl.py b/sphinx/util/jsonimpl.py index b83661a7e..fda85b5e3 100644 --- a/sphinx/util/jsonimpl.py +++ b/sphinx/util/jsonimpl.py @@ -13,8 +13,10 @@ import UserString try: import json + # json-py's json module has not JSONEncoder; this will raise AttributeError + # if json-py is imported instead of the built-in json module JSONEncoder = json.JSONEncoder -except ImportError: +except (ImportError, AttributeError): try: import simplejson as json JSONEncoder = json.JSONEncoder From eedef65aa6d3673b81ac6fcd6c9b05ec74a2567e Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 12:03:45 +0200 Subject: [PATCH 185/207] #487: Fix setting the default role to one provided by the ``oldcmarkup`` extension. --- CHANGES | 3 +++ sphinx/ext/oldcmarkup.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index 60c55e7a9..bc122e9c9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Release 1.0.2 (in development) ============================== +* #487: Fix setting the default role to one provided by the + ``oldcmarkup`` extension. + * #488: Fix crash when json-py is installed, which provides a ``json`` module but is incompatible to simplejson. diff --git a/sphinx/ext/oldcmarkup.py b/sphinx/ext/oldcmarkup.py index 84ae61dd2..00ac37495 100644 --- a/sphinx/ext/oldcmarkup.py +++ b/sphinx/ext/oldcmarkup.py @@ -42,6 +42,8 @@ class OldCDirective(Directive): def old_crole(typ, rawtext, text, lineno, inliner, options={}, content=[]): env = inliner.document.settings.env + if not typ: + typ = env.config.default_role if not env.app._oldcmarkup_warned: env.warn(env.docname, WARNING_MSG) env.app._oldcmarkup_warned = True From 8c91fb78ce0ac364870c3cd1df2149397f46bd8a Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 12:53:05 +0200 Subject: [PATCH 186/207] #484: Fix crash when duplicating a parameter in an info field list. Problem was that the :type: info nodes were inserted twice into the doctree, which led to inconsistencies when reference nodes were resolved. --- CHANGES | 2 ++ sphinx/util/docfields.py | 7 +++++-- tests/root/objects.txt | 2 ++ tests/test_build_html.py | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index bc122e9c9..f9b3b9a49 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ Release 1.0.2 (in development) ============================== +* #484: Fix crash when duplicating a parameter in an info field list. + * #487: Fix setting the default role to one provided by the ``oldcmarkup`` extension. diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index c8e58f48a..6ce6d82bf 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -142,9 +142,12 @@ class TypedField(GroupedField): par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong) if fieldarg in types: par += nodes.Text(' (') - fieldtype = types[fieldarg] + # NOTE: using .pop() here to prevent a single type node to be + # inserted twice into the doctree, which leads to + # inconsistencies later when references are resolved + fieldtype = types.pop(fieldarg) if len(fieldtype) == 1 and isinstance(fieldtype[0], nodes.Text): - typename = u''.join(n.astext() for n in types[fieldarg]) + typename = u''.join(n.astext() for n in fieldtype) par += self.make_xref(self.typerolename, domain, typename) else: par += fieldtype diff --git a/tests/root/objects.txt b/tests/root/objects.txt index 334827de2..d6b8bdf64 100644 --- a/tests/root/objects.txt +++ b/tests/root/objects.txt @@ -62,6 +62,8 @@ Testing object descriptions :ivar int hour: like *hour* :ivar minute: like *minute* :vartype minute: int + :param hour: Duplicate param. Should not lead to crashes. + :type hour: Duplicate type. C items diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 4dee513ae..813c962fe 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -38,7 +38,7 @@ http://www.python.org/logo.png reading included file u'wrongenc.inc' seems to be wrong, try giving an \ :encoding: option\\n? %(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png -%(root)s/objects.txt:84: WARNING: using old C markup; please migrate to \ +%(root)s/objects.txt:86: WARNING: using old C markup; please migrate to \ new-style markup \(e.g. c:function instead of cfunction\), see \ http://sphinx.pocoo.org/domains.html """ From 580e1c90d36c9d126f0a4301e0b492606b755e46 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 13:39:23 +0200 Subject: [PATCH 187/207] #481, #482: fix ``.name`` reference matching. #482: When doing a non-exact search, match only the given type of object. #481: Apply non-exact search for Python reference targets with ``.name`` for modules too. --- CHANGES | 6 +++ doc/builders.rst | 8 ++-- doc/conf.py | 6 ++- doc/config.rst | 21 +++------ doc/domains.rst | 19 +++++--- doc/ext/appapi.rst | 4 +- doc/ext/autodoc.rst | 40 +++++++++-------- doc/ext/inheritance.rst | 2 +- doc/ext/math.rst | 8 ++-- doc/markup/inline.rst | 2 +- doc/markup/toctree.rst | 2 +- doc/templating.rst | 12 ++--- sphinx/domains/python.py | 94 +++++++++++++++++++++++----------------- sphinx/domains/rst.py | 2 +- sphinx/environment.py | 2 +- 15 files changed, 124 insertions(+), 104 deletions(-) diff --git a/CHANGES b/CHANGES index f9b3b9a49..33a3cca2c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,12 @@ Release 1.0.2 (in development) ============================== +* #482: When doing a non-exact search, match only the given type + of object. + +* #481: Apply non-exact search for Python reference targets with + ``.name`` for modules too. + * #484: Fix crash when duplicating a parameter in an info field list. * #487: Fix setting the default role to one provided by the diff --git a/doc/builders.rst b/doc/builders.rst index 6e90ccc62..80203e759 100644 --- a/doc/builders.rst +++ b/doc/builders.rst @@ -255,11 +255,11 @@ All serialization builders outputs one file per source file and a few special files. They also copy the reST source files in the directory ``_sources`` under the output directory. -The :class:`PickleHTMLBuilder` is a builtin subclass that implements the pickle +The :class:`.PickleHTMLBuilder` is a builtin subclass that implements the pickle serialization interface. The files per source file have the extensions of -:attr:`~SerializingHTMLBuilder.out_suffix`, and are arranged in directories +:attr:`~.SerializingHTMLBuilder.out_suffix`, and are arranged in directories just as the source files are. They unserialize to a dictionary (or dictionary like structure) with these keys: @@ -290,7 +290,7 @@ like structure) with these keys: The special files are located in the root output directory. They are: -:attr:`SerializingHTMLBuilder.globalcontext_filename` +:attr:`.SerializingHTMLBuilder.globalcontext_filename` A pickled dict with these keys: ``project``, ``copyright``, ``release``, ``version`` @@ -309,7 +309,7 @@ The special files are located in the root output directory. They are: ``titles`` A dictionary of all documents' titles, as HTML strings. -:attr:`SerializingHTMLBuilder.searchindex_filename` +:attr:`.SerializingHTMLBuilder.searchindex_filename` An index that can be used for searching the documentation. It is a pickled list with these entries: diff --git a/doc/conf.py b/doc/conf.py index 21e8d2f54..b3a1cda79 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -8,8 +8,6 @@ import sphinx extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.autosummary', 'sphinx.ext.extlinks'] -#intersphinx_mapping = {'python': ('http://docs.python.org/dev', None)} - master_doc = 'contents' templates_path = ['_templates'] exclude_patterns = ['_build'] @@ -66,6 +64,10 @@ man_pages = [ 'template generator', '', 1), ] +# We're not using intersphinx right now, but if we did, this would be part of +# the mapping: +intersphinx_mapping = {'python': ('http://docs.python.org/dev', None)} + # -- Extension interface ------------------------------------------------------- diff --git a/doc/config.rst b/doc/config.rst index bf8ad3c2d..e0fbeb46e 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -346,12 +346,12 @@ Project information A boolean that decides whether module names are prepended to all :term:`object` names (for object types where a "module" of some kind is - defined), e.g. for :rst:dir:`function` directives. Default is ``True``. + defined), e.g. for :rst:dir:`py:function` directives. Default is ``True``. .. confval:: show_authors - A boolean that decides whether :rst:dir:`moduleauthor` and :rst:dir:`sectionauthor` - directives produce any output in the built files. + A boolean that decides whether :rst:dir:`codeauthor` and + :rst:dir:`sectionauthor` directives produce any output in the built files. .. confval:: modindex_common_prefix @@ -388,6 +388,8 @@ Options for HTML output These options influence HTML as well as HTML Help output, and other builders that use Sphinx' HTMLWriter class. +.. XXX document html_context + .. confval:: html_theme The "theme" that the HTML output should use. See the :doc:`section about @@ -553,19 +555,6 @@ that use Sphinx' HTMLWriter class. This will render the template ``customdownload.html`` as the page ``download.html``. - .. note:: - - Earlier versions of Sphinx had a value called :confval:`html_index` which - was a clumsy way of controlling the content of the "index" document. If - you used this feature, migrate it by adding an ``'index'`` key to this - setting, with your custom template as the value, and in your custom - template, use :: - - {% extend "defindex.html" %} - {% block tables %} - ... old template content ... - {% endblock %} - .. confval:: html_domain_indices If true, generate domain-specific indices in addition to the general index. diff --git a/doc/domains.rst b/doc/domains.rst index c64930a24..6bbe12150 100644 --- a/doc/domains.rst +++ b/doc/domains.rst @@ -138,11 +138,12 @@ declarations: .. rst:directive:: .. py:currentmodule:: name This directive tells Sphinx that the classes, functions etc. documented from - here are in the given module (like :rst:dir:`py:module`), but it will not create - index entries, an entry in the Global Module Index, or a link target for - :rst:role:`mod`. This is helpful in situations where documentation for things in - a module is spread over multiple files or sections -- one location has the - :rst:dir:`py:module` directive, the others only :rst:dir:`py:currentmodule`. + here are in the given module (like :rst:dir:`py:module`), but it will not + create index entries, an entry in the Global Module Index, or a link target + for :rst:role:`py:mod`. This is helpful in situations where documentation + for things in a module is spread over multiple files or sections -- one + location has the :rst:dir:`py:module` directive, the others only + :rst:dir:`py:currentmodule`. The following directives are provided for module and class contents: @@ -363,6 +364,9 @@ dot, this order is reversed. For example, in the documentation of Python's :mod:`codecs` module, ``:py:func:`open``` always refers to the built-in function, while ``:py:func:`.open``` refers to :func:`codecs.open`. +A similar heuristic is used to determine whether the name is an attribute of the +currently documented class. + Also, if the name is prefixed with a dot, and no exact match is found, the target is taken as a suffix and all object names with that suffix are searched. For example, ``:py:meth:`.TarFile.close``` references the @@ -370,8 +374,9 @@ searched. For example, ``:py:meth:`.TarFile.close``` references the ``tarfile``. Since this can get ambiguous, if there is more than one possible match, you will get a warning from Sphinx. -A similar heuristic is used to determine whether the name is an attribute of the -currently documented class. +Note that you can combine the ``~`` and ``.`` prefixes: +``:py:meth:`~.TarFile.close``` will reference the ``tarfile.TarFile.close()`` +method, but the visible link caption will only be ``close()``. .. _c-domain: diff --git a/doc/ext/appapi.rst b/doc/ext/appapi.rst index 402dd72f0..2717c6a8e 100644 --- a/doc/ext/appapi.rst +++ b/doc/ext/appapi.rst @@ -210,7 +210,7 @@ the following public API: standard Sphinx roles (see :ref:`xref-syntax`). This method is also available under the deprecated alias - :meth:`add_description_unit`. + ``add_description_unit``. .. method:: Sphinx.add_crossref_type(directivename, rolename, indextemplate='', ref_nodeclass=None, objname='') @@ -272,6 +272,8 @@ the following public API: This allows to auto-document new types of objects. See the source of the autodoc module for examples on how to subclass :class:`Documenter`. + .. XXX add real docs for Documenter and subclassing + .. versionadded:: 0.6 .. method:: Sphinx.add_autodoc_attrgetter(type, getter) diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst index bd725cfaa..813331015 100644 --- a/doc/ext/autodoc.rst +++ b/doc/ext/autodoc.rst @@ -27,20 +27,21 @@ two locations for documentation, while at the same time avoiding auto-generated-looking pure API documentation. :mod:`autodoc` provides several directives that are versions of the usual -:rst:dir:`module`, :rst:dir:`class` and so forth. On parsing time, they import the -corresponding module and extract the docstring of the given objects, inserting -them into the page source under a suitable :rst:dir:`module`, :rst:dir:`class` etc. -directive. +:rst:dir:`py:module`, :rst:dir:`py:class` and so forth. On parsing time, they +import the corresponding module and extract the docstring of the given objects, +inserting them into the page source under a suitable :rst:dir:`py:module`, +:rst:dir:`py:class` etc. directive. .. note:: - Just as :rst:dir:`class` respects the current :rst:dir:`module`, :rst:dir:`autoclass` - will also do so, and likewise with :rst:dir:`method` and :rst:dir:`class`. + Just as :rst:dir:`py:class` respects the current :rst:dir:`py:module`, + :rst:dir:`autoclass` will also do so. Likewise, :rst:dir:`automethod` will + respect the current :rst:dir:`py:class`. .. rst:directive:: automodule - autoclass - autoexception + autoclass + autoexception Document a module, class or exception. All three directives will by default only insert the docstring of the object itself:: @@ -127,23 +128,24 @@ directive. .. versionadded:: 0.4 - * The :rst:dir:`automodule`, :rst:dir:`autoclass` and :rst:dir:`autoexception` directives - also support a flag option called ``show-inheritance``. When given, a list - of base classes will be inserted just below the class signature (when used - with :rst:dir:`automodule`, this will be inserted for every class that is - documented in the module). + * The :rst:dir:`automodule`, :rst:dir:`autoclass` and + :rst:dir:`autoexception` directives also support a flag option called + ``show-inheritance``. When given, a list of base classes will be inserted + just below the class signature (when used with :rst:dir:`automodule`, this + will be inserted for every class that is documented in the module). .. versionadded:: 0.4 * All autodoc directives support the ``noindex`` flag option that has the - same effect as for standard :rst:dir:`function` etc. directives: no index - entries are generated for the documented object (and all autodocumented - members). + same effect as for standard :rst:dir:`py:function` etc. directives: no + index entries are generated for the documented object (and all + autodocumented members). .. versionadded:: 0.4 * :rst:dir:`automodule` also recognizes the ``synopsis``, ``platform`` and - ``deprecated`` options that the standard :rst:dir:`module` directive supports. + ``deprecated`` options that the standard :rst:dir:`py:module` directive + supports. .. versionadded:: 0.5 @@ -213,8 +215,8 @@ There are also new config values that you can set: ``"class"`` Only the class' docstring is inserted. This is the default. You can - still document ``__init__`` as a separate method using :rst:dir:`automethod` - or the ``members`` option to :rst:dir:`autoclass`. + still document ``__init__`` as a separate method using + :rst:dir:`automethod` or the ``members`` option to :rst:dir:`autoclass`. ``"both"`` Both the class' and the ``__init__`` method's docstring are concatenated and inserted. diff --git a/doc/ext/inheritance.rst b/doc/ext/inheritance.rst index 76388a94c..cdd017917 100644 --- a/doc/ext/inheritance.rst +++ b/doc/ext/inheritance.rst @@ -17,7 +17,7 @@ It adds this directive: This directive has one or more arguments, each giving a module or class name. Class names can be unqualified; in that case they are taken to exist - in the currently described module (see :rst:dir:`module`). + in the currently described module (see :rst:dir:`py:module`). For each given class, and each class in each given module, the base classes are determined. Then, from all classes and their base classes, a graph is diff --git a/doc/ext/math.rst b/doc/ext/math.rst index b9f6ab12b..f2896c39c 100644 --- a/doc/ext/math.rst +++ b/doc/ext/math.rst @@ -17,15 +17,15 @@ if possible, reuse that support too. .. note:: - :mod:`sphinx.ext.mathbase` is not meant to be added to the - :confval:`extensions` config value, instead, use either - :mod:`sphinx.ext.pngmath` or :mod:`sphinx.ext.jsmath` as described below. + :mod:`.mathbase` is not meant to be added to the :confval:`extensions` config + value, instead, use either :mod:`sphinx.ext.pngmath` or + :mod:`sphinx.ext.jsmath` as described below. The input language for mathematics is LaTeX markup. This is the de-facto standard for plain-text math notation and has the added advantage that no further translation is necessary when building LaTeX output. -:mod:`mathbase` defines these new markup elements: +:mod:`.mathbase` defines these new markup elements: .. rst:role:: math diff --git a/doc/markup/inline.rst b/doc/markup/inline.rst index bb1ed68ec..4453ab00a 100644 --- a/doc/markup/inline.rst +++ b/doc/markup/inline.rst @@ -260,7 +260,7 @@ in a different style: .. rst:role:: samp A piece of literal text, such as code. Within the contents, you can use - curly braces to indicate a "variable" part, as in :rst:dir:`file`. For + curly braces to indicate a "variable" part, as in :rst:role:`file`. For example, in ``:samp:`print 1+{variable}```, the part ``variable`` would be emphasized. diff --git a/doc/markup/toctree.rst b/doc/markup/toctree.rst index 474427d72..2c0a418a2 100644 --- a/doc/markup/toctree.rst +++ b/doc/markup/toctree.rst @@ -151,7 +151,7 @@ The special document names (and pages generated for them) are: :ref:`object descriptions `, and from :rst:dir:`index` directives. - The module index contains one entry per :rst:dir:`module` directive. + The Python module index contains one entry per :rst:dir:`py:module` directive. The search page contains a form that uses the generated JSON search index and JavaScript to full-text search the generated documents for search words; it diff --git a/doc/templating.rst b/doc/templating.rst index 6880663d3..193a90bd9 100644 --- a/doc/templating.rst +++ b/doc/templating.rst @@ -21,10 +21,10 @@ No. You have several other options: configuration value accordingly. * You can :ref:`write a custom builder ` that derives from - :class:`~sphinx.builders.StandaloneHTMLBuilder` and calls your template engine - of choice. + :class:`~sphinx.builders.html.StandaloneHTMLBuilder` and calls your template + engine of choice. -* You can use the :class:`~sphinx.builders.PickleHTMLBuilder` that produces +* You can use the :class:`~sphinx.builders.html.PickleHTMLBuilder` that produces pickle files with the page contents, and postprocess them using a custom tool, or use them in your Web application. @@ -261,9 +261,9 @@ in the future. .. data:: file_suffix - The value of the builder's :attr:`out_suffix` attribute, i.e. the file name - extension that the output files will get. For a standard HTML builder, this - is usually ``.html``. + The value of the builder's :attr:`~.SerializingHTMLBuilder.out_suffix` + attribute, i.e. the file name extension that the output files will get. For + a standard HTML builder, this is usually ``.html``. .. data:: has_source diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index fc8086995..cd87bfbda 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -356,6 +356,9 @@ class PyModule(Directive): env.domaindata['py']['modules'][modname] = \ (env.docname, self.options.get('synopsis', ''), self.options.get('platform', ''), 'deprecated' in self.options) + # make a duplicate entry in 'objects' to facilitate searching for the + # module in PythonDomain.find_obj() + env.domaindata['py']['objects'][modname] = (env.docname, 'module') targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True) self.state.document.note_explicit_target(targetnode) ret = [targetnode] @@ -544,7 +547,7 @@ class PythonDomain(Domain): if fn == docname: del self.data['modules'][modname] - def find_obj(self, env, modname, classname, name, type, searchorder=0): + def find_obj(self, env, modname, classname, name, type, searchmode=0): """ Find a Python object for "name", perhaps using the given module and/or classname. Returns a list of (name, object entry) tuples. @@ -560,22 +563,31 @@ class PythonDomain(Domain): matches = [] newname = None - if searchorder == 1: - if modname and classname and \ - modname + '.' + classname + '.' + name in objects: - newname = modname + '.' + classname + '.' + name - elif modname and modname + '.' + name in objects: - newname = modname + '.' + name - elif name in objects: - newname = name - else: - # "fuzzy" searching mode - searchname = '.' + name - matches = [(name, objects[name]) for name in objects - if name.endswith(searchname)] + if searchmode == 1: + objtypes = self.objtypes_for_role(type) + if modname and classname: + fullname = modname + '.' + classname + '.' + name + if fullname in objects and objects[fullname][1] in objtypes: + newname = fullname + if not newname: + if modname and modname + '.' + name in objects and \ + objects[modname + '.' + name][1] in objtypes: + newname = modname + '.' + name + elif name in objects and objects[name][1] in objtypes: + newname = name + else: + # "fuzzy" searching mode + searchname = '.' + name + matches = [(name, objects[name]) for name in objects + if name.endswith(searchname) + and objects[name][1] in objtypes] else: + # NOTE: searching for exact match, object type is not considered if name in objects: newname = name + elif type == 'mod': + # only exact matches allowed for modules + return [] elif classname and classname + '.' + name in objects: newname = classname + '.' + name elif modname and modname + '.' + name in objects: @@ -597,33 +609,35 @@ class PythonDomain(Domain): def resolve_xref(self, env, fromdocname, builder, type, target, node, contnode): - if (type == 'mod' or - type == 'obj' and target in self.data['modules']): - docname, synopsis, platform, deprecated = \ - self.data['modules'].get(target, ('','','', '')) - if not docname: - return None - else: - title = '%s%s%s' % ((platform and '(%s) ' % platform), - synopsis, - (deprecated and ' (deprecated)' or '')) - return make_refnode(builder, fromdocname, docname, - 'module-' + target, contnode, title) + modname = node.get('py:module') + clsname = node.get('py:class') + searchmode = node.hasattr('refspecific') and 1 or 0 + matches = self.find_obj(env, modname, clsname, target, + type, searchmode) + if not matches: + return None + elif len(matches) > 1: + env.warn(fromdocname, + 'more than one target found for cross-reference ' + '%r: %s' % (target, + ', '.join(match[0] for match in matches)), + node.line) + name, obj = matches[0] + + if obj[1] == 'module': + # get additional info for modules + docname, synopsis, platform, deprecated = self.data['modules'][name] + assert docname == obj[0] + title = name + if synopsis: + title += ': ' + synopsis + if deprecated: + title += _(' (deprecated)') + if platform: + title += ' (' + platform + ')' + return make_refnode(builder, fromdocname, docname, + 'module-' + name, contnode, title) else: - modname = node.get('py:module') - clsname = node.get('py:class') - searchorder = node.hasattr('refspecific') and 1 or 0 - matches = self.find_obj(env, modname, clsname, target, - type, searchorder) - if not matches: - return None - elif len(matches) > 1: - env.warn(fromdocname, - 'more than one target found for cross-reference ' - '%r: %s' % (target, - ', '.join(match[0] for match in matches)), - node.line) - name, obj = matches[0] return make_refnode(builder, fromdocname, obj[0], name, contnode, name) diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py index 61809f330..98f40d845 100644 --- a/sphinx/domains/rst.py +++ b/sphinx/domains/rst.py @@ -28,7 +28,7 @@ class ReSTMarkup(ObjectDescription): """ def add_target_and_index(self, name, sig, signode): - targetname = name + '-' + self.objtype + targetname = self.objtype + '-' + name if targetname not in self.state.document.ids: signode['names'].append(targetname) signode['ids'].append(targetname) diff --git a/sphinx/environment.py b/sphinx/environment.py index 5edcb4d90..19ff62ca1 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -63,7 +63,7 @@ default_settings = { # This is increased every time an environment attribute is added # or changed to properly invalidate pickle files. -ENV_VERSION = 37 +ENV_VERSION = 38 default_substitutions = set([ From 0d8dd33b4d752277c8f9632b726c517ff167ef07 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 15:07:44 +0200 Subject: [PATCH 188/207] #471: Fix LaTeX references to figures. --- CHANGES | 2 ++ sphinx/writers/latex.py | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 33a3cca2c..41f0b1c4d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ Release 1.0.2 (in development) ============================== +* #471: Fix LaTeX references to figures. + * #482: When doing a non-exact search, match only the given type of object. diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 5674b388c..03c90fe27 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -224,6 +224,7 @@ class LaTeXTranslator(nodes.NodeVisitor): else: self.top_sectionlevel = 1 self.next_section_ids = set() + self.next_figure_ids = set() # flags self.verbatim = None self.in_title = 0 @@ -887,11 +888,15 @@ class LaTeXTranslator(nodes.NodeVisitor): pass def visit_figure(self, node): + ids = '' + for id in self.next_figure_ids: + ids += self.hypertarget(id, anchor=False) + self.next_figure_ids.clear() if node.has_key('width') and node.get('align', '') in ('left', 'right'): self.body.append('\\begin{wrapfigure}{%s}{%s}\n\\centering' % (node['align'] == 'right' and 'r' or 'l', node['width'])) - self.context.append('\\end{wrapfigure}\n') + self.context.append(ids + '\\end{wrapfigure}\n') else: if (not node.attributes.has_key('align') or node.attributes['align'] == 'center'): @@ -903,7 +908,7 @@ class LaTeXTranslator(nodes.NodeVisitor): align = '\\begin{flush%s}' % node.attributes['align'] align_end = '\\end{flush%s}' % node.attributes['align'] self.body.append('\\begin{figure}[htbp]%s\n' % align) - self.context.append('%s\\end{figure}\n' % align_end) + self.context.append(ids + align_end + '\\end{figure}\n') def depart_figure(self, node): self.body.append(self.context.pop()) @@ -983,6 +988,11 @@ class LaTeXTranslator(nodes.NodeVisitor): self.next_section_ids.add(node['refid']) self.next_section_ids.update(node['ids']) return + elif isinstance(next, nodes.figure): + if node.get('refid'): + self.next_figure_ids.add(node['refid']) + self.next_figure_ids.update(node['ids']) + return except IndexError: pass if 'refuri' in node: From f3c2220ad1007a3a57db868206968b98dcb5abce Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 15:16:48 +0200 Subject: [PATCH 189/207] Include hypcap package, to get better references to floats. --- sphinx/texinputs/sphinx.sty | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index be8a6c15d..b5381392a 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -446,6 +446,7 @@ linkcolor=InnerLinkColor,filecolor=OuterLinkColor, menucolor=OuterLinkColor,urlcolor=OuterLinkColor, citecolor=InnerLinkColor]{hyperref} +\RequirePackage[figure,table]{hypcap} % From docutils.writers.latex2e \providecommand{\DUspan}[2]{% From 5b2b0ecfd3dda77ad3a110286eea24fd484b42dc Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 15:17:12 +0200 Subject: [PATCH 190/207] Better references to tables, as well. --- sphinx/writers/latex.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 03c90fe27..1bb534a0b 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -225,6 +225,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.top_sectionlevel = 1 self.next_section_ids = set() self.next_figure_ids = set() + self.next_table_ids = set() # flags self.verbatim = None self.in_title = 0 @@ -634,7 +635,10 @@ class LaTeXTranslator(nodes.NodeVisitor): self.body.append('{|' + ('L|' * self.table.colcount) + '}\n') if self.table.longtable and self.table.caption is not None: self.body.append(u'\\caption{%s} \\\\\n' % self.table.caption) - + if self.table.caption is not None: + for id in self.next_table_ids: + self.body.append(self.hypertarget(id, anchor=False)) + self.next_table_ids.clear() if self.table.longtable: self.body.append('\\hline\n') self.body.append('\\endfirsthead\n\n') @@ -989,10 +993,19 @@ class LaTeXTranslator(nodes.NodeVisitor): self.next_section_ids.update(node['ids']) return elif isinstance(next, nodes.figure): + # labels for figures go in the figure body, not before if node.get('refid'): self.next_figure_ids.add(node['refid']) self.next_figure_ids.update(node['ids']) return + elif isinstance(next, nodes.table): + # same for tables, but only if they have a caption + for n in node: + if isinstance(n, nodes.title): + if node.get('refid'): + self.next_table_ids.add(node['refid']) + self.next_table_ids.update(node['ids']) + return except IndexError: pass if 'refuri' in node: From b9529a21a5c9252c7298836467034b0f2c3e9d07 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 15:17:23 +0200 Subject: [PATCH 191/207] Fix references to reST domain items. --- sphinx/domains/rst.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py index 98f40d845..d3ffc6bdc 100644 --- a/sphinx/domains/rst.py +++ b/sphinx/domains/rst.py @@ -130,8 +130,9 @@ class ReSTDomain(Domain): if (objtype, target) in objects: return make_refnode(builder, fromdocname, objects[objtype, target], - target, contnode, target) + objtype + '-' + target, + contnode, target + ' ' + objtype) def get_objects(self): for (typ, name), docname in self.data['objects'].iteritems(): - yield name, name, typ, docname, name, 1 + yield name, name, typ, docname, typ + '-' + name, 1 From 279d025ffe93a05ac3be7b1432409d77e9bbb7a0 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 15:29:45 +0200 Subject: [PATCH 192/207] Add Tau. --- EXAMPLES | 1 + 1 file changed, 1 insertion(+) diff --git a/EXAMPLES b/EXAMPLES index 44c511e9e..778b235e1 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -97,6 +97,7 @@ Documentation using the sphinxdoc theme * Satchmo: http://www.satchmoproject.com/docs/svn/ * Sphinx: http://sphinx.pocoo.org/ * Sqlkit: http://sqlkit.argolinux.org/ +* Tau: http://www.tango-controls.org/static/tau/latest/doc/html/index.html * Total Open Station: http://tops.berlios.de/ * WebFaction: http://docs.webfaction.com/ From 92142bbdb68e98515112c34ec70ca18fd6f3ea6e Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 15:42:15 +0200 Subject: [PATCH 193/207] Allow references to PEPs and RFCs with explicit anchors. --- CHANGES | 2 ++ doc/markup/inline.rst | 6 ++++-- sphinx/roles.py | 14 ++++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 41f0b1c4d..ad51ffeff 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ Release 1.0.2 (in development) ============================== +* Allow references to PEPs and RFCs with explicit anchors. + * #471: Fix LaTeX references to figures. * #482: When doing a non-exact search, match only the given type diff --git a/doc/markup/inline.rst b/doc/markup/inline.rst index 4453ab00a..4b704228f 100644 --- a/doc/markup/inline.rst +++ b/doc/markup/inline.rst @@ -274,13 +274,15 @@ The following roles generate external links: A reference to a Python Enhancement Proposal. This generates appropriate index entries. The text "PEP *number*\ " is generated; in the HTML output, - this text is a hyperlink to an online copy of the specified PEP. + this text is a hyperlink to an online copy of the specified PEP. You can + link to a specific section by saying ``:pep:`number#anchor```. .. rst:role:: rfc A reference to an Internet Request for Comments. This generates appropriate index entries. The text "RFC *number*\ " is generated; in the HTML output, - this text is a hyperlink to an online copy of the specified RFC. + this text is a hyperlink to an online copy of the specified RFC. You can + link to a specific section by saying ``:rfc:`number#anchor```. Note that there are no special roles for including hyperlinks as you can use diff --git a/sphinx/roles.py b/sphinx/roles.py index bacdad5b6..0ea0ec485 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -173,6 +173,10 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner, indexnode['entries'] = [ ('single', _('Python Enhancement Proposals!PEP %s') % text, targetid, 'PEP %s' % text)] + anchor = '' + anchorindex = text.find('#') + if anchorindex > 0: + text, anchor = text[:anchorindex], text[anchorindex:] try: pepnum = int(text) except ValueError: @@ -182,12 +186,17 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner, return [prb], [msg] ref = inliner.document.settings.pep_base_url + 'pep-%04d' % pepnum sn = nodes.strong('PEP '+text, 'PEP '+text) - rn = nodes.reference('', '', internal=False, refuri=ref, classes=[typ]) + rn = nodes.reference('', '', internal=False, refuri=ref+anchor, + classes=[typ]) rn += sn return [indexnode, targetnode, rn], [] elif typ == 'rfc': indexnode['entries'] = [('single', 'RFC; RFC %s' % text, targetid, 'RFC %s' % text)] + anchor = '' + anchorindex = text.find('#') + if anchorindex > 0: + text, anchor = text[:anchorindex], text[anchorindex:] try: rfcnum = int(text) except ValueError: @@ -197,7 +206,8 @@ def indexmarkup_role(typ, rawtext, etext, lineno, inliner, return [prb], [msg] ref = inliner.document.settings.rfc_base_url + inliner.rfc_url % rfcnum sn = nodes.strong('RFC '+text, 'RFC '+text) - rn = nodes.reference('', '', internal=False, refuri=ref, classes=[typ]) + rn = nodes.reference('', '', internal=False, refuri=ref+anchor, + classes=[typ]) rn += sn return [indexnode, targetnode, rn], [] From 5b09e2b41a2c40522f2c6dc4063526ea3a4fc594 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 15:47:10 +0200 Subject: [PATCH 194/207] Fix unwanted styling of C domain references (because of a namespace clash with Pygments styles). --- CHANGES | 3 +++ sphinx/highlighting.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index ad51ffeff..0e06938df 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Release 1.0.2 (in development) ============================== +* Fix unwanted styling of C domain references (because of a + namespace clash with Pygments styles). + * Allow references to PEPs and RFCs with explicit anchors. * #471: Fix LaTeX references to figures. diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py index f5ea859cb..0dcbc0219 100644 --- a/sphinx/highlighting.py +++ b/sphinx/highlighting.py @@ -240,7 +240,7 @@ class PygmentsBridge(object): # no HTML styles needed return '' if self.dest == 'html': - return self.fmter[0].get_style_defs() + return self.fmter[0].get_style_defs('.highlight') else: styledefs = self.fmter[0].get_style_defs() # workaround for Pygments < 0.12 From df107e70f8f684c7fd4475f596ffbc3151478f41 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 16:03:36 +0200 Subject: [PATCH 195/207] Allow breaking long signatures, continuing with backlash-escaped newlines. --- CHANGES | 7 +++++-- doc/domains.rst | 11 ++++++++++- sphinx/directives/__init__.py | 7 +++++-- tests/root/objects.txt | 4 ++++ tests/test_build_html.py | 4 +++- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 0e06938df..a158267b0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,11 @@ Release 1.0.2 (in development) ============================== -* Fix unwanted styling of C domain references (because of a - namespace clash with Pygments styles). +* Allow breaking long signatures, continuing with backlash-escaped + newlines. + +* Fix unwanted styling of C domain references (because of a namespace + clash with Pygments styles). * Allow references to PEPs and RFCs with explicit anchors. diff --git a/doc/domains.rst b/doc/domains.rst index 6bbe12150..8cd7a0c7d 100644 --- a/doc/domains.rst +++ b/doc/domains.rst @@ -52,10 +52,19 @@ flag ``:noindex:``. An example using a Python domain directive:: .. py:function:: spam(eggs) ham(eggs) - :noindex: Spam or ham the foo. +This describes the two Python functions ``spam`` and ``ham``. (Note that when +signatures become too long, you can break them if you add a backslash to lines +that are continued in the next line. Example:: + + .. py:function:: filterwarnings(action, message='', category=Warning, \ + module='', lineno=0, append=False) + :noindex: + +(This example also shows how to use the ``:noindex:`` flag.) + The domains also provide roles that link back to these object descriptions. For example, to link to one of the functions described in the example above, you could say :: diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py index 6c03b8e5f..48c44178d 100644 --- a/sphinx/directives/__init__.py +++ b/sphinx/directives/__init__.py @@ -32,6 +32,7 @@ except AttributeError: # RE to strip backslash escapes +nl_escape_re = re.compile(r'\\\n') strip_backslash_re = re.compile(r'\\(?=[^\\])') @@ -57,10 +58,12 @@ class ObjectDescription(Directive): """ Retrieve the signatures to document from the directive arguments. By default, signatures are given as arguments, one per line. + + Backslash-escaping of newlines is supported. """ + lines = nl_escape_re.sub('', self.arguments[0]).split('\n') # remove backslashes to support (dummy) escapes; helps Vim highlighting - return [strip_backslash_re.sub('', sig.strip()) - for sig in self.arguments[0].split('\n')] + return [strip_backslash_re.sub('', line.strip()) for line in lines] def handle_signature(self, sig, signode): """ diff --git a/tests/root/objects.txt b/tests/root/objects.txt index d6b8bdf64..e62f6d962 100644 --- a/tests/root/objects.txt +++ b/tests/root/objects.txt @@ -41,6 +41,10 @@ Testing object descriptions .. function:: func_without_module2() -> annotation +.. object:: long(parameter, \ + list) + another one + .. class:: TimeInt :param moo: |test| diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 813c962fe..6857d3309 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -38,7 +38,7 @@ http://www.python.org/logo.png reading included file u'wrongenc.inc' seems to be wrong, try giving an \ :encoding: option\\n? %(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png -%(root)s/objects.txt:86: WARNING: using old C markup; please migrate to \ +%(root)s/objects.txt:\\d*: WARNING: using old C markup; please migrate to \ new-style markup \(e.g. c:function instead of cfunction\), see \ http://sphinx.pocoo.org/domains.html """ @@ -161,6 +161,8 @@ HTML_XPATH = { 'objects.html': [ (".//dt[@id='mod.Cls.meth1']", ''), (".//dt[@id='errmod.Error']", ''), + (".//dt/tt", r'long\(parameter,\s* list\)'), + (".//dt/tt", 'another one'), (".//a[@href='#mod.Cls'][@class='reference internal']", ''), (".//dl[@class='userdesc']", ''), (".//dt[@id='userdesc-myobj']", ''), From 7518d194376994f4efa3234a12a0435b62dd4df0 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 18:59:04 +0200 Subject: [PATCH 196/207] #469: document __all__ ordering in members. --- doc/ext/autodoc.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst index 813331015..a1d9d98fb 100644 --- a/doc/ext/autodoc.rst +++ b/doc/ext/autodoc.rst @@ -84,6 +84,9 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, will document all non-private member functions and properties (that is, those whose name doesn't start with ``_``). + For modules, ``__all__`` will be respected when looking for members; the + order of the members will also be the order in ``__all__``. + You can also give an explicit list of members; only these will then be documented:: From 0ed09e9c5314290db52de09fe59a688ed3c44009 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 5 Aug 2010 22:35:12 +0200 Subject: [PATCH 197/207] #258: get a bit smarter about closing double quotes. --- sphinx/util/smartypants.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinx/util/smartypants.py b/sphinx/util/smartypants.py index 75888ea4d..f83f5689b 100644 --- a/sphinx/util/smartypants.py +++ b/sphinx/util/smartypants.py @@ -83,6 +83,7 @@ def sphinx_smarty_pants(t): # Constants for quote education. punct_class = r"""[!"#\$\%'()*+,-.\/:;<=>?\@\[\\\]\^_`{|}~]""" +end_of_word_class = r"""[\s.,;:!?)]""" close_class = r"""[^\ \t\r\n\[\{\(\-]""" dec_dashes = r"""–|—""" @@ -117,8 +118,8 @@ opening_double_quotes_regex = re.compile(r""" closing_double_quotes_regex = re.compile(r""" #(%s)? # character that indicates the quote should be closing " - (?=\s) - """ % (close_class,), re.VERBOSE) + (?=%s) + """ % (close_class, end_of_word_class), re.VERBOSE) closing_double_quotes_regex_2 = re.compile(r""" (%s) # character that indicates the quote should be closing From e227abe1df51d701e00d3f55c08c954a3b342e5b Mon Sep 17 00:00:00 2001 From: Ali Afshar Date: Fri, 6 Aug 2010 11:35:48 +0100 Subject: [PATCH 198/207] Make the dot command part of the caching system for dot output generation --- sphinx/ext/graphviz.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py index 106de7a65..257ff1b63 100644 --- a/sphinx/ext/graphviz.py +++ b/sphinx/ext/graphviz.py @@ -93,6 +93,7 @@ def render_dot(self, code, options, format, prefix='graphviz'): Render graphviz code into a PNG or PDF output file. """ hashkey = code.encode('utf-8') + str(options) + \ + str(self.builder.config.graphviz_dot) + \ str(self.builder.config.graphviz_dot_args) fname = '%s-%s.%s' % (prefix, sha(hashkey).hexdigest(), format) if hasattr(self.builder, 'imgpath'): From bd950c3bb4c687142559def3345fe36b84dd86cd Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 10 Aug 2010 17:16:49 +0200 Subject: [PATCH 199/207] Fix test_config under 2.x. --- tests/test_config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_config.py b/tests/test_config.py index 7fce4495b..b5f88a6f5 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -89,7 +89,8 @@ def test_errors_warnings(dir): raises_msg(ConfigError, 'conf.py', Config, dir, 'conf.py', {}, None) # test the automatic conversion of 2.x only code in configs - write_file(dir / 'conf.py', u'\n\nproject = u"Jägermeister"\n', 'utf-8') + write_file(dir / 'conf.py', u'# -*- coding: utf-8\n\n' + u'project = u"Jägermeister"\n', 'utf-8') cfg = Config(dir, 'conf.py', {}, None) cfg.init_values() assert cfg.project == u'Jägermeister' From 8a17f7a84fdb2bc62a64068875dac65faf223572 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 10 Aug 2010 17:18:46 +0200 Subject: [PATCH 200/207] Prepare for 1.0.2. --- CHANGES | 4 ++-- sphinx/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index a158267b0..da9a80d75 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -Release 1.0.2 (in development) -============================== +Release 1.0.2 (Aug 05, 2010) +============================ * Allow breaking long signatures, continuing with backlash-escaped newlines. diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 50aa28cd6..c193d095c 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -12,8 +12,8 @@ import sys from os import path -__version__ = '1.0.1+' -__released__ = '1.0.1' # used when Sphinx builds its own docs +__version__ = '1.0.2' +__released__ = '1.0.2' # used when Sphinx builds its own docs package_dir = path.abspath(path.dirname(__file__)) From e1ce9a63a664712ceeeda651e4dc039cd9f9eaa8 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Wed, 11 Aug 2010 17:16:20 +0200 Subject: [PATCH 201/207] Fix file name in manifest. --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 5e3104a82..cfc44c17e 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,7 +7,7 @@ include TODO include babel.cfg include Makefile -include setup_distribute.py +include distribute_setup.py include sphinx-autogen.py include sphinx-build.py include sphinx-quickstart.py From a484c6f793e4dc352b98d0202b6d3154664eac2c Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 14 Aug 2010 16:51:04 +0200 Subject: [PATCH 202/207] #490: Fix cross-references to objects of types added by the :func:`~.Sphinx.add_object_type` API function. --- CHANGES | 3 +++ sphinx/domains/std.py | 8 +++++++- tests/test_build_html.py | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index da9a80d75..bd368e17c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Release 1.0.2 (Aug 05, 2010) ============================ +* #490: Fix cross-references to objects of types added by the + :func:`~.Sphinx.add_object_type` API function. + * Allow breaking long signatures, continuing with backlash-escaped newlines. diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index 63a3bf6dc..6194ace9a 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -484,7 +484,13 @@ class StandardDomain(Domain): return make_refnode(builder, fromdocname, docname, labelid, contnode) else: - docname, labelid = self.data['objects'].get((typ, target), ('', '')) + objtypes = self.objtypes_for_role(typ) or [] + for objtype in objtypes: + if (objtype, target) in self.data['objects']: + docname, labelid = self.data['objects'][objtype, target] + break + else: + docname, labelid = '', '' if not docname: if typ == 'term': env.warn(node.get('refdoc', fromdocname), diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 6857d3309..912a0b426 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -166,7 +166,7 @@ HTML_XPATH = { (".//a[@href='#mod.Cls'][@class='reference internal']", ''), (".//dl[@class='userdesc']", ''), (".//dt[@id='userdesc-myobj']", ''), - (".//a[@href='#userdesc-myobj']", ''), + (".//a[@href='#userdesc-myobj'][@class='reference internal']", ''), # C references (".//span[@class='pre']", 'CFunction()'), (".//a[@href='#Sphinx_DoSomething']", ''), From 572e6019817685b811c637deb0be9293732536ab Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 14 Aug 2010 17:04:25 +0200 Subject: [PATCH 203/207] Fix handling of doc field types for different directive types. --- CHANGES | 2 ++ sphinx/directives/__init__.py | 1 - sphinx/util/docfields.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index bd368e17c..89f33dd27 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,8 @@ Release 1.0.2 (Aug 05, 2010) * #490: Fix cross-references to objects of types added by the :func:`~.Sphinx.add_object_type` API function. +* Fix handling of doc field types for different directive types. + * Allow breaking long signatures, continuing with backlash-escaped newlines. diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py index 48c44178d..b7adbcafd 100644 --- a/sphinx/directives/__init__.py +++ b/sphinx/directives/__init__.py @@ -162,7 +162,6 @@ class ObjectDescription(Directive): self.env.temp_data['object'] = self.names[0] self.before_content() self.state.nested_parse(self.content, self.content_offset, contentnode) - #self.handle_doc_fields(contentnode) DocFieldTransformer(self).transform_all(contentnode) self.env.temp_data['object'] = None self.after_content() diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index 6ce6d82bf..89f81e8cb 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -167,7 +167,7 @@ class DocFieldTransformer(object): def __init__(self, directive): self.domain = directive.domain - if not hasattr(directive, '_doc_field_type_map'): + if '_doc_field_type_map' not in directive.__class__.__dict__: directive.__class__._doc_field_type_map = \ self.preprocess_fieldtypes(directive.__class__.doc_field_types) self.typemap = directive._doc_field_type_map From d1cc9be1d00bfe88887aeec74ec34f81edefb9fa Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 14 Aug 2010 17:09:23 +0200 Subject: [PATCH 204/207] Update release date. --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 89f33dd27..a640ea60b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -Release 1.0.2 (Aug 05, 2010) +Release 1.0.2 (Aug 14, 2010) ============================ * #490: Fix cross-references to objects of types added by the From fae5b3c1339ef08fac98ca3ed0a52350350acd70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 14 Aug 2010 19:52:04 +0200 Subject: [PATCH 206/207] Fix doctest to work with Python 2.5 and lower --- tests/root/doctest.txt | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/tests/root/doctest.txt b/tests/root/doctest.txt index 6ac0b2863..ba9a72c52 100644 --- a/tests/root/doctest.txt +++ b/tests/root/doctest.txt @@ -50,23 +50,24 @@ Special directives .. testsetup:: * - from math import factorial + def squared(x): + return x * x .. doctest:: - >>> factorial(1) - 1 + >>> squared(2) + 4 .. testcode:: - print(factorial(1)) + print(squared(2)) .. testoutput:: - 1 + 4 - >>> factorial(1) - 1 + >>> squared(2) + 4 * options for testcode/testoutput blocks @@ -85,36 +86,38 @@ Special directives .. testsetup:: group1 - from math import trunc + def add(x, y): + return x + y - ``trunc`` is now known in "group1", but not in others. + + ``add`` is now known in "group1", but not in others. .. doctest:: group1 - >>> trunc(1.1) - 1 + >>> add(1, 1) + 2 .. doctest:: group2 - >>> trunc(1.1) + >>> add(1, 1) Traceback (most recent call last): ... - NameError: name 'trunc' is not defined + NameError: name 'add' is not defined Interleaving testcode/testoutput: .. testcode:: group1 - print(factorial(3)) + print(squared(3)) .. testcode:: group2 - print(factorial(4)) + print(squared(4)) .. testoutput:: group1 - 6 + 9 .. testoutput:: group2 - 24 + 16 From 860fc27177370cc55d990584f45d39b3583ca378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Neuh=C3=A4user?= Date: Sat, 14 Aug 2010 19:48:42 +0200 Subject: [PATCH 207/207] shutil.copytree doesn't have an ignore argument in Python 2.4 --- tests/path.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/path.py b/tests/path.py index df96bce45..8e9afeaa8 100644 --- a/tests/path.py +++ b/tests/path.py @@ -88,7 +88,7 @@ class path(str): """ shutil.rmtree(self, ignore_errors=ignore_errors, onerror=onerror) - def copytree(self, destination, symlinks=False, ignore=None): + def copytree(self, destination, symlinks=False): """ Recursively copy a directory to the given `destination`. If the given `destination` does not exist it will be created. @@ -97,12 +97,8 @@ class path(str): If ``True`` symbolic links in the source tree result in symbolic links in the destination tree otherwise the contents of the files pointed to by the symbolic links are copied. - - :param ignore: - A callback which gets called with the path of the directory being - copied and a list of paths as returned by :func:`os.listdir`. """ - shutil.copytree(self, destination, symlinks=symlinks, ignore=ignore) + shutil.copytree(self, destination, symlinks=symlinks) def movetree(self, destination): """