mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch 'stable' into 1.7-release
This commit is contained in:
commit
af25fa123d
2
CHANGES
2
CHANGES
@ -204,6 +204,8 @@ Bugs fixed
|
||||
* #4438: math: math with labels with whitespace cause html error
|
||||
* #2437: make full reference for classes, aliased with "alias of"
|
||||
* #4434: pure numbers as link targets produce warning
|
||||
* #4477: Build fails after building specific files
|
||||
* #4449: apidoc: include "empty" packages that contain modules
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
@ -54,9 +54,11 @@ from sphinx.environment.adapters.indexentries import IndexEntries
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict, Iterable, Iterator, List, Type, Tuple, Union # NOQA
|
||||
from sphinx.domains import Domain, Index # NOQA
|
||||
from typing import Any, Dict, IO, Iterable, Iterator, List, Type, Tuple, Union # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from sphinx.config import Config # NOQA
|
||||
from sphinx.domains import Domain, Index # NOQA
|
||||
from sphinx.util.tags import Tags # NOQA
|
||||
|
||||
# Experimental HTML5 Writer
|
||||
if is_html5_writer_available():
|
||||
@ -147,6 +149,56 @@ class Stylesheet(text_type):
|
||||
return self
|
||||
|
||||
|
||||
class BuildInfo(object):
|
||||
"""buildinfo file manipulator.
|
||||
|
||||
HTMLBuilder and its family are storing their own envdata to ``.buildinfo``.
|
||||
This class is a manipulator for the file.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def load(cls, f):
|
||||
# type: (IO) -> BuildInfo
|
||||
try:
|
||||
lines = f.readlines()
|
||||
assert lines[0].rstrip() == '# Sphinx build info version 1'
|
||||
assert lines[2].startswith('config: ')
|
||||
assert lines[3].startswith('tags: ')
|
||||
|
||||
build_info = BuildInfo()
|
||||
build_info.config_hash = lines[2].split()[1].strip()
|
||||
build_info.tags_hash = lines[3].split()[1].strip()
|
||||
return build_info
|
||||
except Exception as exc:
|
||||
raise ValueError('build info file is broken: %r' % exc)
|
||||
|
||||
def __init__(self, config=None, tags=None):
|
||||
# type: (Config, Tags) -> None
|
||||
self.config_hash = u''
|
||||
self.tags_hash = u''
|
||||
|
||||
if config:
|
||||
values = dict((c.name, c.value) for c in config.filter('html'))
|
||||
self.config_hash = get_stable_hash(values)
|
||||
|
||||
if tags:
|
||||
self.tags_hash = get_stable_hash(sorted(tags))
|
||||
|
||||
def __eq__(self, other): # type: ignore
|
||||
# type: (BuildInfo) -> bool
|
||||
return (self.config_hash == other.config_hash and
|
||||
self.tags_hash == other.tags_hash)
|
||||
|
||||
def dump(self, f):
|
||||
# type: (IO) -> None
|
||||
f.write('# Sphinx build info version 1\n'
|
||||
'# This file hashes the configuration used when building these files.'
|
||||
' When it is not found, a full rebuild will be done.\n'
|
||||
'config: %s\n'
|
||||
'tags: %s\n' %
|
||||
(self.config_hash, self.tags_hash))
|
||||
|
||||
|
||||
class StandaloneHTMLBuilder(Builder):
|
||||
"""
|
||||
Builds standalone HTML docs.
|
||||
@ -191,9 +243,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
|
||||
def init(self):
|
||||
# type: () -> None
|
||||
# a hash of all config values that, if changed, cause a full rebuild
|
||||
self.config_hash = '' # type: unicode
|
||||
self.tags_hash = '' # type: unicode
|
||||
self.build_info = BuildInfo(self.config, self.tags)
|
||||
# basename of images directory
|
||||
self.imagedir = '_images'
|
||||
# section numbers for headings in the currently visited document
|
||||
@ -274,32 +324,19 @@ class StandaloneHTMLBuilder(Builder):
|
||||
|
||||
def get_outdated_docs(self):
|
||||
# type: () -> Iterator[unicode]
|
||||
cfgdict = dict((confval.name, confval.value) for confval in self.config.filter('html'))
|
||||
self.config_hash = get_stable_hash(cfgdict)
|
||||
self.tags_hash = get_stable_hash(sorted(self.tags))
|
||||
old_config_hash = old_tags_hash = ''
|
||||
try:
|
||||
with open(path.join(self.outdir, '.buildinfo')) as fp:
|
||||
version = fp.readline()
|
||||
if version.rstrip() != '# Sphinx build info version 1':
|
||||
raise ValueError
|
||||
fp.readline() # skip commentary
|
||||
cfg, old_config_hash = fp.readline().strip().split(': ')
|
||||
if cfg != 'config':
|
||||
raise ValueError
|
||||
tag, old_tags_hash = fp.readline().strip().split(': ')
|
||||
if tag != 'tags':
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
logger.warning('unsupported build info format in %r, building all',
|
||||
path.join(self.outdir, '.buildinfo'))
|
||||
except Exception:
|
||||
pass
|
||||
if old_config_hash != self.config_hash or \
|
||||
old_tags_hash != self.tags_hash:
|
||||
buildinfo = BuildInfo.load(fp)
|
||||
|
||||
if self.build_info != buildinfo:
|
||||
for docname in self.env.found_docs:
|
||||
yield docname
|
||||
return
|
||||
except ValueError as exc:
|
||||
logger.warning('Failed to read build info file: %r', exc)
|
||||
except IOError:
|
||||
# ignore errors on reading
|
||||
pass
|
||||
|
||||
if self.templates:
|
||||
template_mtime = self.templates.newest_template_mtime()
|
||||
@ -777,14 +814,9 @@ class StandaloneHTMLBuilder(Builder):
|
||||
|
||||
def write_buildinfo(self):
|
||||
# type: () -> None
|
||||
# write build info file
|
||||
try:
|
||||
with open(path.join(self.outdir, '.buildinfo'), 'w') as fp:
|
||||
fp.write('# Sphinx build info version 1\n'
|
||||
'# This file hashes the configuration used when building'
|
||||
' these files. When it is not found, a full rebuild will'
|
||||
' be done.\nconfig: %s\ntags: %s\n' %
|
||||
(self.config_hash, self.tags_hash))
|
||||
self.build_info.dump(fp)
|
||||
except IOError as exc:
|
||||
logger.warning('Failed to write build info file: %r', exc)
|
||||
|
||||
@ -1257,8 +1289,7 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
|
||||
|
||||
def init(self):
|
||||
# type: () -> None
|
||||
self.config_hash = ''
|
||||
self.tags_hash = ''
|
||||
self.build_info = BuildInfo(self.config, self.tags)
|
||||
self.imagedir = '_images'
|
||||
self.current_docname = None
|
||||
self.theme = None # no theme necessary
|
||||
|
@ -18,6 +18,7 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
from os import path
|
||||
@ -194,6 +195,16 @@ def shall_skip(module, opts):
|
||||
|
||||
# skip it if there is nothing (or just \n or \r\n) in the file
|
||||
if path.exists(module) and path.getsize(module) <= 2:
|
||||
skip = True
|
||||
if os.path.basename(module) == '__init__.py':
|
||||
pattern = path.join(path.dirname(module), '*.py')
|
||||
# We only want to skip packages if they do not contain any
|
||||
# .py files other than __init__.py.
|
||||
other_modules = list(glob.glob(pattern))
|
||||
other_modules.remove(module)
|
||||
skip = not other_modules
|
||||
|
||||
if skip:
|
||||
return True
|
||||
|
||||
# skip if it has a "private" name and this is selected
|
||||
|
0
tests/roots/test-apidoc-pep420/a/b/e/__init__.py
Normal file
0
tests/roots/test-apidoc-pep420/a/b/e/__init__.py
Normal file
1
tests/roots/test-apidoc-pep420/a/b/e/f.py
Normal file
1
tests/roots/test-apidoc-pep420/a/b/e/f.py
Normal file
@ -0,0 +1 @@
|
||||
"Module f"
|
@ -67,6 +67,7 @@ def test_pep_0420_enabled(make_app, apidoc):
|
||||
outdir = apidoc.outdir
|
||||
assert (outdir / 'conf.py').isfile()
|
||||
assert (outdir / 'a.b.c.rst').isfile()
|
||||
assert (outdir / 'a.b.e.rst').isfile()
|
||||
assert (outdir / 'a.b.x.rst').isfile()
|
||||
|
||||
with open(outdir / 'a.b.c.rst') as f:
|
||||
@ -74,6 +75,10 @@ def test_pep_0420_enabled(make_app, apidoc):
|
||||
assert "automodule:: a.b.c.d\n" in rst
|
||||
assert "automodule:: a.b.c\n" in rst
|
||||
|
||||
with open(outdir / 'a.b.e.rst') as f:
|
||||
rst = f.read()
|
||||
assert "automodule:: a.b.e.f\n" in rst
|
||||
|
||||
with open(outdir / 'a.b.x.rst') as f:
|
||||
rst = f.read()
|
||||
assert "automodule:: a.b.x.y\n" in rst
|
||||
@ -86,12 +91,67 @@ def test_pep_0420_enabled(make_app, apidoc):
|
||||
|
||||
builddir = outdir / '_build' / 'text'
|
||||
assert (builddir / 'a.b.c.txt').isfile()
|
||||
assert (builddir / 'a.b.e.txt').isfile()
|
||||
assert (builddir / 'a.b.x.txt').isfile()
|
||||
|
||||
with open(builddir / 'a.b.c.txt') as f:
|
||||
txt = f.read()
|
||||
assert "a.b.c package\n" in txt
|
||||
|
||||
with open(builddir / 'a.b.e.txt') as f:
|
||||
txt = f.read()
|
||||
assert "a.b.e.f module\n" in txt
|
||||
|
||||
with open(builddir / 'a.b.x.txt') as f:
|
||||
txt = f.read()
|
||||
assert "a.b.x namespace\n" in txt
|
||||
|
||||
|
||||
@pytest.mark.apidoc(
|
||||
coderoot='test-apidoc-pep420/a',
|
||||
options=["--implicit-namespaces", "--separate"],
|
||||
)
|
||||
def test_pep_0420_enabled_separate(make_app, apidoc):
|
||||
outdir = apidoc.outdir
|
||||
assert (outdir / 'conf.py').isfile()
|
||||
assert (outdir / 'a.b.c.rst').isfile()
|
||||
assert (outdir / 'a.b.e.rst').isfile()
|
||||
assert (outdir / 'a.b.e.f.rst').isfile()
|
||||
assert (outdir / 'a.b.x.rst').isfile()
|
||||
assert (outdir / 'a.b.x.y.rst').isfile()
|
||||
|
||||
with open(outdir / 'a.b.c.rst') as f:
|
||||
rst = f.read()
|
||||
assert ".. toctree::\n\n a.b.c.d\n" in rst
|
||||
|
||||
with open(outdir / 'a.b.e.rst') as f:
|
||||
rst = f.read()
|
||||
assert ".. toctree::\n\n a.b.e.f\n" in rst
|
||||
|
||||
with open(outdir / 'a.b.x.rst') as f:
|
||||
rst = f.read()
|
||||
assert ".. toctree::\n\n a.b.x.y\n" in rst
|
||||
|
||||
app = make_app('text', srcdir=outdir)
|
||||
app.build()
|
||||
print(app._status.getvalue())
|
||||
print(app._warning.getvalue())
|
||||
|
||||
builddir = outdir / '_build' / 'text'
|
||||
assert (builddir / 'a.b.c.txt').isfile()
|
||||
assert (builddir / 'a.b.e.txt').isfile()
|
||||
assert (builddir / 'a.b.e.f.txt').isfile()
|
||||
assert (builddir / 'a.b.x.txt').isfile()
|
||||
assert (builddir / 'a.b.x.y.txt').isfile()
|
||||
|
||||
with open(builddir / 'a.b.c.txt') as f:
|
||||
txt = f.read()
|
||||
assert "a.b.c package\n" in txt
|
||||
|
||||
with open(builddir / 'a.b.e.f.txt') as f:
|
||||
txt = f.read()
|
||||
assert "a.b.e.f module\n" in txt
|
||||
|
||||
with open(builddir / 'a.b.x.txt') as f:
|
||||
txt = f.read()
|
||||
assert "a.b.x namespace\n" in txt
|
||||
|
Loading…
Reference in New Issue
Block a user