mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '2.0'
This commit is contained in:
@@ -19,7 +19,7 @@ matrix:
|
||||
- TOXENV=du13
|
||||
- python: '3.7'
|
||||
env:
|
||||
- TOXENV=py37
|
||||
- TOXENV=du14
|
||||
- PYTEST_ADDOPTS="--cov ./ --cov-append --cov-config setup.cfg"
|
||||
- python: 'nightly'
|
||||
env: TOXENV=py38
|
||||
|
54
CHANGES
54
CHANGES
@@ -1,3 +1,4 @@
|
||||
<<<<<<< HEAD
|
||||
Release 3.0.0 (in development)
|
||||
==============================
|
||||
|
||||
@@ -26,7 +27,7 @@ Bugs fixed
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 2.2.0 (in development)
|
||||
Release 2.3.0 (in development)
|
||||
==============================
|
||||
|
||||
Dependencies
|
||||
@@ -35,7 +36,26 @@ Dependencies
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
Deprecated
|
||||
----------
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 2.2.0 (released Aug 19, 2019)
|
||||
=====================================
|
||||
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
* apidoc: template files are renamed to ``.rst_t``
|
||||
* html: Field lists will be styled by grid layout
|
||||
|
||||
Deprecated
|
||||
----------
|
||||
@@ -63,6 +83,9 @@ Features added
|
||||
* #6310: imgmath: let :confval:`imgmath_use_preview` work also with the SVG
|
||||
format for images rendering inline math
|
||||
* #6533: LaTeX: refactor visit_enumerated_list() to use ``\sphinxsetlistlabels``
|
||||
* #6628: quickstart: Use ``https://docs.python.org/3/`` for default setting of
|
||||
:confval:`intersphinx_mapping`
|
||||
* #6419: sphinx-build: give reasons why rebuilded
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
@@ -78,6 +101,9 @@ Bugs fixed
|
||||
``__init__()`` and ``__new__()``
|
||||
* #6574: autodoc: :confval:`autodoc_member_order` does not refer order of
|
||||
imports when ``'bysource'`` order
|
||||
* #6574: autodoc: missing type annotation for variadic and keyword parameters
|
||||
* #6589: autodoc: Formatting issues with autodoc_typehints='none'
|
||||
* #6605: autodoc: crashed when target code contains custom method-like objects
|
||||
* #6498: autosummary: crashed with wrong autosummary_generate setting
|
||||
* #6507: autosummary: crashes without no autosummary_generate setting
|
||||
* #6511: LaTeX: autonumbered list can not be customized in LaTeX
|
||||
@@ -92,30 +118,8 @@ Bugs fixed
|
||||
* #6561: glossary: Wrong hyperlinks are generated for non alphanumeric terms
|
||||
* #6620: i18n: classifiers of definition list are not translated with
|
||||
docutils-0.15
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 2.1.3 (in development)
|
||||
==============================
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
Deprecated
|
||||
----------
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
Testing
|
||||
--------
|
||||
* #6474: ``DocFieldTransformer`` raises AttributeError when given directive is
|
||||
not a subclass of ObjectDescription
|
||||
|
||||
Release 2.1.2 (released Jun 19, 2019)
|
||||
=====================================
|
||||
|
@@ -80,6 +80,14 @@ are built:
|
||||
This value should only contain the path to the latex executable, not further
|
||||
arguments; use :confval:`imgmath_latex_args` for that purpose.
|
||||
|
||||
.. hint::
|
||||
|
||||
Some fancy LaTeX mark-up (an example was reported which used TikZ to add
|
||||
various decorations to the equation) require multiple runs of the LaTeX
|
||||
executable. To handle this, set this configuration setting to
|
||||
``'latexmk'`` (or a full path to it) as this Perl script reliably
|
||||
chooses dynamically how many latex runs are needed.
|
||||
|
||||
.. confval:: imgmath_latex_args
|
||||
|
||||
Additional arguments to give to latex, as a list. The default is an empty
|
||||
|
@@ -388,9 +388,11 @@ class Builder:
|
||||
# ... but not those that already were removed
|
||||
changed.update(self.env.glob_toctrees & self.env.found_docs)
|
||||
|
||||
if changed:
|
||||
reason = CONFIG_CHANGED_REASON.get(self.env.config_status, '')
|
||||
if updated: # explain the change iff build config status was not ok
|
||||
reason = (CONFIG_CHANGED_REASON.get(self.env.config_status, '') +
|
||||
(self.env.config_status_extra or ''))
|
||||
logger.info('[%s] ', reason, nonl=True)
|
||||
|
||||
logger.info(__('%s added, %s changed, %s removed'),
|
||||
len(added), len(changed), len(removed))
|
||||
|
||||
|
@@ -31,10 +31,7 @@ RemovedInNextVersionWarning = RemovedInSphinx40Warning
|
||||
|
||||
def deprecated_alias(modname, objects, warning):
|
||||
# type: (str, Dict, Type[Warning]) -> None
|
||||
module = sys.modules.get(modname)
|
||||
if module is None:
|
||||
module = import_module(modname)
|
||||
|
||||
module = import_module(modname)
|
||||
sys.modules[modname] = _ModuleWrapper(module, modname, objects, warning) # type: ignore
|
||||
|
||||
|
||||
|
@@ -93,14 +93,15 @@ class BuildEnvironment:
|
||||
# --------- ENVIRONMENT INITIALIZATION -------------------------------------
|
||||
|
||||
def __init__(self, app: "Sphinx" = None):
|
||||
self.app = None # type: Sphinx
|
||||
self.doctreedir = None # type: str
|
||||
self.srcdir = None # type: str
|
||||
self.config = None # type: Config
|
||||
self.config_status = None # type: int
|
||||
self.events = None # type: EventManager
|
||||
self.project = None # type: Project
|
||||
self.version = None # type: Dict[str, str]
|
||||
self.app = None # type: Sphinx
|
||||
self.doctreedir = None # type: str
|
||||
self.srcdir = None # type: str
|
||||
self.config = None # type: Config
|
||||
self.config_status = None # type: int
|
||||
self.config_status_extra = None # type: str
|
||||
self.events = None # type: EventManager
|
||||
self.project = None # type: Project
|
||||
self.version = None # type: Dict[str, str]
|
||||
|
||||
# the method of doctree versioning; see set_versioning_method
|
||||
self.versioning_condition = None # type: Union[bool, Callable]
|
||||
@@ -230,16 +231,25 @@ class BuildEnvironment:
|
||||
def _update_config(self, config: Config) -> None:
|
||||
"""Update configurations by new one."""
|
||||
self.config_status = CONFIG_OK
|
||||
self.config_status_extra = ''
|
||||
if self.config is None:
|
||||
self.config_status = CONFIG_NEW
|
||||
elif self.config.extensions != config.extensions:
|
||||
self.config_status = CONFIG_EXTENSIONS_CHANGED
|
||||
extensions = sorted(
|
||||
set(self.config.extensions) ^ set(config.extensions))
|
||||
if len(extensions) == 1:
|
||||
extension = extensions[0]
|
||||
else:
|
||||
extension = '%d' % (len(extensions),)
|
||||
self.config_status_extra = ' (%r)' % (extension,)
|
||||
else:
|
||||
# check if a config value was changed that affects how
|
||||
# doctrees are read
|
||||
for item in config.filter('env'):
|
||||
if self.config[item.name] != item.value:
|
||||
self.config_status = CONFIG_CHANGED
|
||||
self.config_status_extra = ' (%r)' % (item.name,)
|
||||
break
|
||||
|
||||
self.config = config
|
||||
|
@@ -8,7 +8,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import importlib
|
||||
import traceback
|
||||
import warnings
|
||||
from collections import namedtuple
|
||||
@@ -23,14 +23,13 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
def import_module(modname: str, warningiserror: bool = False) -> Any:
|
||||
"""
|
||||
Call __import__(modname), convert exceptions to ImportError
|
||||
Call importlib.import_module(modname), convert exceptions to ImportError
|
||||
"""
|
||||
try:
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=ImportWarning)
|
||||
with logging.skip_warningiserror(not warningiserror):
|
||||
__import__(modname)
|
||||
return sys.modules[modname]
|
||||
return importlib.import_module(modname)
|
||||
except BaseException as exc:
|
||||
# Importing modules may cause any side effects, including
|
||||
# SystemExit, so we need to catch all errors.
|
||||
|
@@ -13,6 +13,7 @@ import glob
|
||||
import inspect
|
||||
import pickle
|
||||
import re
|
||||
from importlib import import_module
|
||||
from os import path
|
||||
from typing import Any, Dict, IO, List, Pattern, Set, Tuple
|
||||
|
||||
@@ -144,7 +145,7 @@ class CoverageBuilder(Builder):
|
||||
continue
|
||||
|
||||
try:
|
||||
mod = __import__(mod_name, fromlist=['foo'])
|
||||
mod = import_module(mod_name)
|
||||
except ImportError as err:
|
||||
logger.warning(__('module %s could not be imported: %s'), mod_name, err)
|
||||
self.py_undoc[mod_name] = {'error': err}
|
||||
|
@@ -38,8 +38,8 @@ r"""
|
||||
import builtins
|
||||
import inspect
|
||||
import re
|
||||
import sys
|
||||
from hashlib import md5
|
||||
from importlib import import_module
|
||||
from typing import Any, Dict, Iterable, List, Tuple
|
||||
from typing import cast
|
||||
|
||||
@@ -74,8 +74,10 @@ def try_import(objname: str) -> Any:
|
||||
Returns imported object or module. If failed, returns None value.
|
||||
"""
|
||||
try:
|
||||
__import__(objname)
|
||||
return sys.modules.get(objname)
|
||||
return import_module(objname)
|
||||
except TypeError:
|
||||
# Relative import
|
||||
return None
|
||||
except ImportError:
|
||||
matched = module_sig_re.match(objname)
|
||||
|
||||
@@ -87,8 +89,8 @@ def try_import(objname: str) -> Any:
|
||||
if modname is None:
|
||||
return None
|
||||
try:
|
||||
__import__(modname)
|
||||
return getattr(sys.modules.get(modname), attrname, None)
|
||||
module = import_module(modname)
|
||||
return getattr(module, attrname, None)
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
|
@@ -9,6 +9,7 @@
|
||||
"""
|
||||
|
||||
from functools import partial
|
||||
from importlib import import_module
|
||||
|
||||
from pygments import highlight
|
||||
from pygments.filters import ErrorToken
|
||||
@@ -83,7 +84,7 @@ class PygmentsBridge:
|
||||
return NoneStyle
|
||||
elif '.' in stylename:
|
||||
module, stylename = stylename.rsplit('.', 1)
|
||||
return getattr(__import__(module, None, None, ['__name__']), stylename)
|
||||
return getattr(import_module(module), stylename)
|
||||
else:
|
||||
return get_style_by_name(stylename)
|
||||
|
||||
|
@@ -9,6 +9,7 @@
|
||||
"""
|
||||
|
||||
import traceback
|
||||
from importlib import import_module
|
||||
from types import MethodType
|
||||
|
||||
from docutils.parsers.rst import Directive
|
||||
@@ -419,18 +420,19 @@ class SphinxComponentRegistry:
|
||||
prefix = __('while setting up extension %s:') % extname
|
||||
with prefixed_warnings(prefix):
|
||||
try:
|
||||
mod = __import__(extname, None, None, ['setup'])
|
||||
mod = import_module(extname)
|
||||
except ImportError as err:
|
||||
logger.verbose(__('Original exception:\n') + traceback.format_exc())
|
||||
raise ExtensionError(__('Could not import extension %s') % extname, err)
|
||||
|
||||
if not hasattr(mod, 'setup'):
|
||||
setup = getattr(mod, 'setup', None)
|
||||
if setup is None:
|
||||
logger.warning(__('extension %r has no setup() function; is it really '
|
||||
'a Sphinx extension module?'), extname)
|
||||
metadata = {} # type: Dict[str, Any]
|
||||
else:
|
||||
try:
|
||||
metadata = mod.setup(app)
|
||||
metadata = setup(app)
|
||||
except VersionRequirementError as err:
|
||||
# add the extension name to the version required
|
||||
raise VersionRequirementError(
|
||||
|
@@ -11,6 +11,7 @@ import html
|
||||
import pickle
|
||||
import re
|
||||
import warnings
|
||||
from importlib import import_module
|
||||
from os import path
|
||||
|
||||
from docutils import nodes
|
||||
@@ -278,8 +279,7 @@ class IndexBuilder:
|
||||
self.lang = SearchEnglish(options) # type: SearchLanguage
|
||||
elif isinstance(lang_class, str):
|
||||
module, classname = lang_class.rsplit('.', 1)
|
||||
lang_class = getattr(__import__(module, None, None, [classname]),
|
||||
classname)
|
||||
lang_class = getattr(import_module(module), classname)
|
||||
self.lang = lang_class(options)
|
||||
else:
|
||||
# it's directly a class (e.g. added by app.add_search_language)
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
@@ -105,7 +105,7 @@ html_static_path = ['{{ dot }}static']
|
||||
# -- Options for intersphinx extension ---------------------------------------
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
intersphinx_mapping = {'https://docs.python.org/3/': None}
|
||||
{%- endif %}
|
||||
{%- if 'sphinx.ext.todo' in extensions %}
|
||||
|
||||
@@ -114,4 +114,3 @@ intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
{%- endif %}
|
||||
|
||||
|
@@ -520,14 +520,15 @@ dl.citation > dd:after {
|
||||
}
|
||||
|
||||
dl.field-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
display: grid;
|
||||
grid-template-columns: fit-content(30%) auto;
|
||||
}
|
||||
|
||||
dl.field-list > dt {
|
||||
flex-basis: 20%;
|
||||
font-weight: bold;
|
||||
word-break: break-word;
|
||||
padding-left: 0.5em;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
dl.field-list > dt:after {
|
||||
@@ -535,8 +536,8 @@ dl.field-list > dt:after {
|
||||
}
|
||||
|
||||
dl.field-list > dd {
|
||||
flex-basis: 70%;
|
||||
padding-left: 1em;
|
||||
padding-left: 0.5em;
|
||||
margin-top: 0em;
|
||||
margin-left: 0em;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
6
sphinx/themes/basic/static/jquery.js
vendored
6
sphinx/themes/basic/static/jquery.js
vendored
File diff suppressed because one or more lines are too long
@@ -412,15 +412,10 @@ p.versionchanged span.versionmodified {
|
||||
|
||||
dl.field-list > dt {
|
||||
color: white;
|
||||
padding-left: 0.5em;
|
||||
padding-right: 5px;
|
||||
background-color: #82A0BE;
|
||||
}
|
||||
|
||||
dl.field-list > dd {
|
||||
padding-left: 0.5em;
|
||||
margin-top: 0em;
|
||||
margin-left: 0em;
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
|
@@ -292,7 +292,7 @@ code {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
th {
|
||||
th, dl.field-list > dt {
|
||||
background-color: #ede;
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,7 @@ from codecs import BOM_UTF8
|
||||
from collections import deque
|
||||
from datetime import datetime
|
||||
from hashlib import md5
|
||||
from importlib import import_module
|
||||
from os import path
|
||||
from time import mktime, strptime
|
||||
from typing import Any, Callable, Dict, IO, Iterable, Iterator, List, Pattern, Set, Tuple
|
||||
@@ -238,12 +239,10 @@ def get_module_source(modname: str) -> Tuple[str, str]:
|
||||
Can return ('file', 'filename') in which case the source is in the given
|
||||
file, or ('string', 'source') which which case the source is the string.
|
||||
"""
|
||||
if modname not in sys.modules:
|
||||
try:
|
||||
__import__(modname)
|
||||
except Exception as err:
|
||||
raise PycodeError('error importing %r' % modname, err)
|
||||
mod = sys.modules[modname]
|
||||
try:
|
||||
mod = import_module(modname)
|
||||
except Exception as err:
|
||||
raise PycodeError('error importing %r' % modname, err)
|
||||
filename = getattr(mod, '__file__', None)
|
||||
loader = getattr(mod, '__loader__', None)
|
||||
if loader and getattr(loader, 'get_filename', None):
|
||||
@@ -284,8 +283,7 @@ def get_full_modname(modname: str, attribute: str) -> str:
|
||||
# Prevents a TypeError: if the last getattr() call will return None
|
||||
# then it's better to return it directly
|
||||
return None
|
||||
__import__(modname)
|
||||
module = sys.modules[modname]
|
||||
module = import_module(modname)
|
||||
|
||||
# Allow an attribute to have multiple parts and incidentially allow
|
||||
# repeated .s in the attribute.
|
||||
@@ -540,14 +538,13 @@ def import_object(objname: str, source: str = None) -> Any:
|
||||
try:
|
||||
objpath = objname.split('.')
|
||||
modname = objpath.pop(0)
|
||||
obj = __import__(modname)
|
||||
obj = import_module(modname)
|
||||
for name in objpath:
|
||||
modname += '.' + name
|
||||
try:
|
||||
obj = getattr(obj, name)
|
||||
except AttributeError:
|
||||
__import__(modname)
|
||||
obj = getattr(obj, name)
|
||||
obj = import_module(modname)
|
||||
|
||||
return obj
|
||||
except (AttributeError, ImportError) as exc:
|
||||
|
@@ -218,7 +218,14 @@ class DocFieldTransformer:
|
||||
|
||||
def __init__(self, directive: "ObjectDescription") -> None:
|
||||
self.directive = directive
|
||||
self.typemap = directive.get_field_type_map()
|
||||
|
||||
try:
|
||||
self.typemap = directive.get_field_type_map()
|
||||
except Exception:
|
||||
# for 3rd party extensions directly calls this transformer.
|
||||
warnings.warn('DocFieldTransformer expects given directive object is a subclass '
|
||||
'of ObjectDescription.', RemovedInSphinx40Warning)
|
||||
self.typemap = self.preprocess_fieldtypes(directive.__class__.doc_field_types)
|
||||
|
||||
def preprocess_fieldtypes(self, types: List[Field]) -> Dict[str, Tuple[Field, bool]]:
|
||||
warnings.warn('DocFieldTransformer.preprocess_fieldtypes() is deprecated.',
|
||||
|
@@ -205,9 +205,12 @@ def isbuiltin(obj: Any) -> bool:
|
||||
|
||||
def iscoroutinefunction(obj: Any) -> bool:
|
||||
"""Check if the object is coroutine-function."""
|
||||
if inspect.iscoroutinefunction(obj):
|
||||
if hasattr(obj, '__code__') and inspect.iscoroutinefunction(obj):
|
||||
# check obj.__code__ because iscoroutinefunction() crashes for custom method-like
|
||||
# objects (see https://github.com/sphinx-doc/sphinx/issues/6605)
|
||||
return True
|
||||
elif ispartial(obj) and inspect.iscoroutinefunction(obj.func):
|
||||
elif (ispartial(obj) and hasattr(obj.func, '__code__') and
|
||||
inspect.iscoroutinefunction(obj.func)):
|
||||
# partialed
|
||||
return True
|
||||
else:
|
||||
@@ -378,6 +381,12 @@ class Signature:
|
||||
return None
|
||||
|
||||
def format_args(self, show_annotation: bool = True) -> str:
|
||||
def format_param_annotation(param: inspect.Parameter) -> str:
|
||||
if isinstance(param.annotation, str) and param.name in self.annotations:
|
||||
return self.format_annotation(self.annotations[param.name])
|
||||
else:
|
||||
return self.format_annotation(param.annotation)
|
||||
|
||||
args = []
|
||||
last_kind = None
|
||||
for i, param in enumerate(self.parameters.values()):
|
||||
@@ -399,14 +408,10 @@ class Signature:
|
||||
param.KEYWORD_ONLY):
|
||||
arg.write(param.name)
|
||||
if show_annotation and param.annotation is not param.empty:
|
||||
if isinstance(param.annotation, str) and param.name in self.annotations:
|
||||
arg.write(': ')
|
||||
arg.write(self.format_annotation(self.annotations[param.name]))
|
||||
else:
|
||||
arg.write(': ')
|
||||
arg.write(self.format_annotation(param.annotation))
|
||||
arg.write(': ')
|
||||
arg.write(format_param_annotation(param))
|
||||
if param.default is not param.empty:
|
||||
if param.annotation is param.empty:
|
||||
if param.annotation is param.empty or show_annotation is False:
|
||||
arg.write('=')
|
||||
arg.write(object_description(param.default))
|
||||
else:
|
||||
@@ -415,14 +420,20 @@ class Signature:
|
||||
elif param.kind == param.VAR_POSITIONAL:
|
||||
arg.write('*')
|
||||
arg.write(param.name)
|
||||
if show_annotation and param.annotation is not param.empty:
|
||||
arg.write(': ')
|
||||
arg.write(format_param_annotation(param))
|
||||
elif param.kind == param.VAR_KEYWORD:
|
||||
arg.write('**')
|
||||
arg.write(param.name)
|
||||
if show_annotation and param.annotation is not param.empty:
|
||||
arg.write(': ')
|
||||
arg.write(format_param_annotation(param))
|
||||
|
||||
args.append(arg.getvalue())
|
||||
last_kind = param.kind
|
||||
|
||||
if self.return_annotation is inspect.Parameter.empty:
|
||||
if self.return_annotation is inspect.Parameter.empty or show_annotation is False:
|
||||
return '(%s)' % ', '.join(args)
|
||||
else:
|
||||
if 'return' in self.annotations:
|
||||
|
@@ -7,6 +7,8 @@
|
||||
:copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
import pytest
|
||||
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
@@ -23,18 +25,30 @@ def test_config_status(make_app, app_params):
|
||||
app1 = make_app(*args, freshenv=True, **kwargs)
|
||||
assert app1.env.config_status == CONFIG_NEW
|
||||
app1.build()
|
||||
assert '[new config] 1 added' in app1._status.getvalue()
|
||||
|
||||
# incremental build (no config changed)
|
||||
app2 = make_app(*args, **kwargs)
|
||||
assert app2.env.config_status == CONFIG_OK
|
||||
app2.build()
|
||||
assert "0 added, 0 changed, 0 removed" in app2._status.getvalue()
|
||||
|
||||
# incremental build (config entry changed)
|
||||
app3 = make_app(*args, confoverrides={'master_doc': 'content'}, **kwargs)
|
||||
app3 = make_app(*args, confoverrides={'master_doc': 'indexx'}, **kwargs)
|
||||
fname = os.path.join(app3.srcdir, 'index.rst')
|
||||
assert os.path.isfile(fname)
|
||||
shutil.move(fname, fname[:-4] + 'x.rst')
|
||||
assert app3.env.config_status == CONFIG_CHANGED
|
||||
app3.build()
|
||||
shutil.move(fname[:-4] + 'x.rst', fname)
|
||||
assert "[config changed ('master_doc')] 1 added" in app3._status.getvalue()
|
||||
|
||||
# incremental build (extension changed)
|
||||
app4 = make_app(*args, confoverrides={'extensions': ['sphinx.ext.autodoc']}, **kwargs)
|
||||
assert app4.env.config_status == CONFIG_EXTENSIONS_CHANGED
|
||||
app4.build()
|
||||
want_str = "[extensions changed ('sphinx.ext.autodoc')] 1 added"
|
||||
assert want_str in app4._status.getvalue()
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy')
|
||||
|
@@ -500,15 +500,15 @@ def test_autodoc_typehints_none(app):
|
||||
'.. py:module:: target.typehints',
|
||||
'',
|
||||
'',
|
||||
'.. py:class:: Math(s, o = None)',
|
||||
'.. py:class:: Math(s, o=None)',
|
||||
' :module: target.typehints',
|
||||
'',
|
||||
' ',
|
||||
' .. py:method:: Math.incr(a, b = 1) -> int',
|
||||
' .. py:method:: Math.incr(a, b=1)',
|
||||
' :module: target.typehints',
|
||||
' ',
|
||||
'',
|
||||
'.. py:function:: incr(a, b = 1) -> int',
|
||||
'.. py:function:: incr(a, b=1)',
|
||||
' :module: target.typehints',
|
||||
''
|
||||
]
|
||||
|
@@ -10,6 +10,7 @@
|
||||
|
||||
import abc
|
||||
import sys
|
||||
from importlib import import_module
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -56,27 +57,27 @@ def test_mock():
|
||||
submodule = modname + '.submodule'
|
||||
assert modname not in sys.modules
|
||||
with pytest.raises(ImportError):
|
||||
__import__(modname)
|
||||
import_module(modname)
|
||||
|
||||
with mock([modname]):
|
||||
__import__(modname)
|
||||
import_module(modname)
|
||||
assert modname in sys.modules
|
||||
assert isinstance(sys.modules[modname], _MockModule)
|
||||
|
||||
# submodules are also mocked
|
||||
__import__(submodule)
|
||||
import_module(submodule)
|
||||
assert submodule in sys.modules
|
||||
assert isinstance(sys.modules[submodule], _MockModule)
|
||||
|
||||
assert modname not in sys.modules
|
||||
with pytest.raises(ImportError):
|
||||
__import__(modname)
|
||||
import_module(modname)
|
||||
|
||||
|
||||
def test_mock_does_not_follow_upper_modules():
|
||||
with mock(['sphinx.unknown.module']):
|
||||
with pytest.raises(ImportError):
|
||||
__import__('sphinx.unknown')
|
||||
import_module('sphinx.unknown')
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 7), reason='Only for py37 or above')
|
||||
|
@@ -74,7 +74,7 @@ def test_js_source(app, status, warning):
|
||||
|
||||
app.builder.build(['contents'])
|
||||
|
||||
v = '3.2.1'
|
||||
v = '3.4.1'
|
||||
msg = 'jquery.js version does not match to {v}'.format(v=v)
|
||||
jquery_min = (app.outdir / '_static' / 'jquery.js').text()
|
||||
assert 'jQuery v{v}'.format(v=v) in jquery_min, msg
|
||||
|
@@ -195,7 +195,7 @@ def test_Signature_partialmethod():
|
||||
|
||||
def test_Signature_annotations():
|
||||
from typing_test_data import (f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10,
|
||||
f11, f12, f13, f14, f15, f16, f17, f18, Node)
|
||||
f11, f12, f13, f14, f15, f16, f17, f18, f19, Node)
|
||||
|
||||
# Class annotations
|
||||
sig = inspect.Signature(f0).format_args()
|
||||
@@ -275,6 +275,10 @@ def test_Signature_annotations():
|
||||
sig = inspect.Signature(f18).format_args()
|
||||
assert sig == '(self, arg1: Union[int, Tuple] = 10) -> List[Dict]'
|
||||
|
||||
# annotations for variadic and keyword parameters
|
||||
sig = inspect.Signature(f19).format_args()
|
||||
assert sig == '(*args: int, **kwargs: str)'
|
||||
|
||||
# type hints by string
|
||||
sig = inspect.Signature(Node.children).format_args()
|
||||
if (3, 5, 0) <= sys.version_info < (3, 5, 3):
|
||||
@@ -285,6 +289,10 @@ def test_Signature_annotations():
|
||||
sig = inspect.Signature(Node.__init__).format_args()
|
||||
assert sig == '(self, parent: Optional[Node]) -> None'
|
||||
|
||||
# show_annotation is False
|
||||
sig = inspect.Signature(f7).format_args(show_annotation=False)
|
||||
assert sig == '(x=None, y={})'
|
||||
|
||||
|
||||
def test_safe_getattr_with_default():
|
||||
class Foo:
|
||||
|
@@ -92,6 +92,11 @@ def f18(self, arg1: Union[int, Tuple] = 10) -> List[Dict]:
|
||||
pass
|
||||
|
||||
|
||||
def f19(*args: int, **kwargs: str):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class Node:
|
||||
def __init__(self, parent: Optional['Node']) -> None:
|
||||
pass
|
||||
|
3
tox.ini
3
tox.ini
@@ -1,6 +1,6 @@
|
||||
[tox]
|
||||
minversion = 2.4.0
|
||||
envlist = docs,flake8,mypy,coverage,py{35,36,37,38},du{12,13,14}
|
||||
envlist = docs,flake8,mypy,coverage,py{35,36,37,38},du{12,13,14,15}
|
||||
|
||||
[testenv]
|
||||
usedevelop = True
|
||||
@@ -13,6 +13,7 @@ deps =
|
||||
du12: docutils==0.12
|
||||
du13: docutils==0.13.1
|
||||
du14: docutils==0.14
|
||||
du15: docutils==0.15
|
||||
extras =
|
||||
test
|
||||
setenv =
|
||||
|
Reference in New Issue
Block a user