mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '1.7' into 4817_fix_URLs
This commit is contained in:
commit
ca8e79a392
3
CHANGES
3
CHANGES
@ -20,6 +20,9 @@ Bugs fixed
|
||||
* #4790: autosummary: too wide two column tables in PDF builds
|
||||
* #4795: Latex customization via ``_templates/longtable.tex_t`` is broken
|
||||
* #4789: imgconverter: confused by convert.exe of Windows
|
||||
* #4783: On windows, Sphinx crashed when drives of srcdir and outdir are
|
||||
different
|
||||
* #4812: autodoc ignores type annotated variables
|
||||
* #4817: wrong URLs on warning messages
|
||||
|
||||
Testing
|
||||
|
@ -40,7 +40,7 @@ from sphinx.util import pycompat # noqa: F401
|
||||
from sphinx.util.console import bold # type: ignore
|
||||
from sphinx.util.docutils import is_html5_writer_available, directive_helper
|
||||
from sphinx.util.i18n import find_catalog_source_files
|
||||
from sphinx.util.osutil import ENOENT, ensuredir
|
||||
from sphinx.util.osutil import ENOENT, ensuredir, relpath
|
||||
from sphinx.util.tags import Tags
|
||||
|
||||
if False:
|
||||
@ -342,7 +342,7 @@ class Sphinx(object):
|
||||
if self.statuscode == 0 and self.builder.epilog:
|
||||
logger.info('')
|
||||
logger.info(self.builder.epilog % {
|
||||
'outdir': path.relpath(self.outdir),
|
||||
'outdir': relpath(self.outdir),
|
||||
'project': self.config.project
|
||||
})
|
||||
except Exception as err:
|
||||
|
@ -19,7 +19,7 @@ from sphinx.environment.adapters.asset import ImageAdapter
|
||||
from sphinx.util import i18n, logging, status_iterator
|
||||
from sphinx.util.console import bold # type: ignore
|
||||
from sphinx.util.i18n import find_catalog
|
||||
from sphinx.util.osutil import SEP, ensuredir, relative_uri
|
||||
from sphinx.util.osutil import SEP, ensuredir, relative_uri, relpath
|
||||
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \
|
||||
parallel_available
|
||||
|
||||
@ -237,7 +237,7 @@ class Builder(object):
|
||||
|
||||
def cat2relpath(cat):
|
||||
# type: (CatalogInfo) -> unicode
|
||||
return path.relpath(cat.mo_path, self.env.srcdir).replace(path.sep, SEP)
|
||||
return relpath(cat.mo_path, self.env.srcdir).replace(path.sep, SEP)
|
||||
|
||||
logger.info(bold('building [mo]: ') + message)
|
||||
for catalog in status_iterator(catalogs, 'writing output... ', "darkgreen",
|
||||
|
@ -26,7 +26,7 @@ from sphinx.util import split_index_msg, logging, status_iterator
|
||||
from sphinx.util.console import bold # type: ignore
|
||||
from sphinx.util.i18n import find_catalog
|
||||
from sphinx.util.nodes import extract_messages, traverse_translatable_index
|
||||
from sphinx.util.osutil import safe_relpath, ensuredir, canon_path
|
||||
from sphinx.util.osutil import relpath, ensuredir, canon_path
|
||||
from sphinx.util.tags import Tags
|
||||
|
||||
if False:
|
||||
@ -284,8 +284,7 @@ class MessageCatalogBuilder(I18nBuilder):
|
||||
if self.config.gettext_location:
|
||||
# generate "#: file1:line1\n#: file2:line2 ..."
|
||||
output.write("#: %s\n" % "\n#: ".join( # type: ignore
|
||||
"%s:%s" % (canon_path(
|
||||
safe_relpath(source, self.outdir)), line)
|
||||
"%s:%s" % (canon_path(relpath(source, self.outdir)), line)
|
||||
for source, line, _ in positions))
|
||||
if self.config.gettext_uuid:
|
||||
# generate "# uuid1\n# uuid2\n ..."
|
||||
|
@ -23,7 +23,7 @@ from sphinx.util.nodes import explicit_title_re, set_source_info, \
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict, List, Tuple # NOQA
|
||||
from typing import Any, Dict, Generator, List, Tuple # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@ from sphinx.util.docutils import sphinx_domains, WarningStream
|
||||
from sphinx.util.i18n import find_catalog_files
|
||||
from sphinx.util.matching import compile_matchers
|
||||
from sphinx.util.nodes import is_translatable
|
||||
from sphinx.util.osutil import SEP, ensuredir
|
||||
from sphinx.util.osutil import SEP, ensuredir, relpath
|
||||
from sphinx.util.parallel import ParallelTasks, parallel_available, make_chunks
|
||||
from sphinx.util.websupport import is_commentable
|
||||
|
||||
@ -346,7 +346,7 @@ class BuildEnvironment(object):
|
||||
*filename* should be absolute or relative to the source directory.
|
||||
"""
|
||||
if filename.startswith(self.srcdir):
|
||||
filename = os.path.relpath(filename, self.srcdir)
|
||||
filename = relpath(filename, self.srcdir)
|
||||
for suffix in self.config.source_suffix:
|
||||
if filename.endswith(suffix):
|
||||
return filename[:-len(suffix)]
|
||||
|
@ -90,7 +90,7 @@ if False:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
periods_re = re.compile('\.(?:\s+)')
|
||||
periods_re = re.compile(r'\.(?:\s+)')
|
||||
|
||||
|
||||
# -- autosummary_toc node ------------------------------------------------------
|
||||
|
@ -30,7 +30,7 @@ from sphinx.locale import _
|
||||
from sphinx.util import force_decode, logging
|
||||
from sphinx.util.console import bold # type: ignore
|
||||
from sphinx.util.nodes import set_source_info
|
||||
from sphinx.util.osutil import fs_encoding
|
||||
from sphinx.util.osutil import fs_encoding, relpath
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
@ -372,7 +372,7 @@ Doctest summary
|
||||
"""Try to get the file which actually contains the doctest, not the
|
||||
filename of the document it's included in."""
|
||||
try:
|
||||
filename = path.relpath(node.source, self.env.srcdir)\
|
||||
filename = relpath(node.source, self.env.srcdir)\
|
||||
.rsplit(':docstring of ', maxsplit=1)[0]
|
||||
except Exception:
|
||||
filename = self.env.doc2path(docname, base=None)
|
||||
|
@ -12,6 +12,7 @@ import ast
|
||||
import inspect
|
||||
import itertools
|
||||
import re
|
||||
import sys
|
||||
import tokenize
|
||||
from token import NAME, NEWLINE, INDENT, DEDENT, NUMBER, OP, STRING
|
||||
from tokenize import COMMENT, NL
|
||||
@ -27,6 +28,21 @@ indent_re = re.compile(u'^\\s*$')
|
||||
emptyline_re = re.compile(u'^\\s*(#.*)?$')
|
||||
|
||||
|
||||
if sys.version_info >= (3, 6):
|
||||
ASSIGN_NODES = (ast.Assign, ast.AnnAssign)
|
||||
else:
|
||||
ASSIGN_NODES = (ast.Assign)
|
||||
|
||||
|
||||
def get_assign_targets(node):
|
||||
# type: (ast.AST) -> List[ast.expr]
|
||||
"""Get list of targets from Assign and AnnAssign node."""
|
||||
if isinstance(node, ast.Assign):
|
||||
return node.targets
|
||||
else:
|
||||
return [node.target] # type: ignore
|
||||
|
||||
|
||||
def get_lvar_names(node, self=None):
|
||||
# type: (ast.AST, ast.expr) -> List[unicode]
|
||||
"""Convert assignment-AST to variable names.
|
||||
@ -284,7 +300,8 @@ class VariableCommentPicker(ast.NodeVisitor):
|
||||
# type: (ast.Assign) -> None
|
||||
"""Handles Assign node and pick up a variable comment."""
|
||||
try:
|
||||
varnames = sum([get_lvar_names(t, self=self.get_self()) for t in node.targets], [])
|
||||
targets = get_assign_targets(node)
|
||||
varnames = sum([get_lvar_names(t, self=self.get_self()) for t in targets], [])
|
||||
current_line = self.get_line(node.lineno)
|
||||
except TypeError:
|
||||
return # this assignment is not new definition!
|
||||
@ -320,12 +337,18 @@ class VariableCommentPicker(ast.NodeVisitor):
|
||||
for varname in varnames:
|
||||
self.add_entry(varname)
|
||||
|
||||
def visit_AnnAssign(self, node):
|
||||
# type: (ast.AST) -> None
|
||||
"""Handles AnnAssign node and pick up a variable comment."""
|
||||
self.visit_Assign(node) # type: ignore
|
||||
|
||||
def visit_Expr(self, node):
|
||||
# type: (ast.Expr) -> None
|
||||
"""Handles Expr node and pick up a comment if string."""
|
||||
if (isinstance(self.previous, ast.Assign) and isinstance(node.value, ast.Str)):
|
||||
if (isinstance(self.previous, ASSIGN_NODES) and isinstance(node.value, ast.Str)):
|
||||
try:
|
||||
varnames = get_lvar_names(self.previous.targets[0], self.get_self())
|
||||
targets = get_assign_targets(self.previous)
|
||||
varnames = get_lvar_names(targets[0], self.get_self())
|
||||
for varname in varnames:
|
||||
if isinstance(node.value.s, text_type):
|
||||
docstring = node.value.s
|
||||
|
@ -23,6 +23,7 @@ from sphinx.builders.latex import LaTeXBuilder
|
||||
from sphinx.ext.autodoc import AutoDirective
|
||||
from sphinx.pycode import ModuleAnalyzer
|
||||
from sphinx.testing.path import path
|
||||
from sphinx.util.osutil import relpath
|
||||
|
||||
if False:
|
||||
from typing import List # NOQA
|
||||
@ -184,7 +185,7 @@ def find_files(root, suffix=None):
|
||||
dirpath = path(dirpath)
|
||||
for f in [f for f in files if not suffix or f.endswith(suffix)]:
|
||||
fpath = dirpath / f
|
||||
yield os.path.relpath(fpath, root)
|
||||
yield relpath(fpath, root)
|
||||
|
||||
|
||||
def strip_escseq(text):
|
||||
|
@ -22,7 +22,7 @@ from babel.messages.pofile import read_po
|
||||
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.osutil import SEP, walk
|
||||
from sphinx.util.osutil import SEP, relpath, walk
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -96,7 +96,7 @@ def find_catalog_files(docname, srcdir, locale_dirs, lang, compaction):
|
||||
domain = find_catalog(docname, compaction)
|
||||
files = [gettext.find(domain, path.join(srcdir, dir_), [lang]) # type: ignore
|
||||
for dir_ in locale_dirs]
|
||||
files = [path.relpath(f, srcdir) for f in files if f] # type: ignore
|
||||
files = [relpath(f, srcdir) for f in files if f] # type: ignore
|
||||
return files # type: ignore
|
||||
|
||||
|
||||
@ -137,7 +137,7 @@ def find_catalog_source_files(locale_dirs, locale, domains=None, gettext_compact
|
||||
filenames = [f for f in filenames if f.endswith('.po')]
|
||||
for filename in filenames:
|
||||
base = path.splitext(filename)[0]
|
||||
domain = path.relpath(path.join(dirpath, base), base_dir)
|
||||
domain = relpath(path.join(dirpath, base), base_dir)
|
||||
if gettext_compact and path.sep in domain:
|
||||
domain = path.split(domain)[0]
|
||||
domain = domain.replace(path.sep, SEP)
|
||||
|
@ -205,14 +205,21 @@ def ustrftime(format, *args):
|
||||
return r.encode().decode('unicode-escape')
|
||||
|
||||
|
||||
def safe_relpath(path, start=None):
|
||||
def relpath(path, start=os.curdir):
|
||||
# type: (unicode, unicode) -> unicode
|
||||
"""Return a relative filepath to *path* either from the current directory or
|
||||
from an optional *start* directory.
|
||||
|
||||
This is an alternative of ``os.path.relpath()``. This returns original path
|
||||
if *path* and *start* are on different drives (for Windows platform).
|
||||
"""
|
||||
try:
|
||||
return os.path.relpath(path, start)
|
||||
except ValueError:
|
||||
return path
|
||||
|
||||
|
||||
safe_relpath = relpath # for compatibility
|
||||
fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() # type: unicode
|
||||
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from six import PY2
|
||||
|
||||
@ -94,6 +96,18 @@ def test_comment_picker_location():
|
||||
('Foo', 'attr3'): 'comment for attr3(3)'}
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 6), reason='tests for py36+ syntax')
|
||||
def test_annotated_assignment_py36():
|
||||
source = ('a: str = "Sphinx" #: comment\n'
|
||||
'b: int = 1\n'
|
||||
'"""string on next line"""')
|
||||
parser = Parser(source)
|
||||
parser.parse()
|
||||
assert parser.comments == {('', 'a'): 'comment',
|
||||
('', 'b'): 'string on next line'}
|
||||
assert parser.definitions == {}
|
||||
|
||||
|
||||
def test_complex_assignment():
|
||||
source = ('a = 1 + 1; b = a #: compound statement\n'
|
||||
'c, d = (1, 1) #: unpack assignment\n'
|
||||
|
Loading…
Reference in New Issue
Block a user