diff options
Diffstat (limited to 'sphinx')
149 files changed, 2259 insertions, 1143 deletions
diff --git a/sphinx/__init__.py b/sphinx/__init__.py index 6a49a226c..8caea80d0 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -32,8 +32,8 @@ if 'PYTHONWARNINGS' not in os.environ: warnings.filterwarnings('ignore', "'U' mode is deprecated", DeprecationWarning, module='docutils.io') -__version__ = '3.0.5+' -__released__ = '3.0.5' # used when Sphinx builds its own docs +__version__ = '3.1.0+' +__released__ = '3.1.0' # used when Sphinx builds its own docs #: Version info for better programmatic use. #: @@ -43,7 +43,7 @@ __released__ = '3.0.5' # used when Sphinx builds its own docs #: #: .. versionadded:: 1.2 #: Before version 1.2, check the string ``sphinx.__version__``. -version_info = (3, 0, 5, 'beta', 0) +version_info = (3, 1, 0, 'beta', 0) package_dir = path.abspath(path.dirname(__file__)) @@ -56,6 +56,7 @@ if __version__.endswith('+'): __version__ = __version__[:-1] # remove '+' for PEP-440 version spec. try: ret = subprocess.run(['git', 'show', '-s', '--pretty=format:%h'], + cwd=package_dir, stdout=PIPE, stderr=PIPE) if ret.stdout: __display_version__ += '/' + ret.stdout.decode('ascii').strip() diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 847a6d715..5e191e989 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -112,6 +112,13 @@ class desc_signature(nodes.Part, nodes.Inline, nodes.TextElement): In that case all child nodes must be ``desc_signature_line`` nodes. """ + @property + def child_text_separator(self): + if self.get('is_multiline'): + return ' ' + else: + return super().child_text_separator + class desc_signature_line(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for a line in a multi-line object signatures. @@ -150,6 +157,9 @@ class desc_parameterlist(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for a general parameter list.""" child_text_separator = ', ' + def astext(self): + return '({})'.format(super().astext()) + class desc_parameter(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for a single parameter.""" diff --git a/sphinx/application.py b/sphinx/application.py index d2fd776ff..bd23c86e7 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -204,7 +204,7 @@ class Sphinx: # notice for parallel build on macOS and py38+ if sys.version_info > (3, 8) and platform.system() == 'Darwin' and parallel > 1: logger.info(bold(__("For security reason, parallel mode is disabled on macOS and " - "python3.8 and above. For more details, please read " + "python3.8 and above. For more details, please read " "https://github.com/sphinx-doc/sphinx/issues/6803"))) # status code for command-line application @@ -436,22 +436,32 @@ class Sphinx: logger.debug('[app] disconnecting event: [id=%s]', listener_id) self.events.disconnect(listener_id) - def emit(self, event: str, *args: Any) -> List: + def emit(self, event: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> List: """Emit *event* and pass *arguments* to the callback functions. Return the return values of all callbacks as a list. Do not emit core Sphinx events in extensions! + + .. versionchanged:: 3.1 + + Added *allowed_exceptions* to specify path-through exceptions """ - return self.events.emit(event, *args) + return self.events.emit(event, *args, allowed_exceptions=allowed_exceptions) - def emit_firstresult(self, event: str, *args: Any) -> Any: + def emit_firstresult(self, event: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> Any: """Emit *event* and pass *arguments* to the callback functions. Return the result of the first callback that doesn't return ``None``. .. versionadded:: 0.5 + .. versionchanged:: 3.1 + + Added *allowed_exceptions* to specify path-through exceptions """ - return self.events.emit_firstresult(event, *args) + return self.events.emit_firstresult(event, *args, + allowed_exceptions=allowed_exceptions) # registering addon parts @@ -958,12 +968,14 @@ class Sphinx: self.add_css_file(filename, **attributes) - def add_latex_package(self, packagename: str, options: str = None) -> None: + def add_latex_package(self, packagename: str, options: str = None, + after_hyperref: bool = False) -> None: r"""Register a package to include in the LaTeX source code. Add *packagename* to the list of packages that LaTeX source code will include. If you provide *options*, it will be taken to `\usepackage` - declaration. + declaration. If you set *after_hyperref* truthy, the package will be + loaded after ``hyperref`` package. .. code-block:: python @@ -973,8 +985,11 @@ class Sphinx: # => \usepackage[foo,bar]{mypackage} .. versionadded:: 1.3 + .. versionadded:: 3.1 + + *after_hyperref* option. """ - self.registry.add_latex_package(packagename, options) + self.registry.add_latex_package(packagename, options, after_hyperref) def add_lexer(self, alias: str, lexer: Union[Lexer, "Type[Lexer]"]) -> None: """Register a new lexer for source code. @@ -990,7 +1005,7 @@ class Sphinx: if isinstance(lexer, Lexer): warnings.warn('app.add_lexer() API changed; ' 'Please give lexer class instead instance', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) lexers[alias] = lexer else: lexer_classes[alias] = lexer diff --git a/sphinx/builders/_epub_base.py b/sphinx/builders/_epub_base.py index b2d8413a8..f26a1ba9f 100644 --- a/sphinx/builders/_epub_base.py +++ b/sphinx/builders/_epub_base.py @@ -173,7 +173,7 @@ class EpubBuilder(StandaloneHTMLBuilder): """Replace all characters not allowed in text an attribute values.""" warnings.warn( '%s.esc() is deprecated. Use html.escape() instead.' % self.__class__.__name__, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) name = name.replace('&', '&') name = name.replace('<', '<') name = name.replace('>', '>') diff --git a/sphinx/builders/applehelp.py b/sphinx/builders/applehelp.py index f081f9fe5..759ba66da 100644 --- a/sphinx/builders/applehelp.py +++ b/sphinx/builders/applehelp.py @@ -32,7 +32,7 @@ deprecated_alias('sphinx.builders.applehelp', def setup(app: Sphinx) -> Dict[str, Any]: warnings.warn('sphinx.builders.applehelp has been moved to sphinxcontrib-applehelp.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) app.setup_extension('sphinxcontrib.applehelp') return { diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py index 463e19b7b..5340c93f9 100644 --- a/sphinx/builders/html/__init__.py +++ b/sphinx/builders/html/__init__.py @@ -881,7 +881,7 @@ class StandaloneHTMLBuilder(Builder): 'The %s.feed() method signature is deprecated. Update to ' '%s.feed(docname, filename, title, doctree).' % ( indexer_name, indexer_name), - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) def _get_local_toctree(self, docname: str, collapse: bool = True, **kwargs: Any) -> str: if 'includehidden' not in kwargs: @@ -1242,6 +1242,9 @@ def setup(app: Sphinx) -> Dict[str, Any]: # load default math renderer app.setup_extension('sphinx.ext.mathjax') + # load transforms for HTML builder + app.setup_extension('sphinx.builders.html.transforms') + return { 'version': 'builtin', 'parallel_read_safe': True, diff --git a/sphinx/builders/html/transforms.py b/sphinx/builders/html/transforms.py new file mode 100644 index 000000000..c91da57e9 --- /dev/null +++ b/sphinx/builders/html/transforms.py @@ -0,0 +1,69 @@ +""" + sphinx.builders.html.transforms + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Transforms for HTML builder. + + :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import re +from typing import Any, Dict + +from docutils import nodes + +from sphinx.application import Sphinx +from sphinx.transforms.post_transforms import SphinxPostTransform +from sphinx.util.nodes import NodeMatcher + + +class KeyboardTransform(SphinxPostTransform): + """Transform :kbd: role to more detailed form. + + Before:: + + <literal class="kbd"> + Control-x + + After:: + + <literal class="kbd"> + <literal class="kbd"> + Control + - + <literal class="kbd"> + x + """ + default_priority = 400 + builders = ('html',) + pattern = re.compile(r'(-|\+|\^|\s+)') + + def run(self, **kwargs: Any) -> None: + matcher = NodeMatcher(nodes.literal, classes=["kbd"]) + for node in self.document.traverse(matcher): # type: nodes.literal + parts = self.pattern.split(node[-1].astext()) + if len(parts) == 1: + continue + + node.pop() + while parts: + key = parts.pop(0) + node += nodes.literal('', key, classes=["kbd"]) + + try: + # key separator (ex. -, +, ^) + sep = parts.pop(0) + node += nodes.Text(sep) + except IndexError: + pass + + +def setup(app: Sphinx) -> Dict[str, Any]: + app.add_post_transform(KeyboardTransform) + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py index 8732de7fd..1d6304d38 100644 --- a/sphinx/builders/htmlhelp.py +++ b/sphinx/builders/htmlhelp.py @@ -32,7 +32,7 @@ deprecated_alias('sphinx.builders.htmlhelp', def setup(app: Sphinx) -> Dict[str, Any]: warnings.warn('sphinx.builders.htmlhelp has been moved to sphinxcontrib-htmlhelp.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) app.setup_extension('sphinxcontrib.htmlhelp') return { diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py index 183708520..88c471675 100644 --- a/sphinx/builders/latex/__init__.py +++ b/sphinx/builders/latex/__init__.py @@ -129,6 +129,7 @@ class LaTeXBuilder(Builder): self.document_data = [] # type: List[Tuple[str, str, str, str, str, bool]] self.themes = ThemeFactory(self.app) self.usepackages = self.app.registry.latex_packages + self.usepackages_after_hyperref = self.app.registry.latex_packages_after_hyperref texescape.init() self.init_context() @@ -180,6 +181,7 @@ class LaTeXBuilder(Builder): # Apply extension settings to context self.context['packages'] = self.usepackages + self.context['packages_after_hyperref'] = self.usepackages_after_hyperref # Apply user settings to context self.context.update(self.config.latex_elements) @@ -314,6 +316,8 @@ class LaTeXBuilder(Builder): self.context['title'] = title self.context['author'] = author self.context['docclass'] = theme.docclass + self.context['papersize'] = theme.papersize + self.context['pointsize'] = theme.pointsize self.context['wrapperclass'] = theme.wrapperclass def assemble_doctree(self, indexfile: str, toctree_only: bool, appendices: List[str]) -> nodes.document: # NOQA @@ -361,7 +365,7 @@ class LaTeXBuilder(Builder): def apply_transforms(self, doctree: nodes.document) -> None: warnings.warn('LaTeXBuilder.apply_transforms() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) def finish(self) -> None: self.copy_image_files() @@ -491,6 +495,20 @@ def validate_config_values(app: Sphinx, config: Config) -> None: config.latex_elements.pop(key) +def validate_latex_theme_options(app: Sphinx, config: Config) -> None: + for key in list(config.latex_theme_options): + if key not in Theme.UPDATABLE_KEYS: + msg = __("Unknown theme option: latex_theme_options[%r], ignored.") + logger.warning(msg % (key,)) + config.latex_theme_options.pop(key) + + +def install_pakcages_for_ja(app: Sphinx) -> None: + """Install packages for Japanese.""" + if app.config.language == 'ja': + app.add_latex_package('pxjahyper', after_hyperref=True) + + def default_latex_engine(config: Config) -> str: """ Better default latex_engine settings for specific languages. """ if config.language == 'ja': @@ -537,6 +555,8 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_builder(LaTeXBuilder) app.connect('config-inited', validate_config_values, priority=800) + app.connect('config-inited', validate_latex_theme_options, priority=800) + app.connect('builder-inited', install_pakcages_for_ja) app.add_config_value('latex_engine', default_latex_engine, None, ENUM('pdflatex', 'xelatex', 'lualatex', 'platex', 'uplatex')) @@ -553,6 +573,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value('latex_elements', {}, None) app.add_config_value('latex_additional_files', [], None) app.add_config_value('latex_theme', 'manual', None, [str]) + app.add_config_value('latex_theme_options', {}, None) app.add_config_value('latex_theme_path', [], None, [list]) app.add_config_value('latex_docclass', default_latex_docclass, None) diff --git a/sphinx/builders/latex/constants.py b/sphinx/builders/latex/constants.py index 9a89036bf..7146079ff 100644 --- a/sphinx/builders/latex/constants.py +++ b/sphinx/builders/latex/constants.py @@ -69,8 +69,8 @@ LUALATEX_DEFAULT_FONTPKG = XELATEX_DEFAULT_FONTPKG DEFAULT_SETTINGS = { 'latex_engine': 'pdflatex', - 'papersize': 'letterpaper', - 'pointsize': '10pt', + 'papersize': '', + 'pointsize': '', 'pxunit': '.75bp', 'classoptions': '', 'extraclassoptions': '', diff --git a/sphinx/builders/latex/theming.py b/sphinx/builders/latex/theming.py index 56f2735f0..da6a7fa04 100644 --- a/sphinx/builders/latex/theming.py +++ b/sphinx/builders/latex/theming.py @@ -24,61 +24,80 @@ logger = logging.getLogger(__name__) class Theme: """A set of LaTeX configurations.""" + LATEX_ELEMENTS_KEYS = ['papersize', 'pointsize'] + UPDATABLE_KEYS = ['papersize', 'pointsize'] + def __init__(self, name: str) -> None: self.name = name self.docclass = name self.wrapperclass = name + self.papersize = 'letterpaper' + self.pointsize = '10pt' self.toplevel_sectioning = 'chapter' + def update(self, config: Config) -> None: + """Override theme settings by user's configuration.""" + for key in self.LATEX_ELEMENTS_KEYS: + if config.latex_elements.get(key): + value = config.latex_elements[key] + setattr(self, key, value) + + for key in self.UPDATABLE_KEYS: + if key in config.latex_theme_options: + value = config.latex_theme_options[key] + setattr(self, key, value) + class BuiltInTheme(Theme): """A built-in LaTeX theme.""" def __init__(self, name: str, config: Config) -> None: - # Note: Don't call supermethod here. - self.name = name - self.latex_docclass = config.latex_docclass # type: Dict[str, str] + super().__init__(name) - @property - def docclass(self) -> str: # type: ignore - if self.name == 'howto': - return self.latex_docclass.get('howto', 'article') + if name == 'howto': + self.docclass = config.latex_docclass.get('howto', 'article') else: - return self.latex_docclass.get('manual', 'report') + self.docclass = config.latex_docclass.get('manual', 'report') - @property - def wrapperclass(self) -> str: # type: ignore - if self.name in ('manual', 'howto'): - return 'sphinx' + self.name + if name in ('manual', 'howto'): + self.wrapperclass = 'sphinx' + name else: - return self.name + self.wrapperclass = name - @property - def toplevel_sectioning(self) -> str: # type: ignore # we assume LaTeX class provides \chapter command except in case # of non-Japanese 'howto' case - if self.name == 'howto' and not self.docclass.startswith('j'): - return 'section' + if name == 'howto' and not self.docclass.startswith('j'): + self.toplevel_sectioning = 'section' else: - return 'chapter' + self.toplevel_sectioning = 'chapter' class UserTheme(Theme): """A user defined LaTeX theme.""" + REQUIRED_CONFIG_KEYS = ['docclass', 'wrapperclass'] + OPTIONAL_CONFIG_KEYS = ['papersize', 'pointsize', 'toplevel_sectioning'] + def __init__(self, name: str, filename: str) -> None: - self.name = name + super().__init__(name) self.config = configparser.RawConfigParser() self.config.read(path.join(filename)) - try: - self.docclass = self.config.get('theme', 'docclass') - self.wrapperclass = self.config.get('theme', 'wrapperclass') - self.toplevel_sectioning = self.config.get('theme', 'toplevel_sectioning') - except configparser.NoSectionError: - raise ThemeError(__('%r doesn\'t have "theme" setting') % filename) - except configparser.NoOptionError as exc: - raise ThemeError(__('%r doesn\'t have "%s" setting') % (filename, exc.args[0])) + for key in self.REQUIRED_CONFIG_KEYS: + try: + value = self.config.get('theme', key) + setattr(self, key, value) + except configparser.NoSectionError: + raise ThemeError(__('%r doesn\'t have "theme" setting') % filename) + except configparser.NoOptionError as exc: + raise ThemeError(__('%r doesn\'t have "%s" setting') % (filename, exc.args[0])) + + for key in self.OPTIONAL_CONFIG_KEYS: + try: + value = self.config.get('theme', key) + setattr(self, key, value) + except configparser.NoOptionError: + pass class ThemeFactory: @@ -87,6 +106,7 @@ class ThemeFactory: def __init__(self, app: Sphinx) -> None: self.themes = {} # type: Dict[str, Theme] self.theme_paths = [path.join(app.srcdir, p) for p in app.config.latex_theme_path] + self.config = app.config self.load_builtin_themes(app.config) def load_builtin_themes(self, config: Config) -> None: @@ -97,13 +117,14 @@ class ThemeFactory: def get(self, name: str) -> Theme: """Get a theme for given *name*.""" if name in self.themes: - return self.themes[name] + theme = self.themes[name] else: theme = self.find_user_theme(name) - if theme: - return theme - else: - return Theme(name) + if not theme: + theme = Theme(name) + + theme.update(self.config) + return theme def find_user_theme(self, name: str) -> Theme: """Find a theme named as *name* from latex_theme_path.""" diff --git a/sphinx/builders/latex/util.py b/sphinx/builders/latex/util.py index b7d79121c..0e3eb739d 100644 --- a/sphinx/builders/latex/util.py +++ b/sphinx/builders/latex/util.py @@ -8,6 +8,8 @@ :license: BSD, see LICENSE for details. """ +from typing import Optional + from docutils.writers.latex2e import Babel @@ -40,7 +42,7 @@ class ExtBabel(Babel): self.supported = False return 'english' # fallback to english - def get_mainlanguage_options(self) -> str: + def get_mainlanguage_options(self) -> Optional[str]: """Return options for polyglossia's ``\\setmainlanguage``.""" if self.use_polyglossia is False: return None diff --git a/sphinx/cmd/build.py b/sphinx/cmd/build.py index cf50f1730..c4cf11cc4 100644 --- a/sphinx/cmd/build.py +++ b/sphinx/cmd/build.py @@ -64,7 +64,7 @@ def handle_exception(app: Sphinx, args: Any, exception: BaseException, stderr: I print(terminal_safe(str(exception)), file=stderr) print(file=stderr) print(__('This can happen with very large or deeply nested source ' - 'files. You can carefully increase the default Python ' + 'files. You can carefully increase the default Python ' 'recursion limit of 1000 in conf.py with e.g.:'), file=stderr) print(' import sys; sys.setrecursionlimit(1500)', file=stderr) else: @@ -107,7 +107,7 @@ Generate documentation from source files. sphinx-build generates documentation from the files in SOURCEDIR and places it in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration -settings. The 'sphinx-quickstart' tool may be used to generate template files, +settings. The 'sphinx-quickstart' tool may be used to generate template files, including 'conf.py' sphinx-build can create documentation in different formats. A format is diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py index 8f8ae58a1..cad3c65e5 100644 --- a/sphinx/cmd/quickstart.py +++ b/sphinx/cmd/quickstart.py @@ -187,7 +187,7 @@ def do_prompt(text: str, default: str = None, validator: Callable[[str], Any] = def convert_python_source(source: str, rex: Pattern = re.compile(r"[uU]('.*?')")) -> str: # remove Unicode literal prefixes warnings.warn('convert_python_source() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) return rex.sub('\\1', source) @@ -275,7 +275,7 @@ def ask_user(d: Dict) -> None: print(__('Sphinx has the notion of a "version" and a "release" for the\n' 'software. Each version can have multiple releases. For example, for\n' 'Python the version is something like 2.5 or 3.0, while the release is\n' - 'something like 2.5.1 or 3.0a1. If you don\'t need this dual structure,\n' + 'something like 2.5.1 or 3.0a1. If you don\'t need this dual structure,\n' 'just set both to the same value.')) d['version'] = do_prompt(__('Project version'), '', allow_empty) if 'release' not in d: @@ -296,7 +296,7 @@ def ask_user(d: Dict) -> None: if 'suffix' not in d: print() print(__('The file name suffix for source files. Commonly, this is either ".txt"\n' - 'or ".rst". Only files with this suffix are considered documents.')) + 'or ".rst". Only files with this suffix are considered documents.')) d['suffix'] = do_prompt(__('Source file suffix'), '.rst', suffix) if 'master' not in d: @@ -357,6 +357,7 @@ def generate(d: Dict, overwrite: bool = True, silent: bool = False, templatedir: d.setdefault('extensions', []) d['copyright'] = time.strftime('%Y') + ', ' + d['author'] + d["path"] = os.path.abspath(d['path']) ensuredir(d['path']) srcdir = path.join(d['path'], 'source') if d['sep'] else d['path'] diff --git a/sphinx/config.py b/sphinx/config.py index 19a8f6c4f..6e6c256c5 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -444,7 +444,7 @@ def check_unicode(config: Config) -> None: since that can result in UnicodeErrors all over the place """ warnings.warn('sphinx.config.check_unicode() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) nonascii_re = re.compile(br'[\x80-\xff]') diff --git a/sphinx/deprecation.py b/sphinx/deprecation.py index 8e3e47f0b..6f0fb2db4 100644 --- a/sphinx/deprecation.py +++ b/sphinx/deprecation.py @@ -76,6 +76,6 @@ class DeprecatedDict(dict): warnings.warn(self.message, self.warning, stacklevel=2) return super().get(key, default) - def update(self, other: Dict = None) -> None: # type: ignore + def update(self, other: Dict) -> None: # type: ignore warnings.warn(self.message, self.warning, stacklevel=2) super().update(other) diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index eab0928f9..36a8f1f65 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -10,7 +10,7 @@ import re from typing import ( - Any, Callable, Dict, Iterator, List, Type, Tuple, Union + Any, Callable, Dict, Generator, Iterator, List, Type, Tuple, Union ) from typing import cast @@ -31,10 +31,12 @@ from sphinx.util.cfamily import ( NoOldIdError, ASTBaseBase, verify_description_mode, StringifyTransform, BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral, identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re, - hex_literal_re, binary_literal_re, float_literal_re, + hex_literal_re, binary_literal_re, integers_literal_suffix_re, + float_literal_re, float_literal_suffix_re, char_literal_re ) from sphinx.util.docfields import Field, TypedField +from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import make_refnode logger = logging.getLogger(__name__) @@ -184,11 +186,17 @@ class ASTNestedName(ASTBase): # If lastIsName, then wrap all of the prefix in a desc_addname, # else append directly to signode. # TODO: also for C? - # NOTE: Breathe relies on the prefix being in the desc_addname node, + # NOTE: Breathe previously relied on the prefix being in the desc_addname node, # so it can remove it in inner declarations. dest = signode if mode == 'lastIsName': dest = addnodes.desc_addname() + if self.rooted: + prefix += '.' + if mode == 'lastIsName' and len(names) == 0: + signode += nodes.Text('.') + else: + dest += nodes.Text('.') for i in range(len(names)): ident = names[i] if not first: @@ -339,7 +347,7 @@ class ASTPostfixCallExpr(ASTPostfixOp): class ASTPostfixArray(ASTPostfixOp): - def __init__(self, expr): + def __init__(self, expr: ASTExpression) -> None: self.expr = expr def _stringify(self, transform: StringifyTransform) -> str: @@ -1311,10 +1319,12 @@ class ASTEnumerator(ASTBase): class ASTDeclaration(ASTBaseBase): - def __init__(self, objectType: str, directiveType: str, declaration: Any) -> None: + def __init__(self, objectType: str, directiveType: str, declaration: Any, + semicolon: bool = False) -> None: self.objectType = objectType self.directiveType = directiveType self.declaration = declaration + self.semicolon = semicolon self.symbol = None # type: Symbol # set by CObject._add_enumerator_to_parent @@ -1343,7 +1353,10 @@ class ASTDeclaration(ASTBaseBase): return self.get_id(_max_id, True) def _stringify(self, transform: StringifyTransform) -> str: - return transform(self.declaration) + res = transform(self.declaration) + if self.semicolon: + res += ';' + return res def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", options: Dict) -> None: @@ -1379,6 +1392,8 @@ class ASTDeclaration(ASTBaseBase): else: assert False self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol) + if self.semicolon: + mainDeclNode += nodes.Text(';') class SymbolLookupResult: @@ -1393,7 +1408,7 @@ class LookupKey: def __init__(self, data: List[Tuple[ASTIdentifier, str]]) -> None: self.data = data - def __str__(self): + def __str__(self) -> str: return '[{}]'.format(', '.join("({}, {})".format( ident, id_) for ident, id_ in self.data)) @@ -1418,7 +1433,7 @@ class Symbol: if self.declaration: assert self.docname - def __setattr__(self, key, value): + def __setattr__(self, key: str, value: Any) -> None: if key == "children": assert False else: @@ -1580,7 +1595,7 @@ class Symbol: Symbol.debug_print("recurseInAnon: ", recurseInAnon) Symbol.debug_print("searchInSiblings: ", searchInSiblings) - def candidates(): + def candidates() -> Generator["Symbol", None, None]: s = self if Symbol.debug_lookup: Symbol.debug_print("searching in self:") @@ -1772,7 +1787,7 @@ class Symbol: # First check if one of those with a declaration matches. # If it's a function, we need to compare IDs, # otherwise there should be only one symbol with a declaration. - def makeCandSymbol(): + def makeCandSymbol() -> "Symbol": if Symbol.debug_lookup: Symbol.debug_print("begin: creating candidate symbol") symbol = Symbol(parent=lookupResult.parentSymbol, @@ -1788,7 +1803,7 @@ class Symbol: else: candSymbol = makeCandSymbol() - def handleDuplicateDeclaration(symbol, candSymbol): + def handleDuplicateDeclaration(symbol: "Symbol", candSymbol: "Symbol") -> None: if Symbol.debug_lookup: Symbol.debug_indent += 1 Symbol.debug_print("redeclaration") @@ -2068,12 +2083,14 @@ class DefinitionParser(BaseParser): return ASTBooleanLiteral(True) if self.skip_word('false'): return ASTBooleanLiteral(False) - for regex in [float_literal_re, binary_literal_re, hex_literal_re, + pos = self.pos + if self.match(float_literal_re): + self.match(float_literal_suffix_re) + return ASTNumberLiteral(self.definition[pos:self.pos]) + for regex in [binary_literal_re, hex_literal_re, integer_literal_re, octal_literal_re]: - pos = self.pos if self.match(regex): - while self.current_char in 'uUlLfF': - self.pos += 1 + self.match(integers_literal_suffix_re) return ASTNumberLiteral(self.definition[pos:self.pos]) string = self._parse_string() @@ -2338,7 +2355,7 @@ class DefinitionParser(BaseParser): return ASTBinOpExpr(exprs, ops) return _parse_bin_op_expr(self, 0) - def _parse_conditional_expression_tail(self, orExprHead): + def _parse_conditional_expression_tail(self, orExprHead: Any) -> ASTExpression: # -> "?" expression ":" assignment-expression return None @@ -2808,7 +2825,7 @@ class DefinitionParser(BaseParser): declSpecs = self._parse_decl_specs(outer=outer, typed=False) decl = self._parse_declarator(named=True, paramMode=outer, typed=False) - self.assert_end() + self.assert_end(allowSemicolon=True) except DefinitionError as exUntyped: desc = "If just a name" prevErrors.append((exUntyped, desc)) @@ -2907,7 +2924,7 @@ class DefinitionParser(BaseParser): if self.skip_string('='): self.skip_ws() - def parser(): + def parser() -> ASTExpression: return self._parse_constant_expression() initVal = self._parse_expression_fallback([], parser) @@ -2941,7 +2958,15 @@ class DefinitionParser(BaseParser): declaration = self._parse_type(named=True, outer='type') else: assert False - return ASTDeclaration(objectType, directiveType, declaration) + if objectType != 'macro': + self.skip_ws() + semicolon = self.skip_string(';') + else: + semicolon = False + return ASTDeclaration(objectType, directiveType, declaration, semicolon) + + def parse_namespace_object(self) -> ASTNestedName: + return self._parse_nested_name() def parse_xref_object(self) -> ASTNestedName: name = self._parse_nested_name() @@ -3193,6 +3218,97 @@ class CTypeObject(CObject): object_type = 'type' +class CNamespaceObject(SphinxDirective): + """ + This directive is just to tell Sphinx that we're documenting stuff in + namespace foo. + """ + + has_content = False + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = True + option_spec = {} # type: Dict + + def run(self) -> List[Node]: + rootSymbol = self.env.domaindata['c']['root_symbol'] + if self.arguments[0].strip() in ('NULL', '0', 'nullptr'): + symbol = rootSymbol + stack = [] # type: List[Symbol] + else: + parser = DefinitionParser(self.arguments[0], + location=self.get_source_info(), + config=self.env.config) + try: + name = parser.parse_namespace_object() + parser.assert_end() + except DefinitionError as e: + logger.warning(e, location=self.get_source_info()) + name = _make_phony_error_name() + symbol = rootSymbol.add_name(name) + stack = [symbol] + self.env.temp_data['c:parent_symbol'] = symbol + self.env.temp_data['c:namespace_stack'] = stack + self.env.ref_context['c:parent_key'] = symbol.get_lookup_key() + return [] + + +class CNamespacePushObject(SphinxDirective): + has_content = False + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = True + option_spec = {} # type: Dict + + def run(self) -> List[Node]: + if self.arguments[0].strip() in ('NULL', '0', 'nullptr'): + return [] + parser = DefinitionParser(self.arguments[0], + location=self.get_source_info(), + config=self.env.config) + try: + name = parser.parse_namespace_object() + parser.assert_end() + except DefinitionError as e: + logger.warning(e, location=self.get_source_info()) + name = _make_phony_error_name() + oldParent = self.env.temp_data.get('c:parent_symbol', None) + if not oldParent: + oldParent = self.env.domaindata['c']['root_symbol'] + symbol = oldParent.add_name(name) + stack = self.env.temp_data.get('c:namespace_stack', []) + stack.append(symbol) + self.env.temp_data['c:parent_symbol'] = symbol + self.env.temp_data['c:namespace_stack'] = stack + self.env.ref_context['c:parent_key'] = symbol.get_lookup_key() + return [] + + +class CNamespacePopObject(SphinxDirective): + has_content = False + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = True + option_spec = {} # type: Dict + + def run(self) -> List[Node]: + stack = self.env.temp_data.get('c:namespace_stack', None) + if not stack or len(stack) == 0: + logger.warning("C namespace pop on empty stack. Defaulting to gobal scope.", + location=self.get_source_info()) + stack = [] + else: + stack.pop() + if len(stack) > 0: + symbol = stack[-1] + else: + symbol = self.env.domaindata['c']['root_symbol'] + self.env.temp_data['c:parent_symbol'] = symbol + self.env.temp_data['c:namespace_stack'] = stack + self.env.ref_context['cp:parent_key'] = symbol.get_lookup_key() + return [] + + class CXRefRole(XRefRole): def process_link(self, env: BuildEnvironment, refnode: Element, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]: @@ -3272,6 +3388,10 @@ class CDomain(Domain): 'enum': CEnumObject, 'enumerator': CEnumeratorObject, 'type': CTypeObject, + # scope control + 'namespace': CNamespaceObject, + 'namespace-push': CNamespacePushObject, + 'namespace-pop': CNamespacePopObject, } roles = { 'member': CXRefRole(), diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 1be840e51..dca69bace 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -10,7 +10,7 @@ import re from typing import ( - Any, Callable, Dict, Iterator, List, Tuple, Type, TypeVar, Union + Any, Callable, Dict, Generator, Iterator, List, Tuple, Type, TypeVar, Union, Optional ) from docutils import nodes @@ -34,7 +34,8 @@ from sphinx.util.cfamily import ( NoOldIdError, ASTBaseBase, ASTAttribute, verify_description_mode, StringifyTransform, BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral, identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re, - hex_literal_re, binary_literal_re, float_literal_re, + hex_literal_re, binary_literal_re, integers_literal_suffix_re, + float_literal_re, float_literal_suffix_re, char_literal_re ) from sphinx.util.docfields import Field, GroupedField @@ -109,7 +110,8 @@ T = TypeVar('T') simple-declaration -> attribute-specifier-seq[opt] decl-specifier-seq[opt] init-declarator-list[opt] ; - # Drop the semi-colon. For now: drop the attributes (TODO). + # Make the semicolon optional. + # For now: drop the attributes (TODO). # Use at most 1 init-declarator. -> decl-specifier-seq init-declarator -> decl-specifier-seq declarator initializer @@ -295,6 +297,9 @@ T = TypeVar('T') nested-name """ +udl_identifier_re = re.compile(r'''(?x) + [a-zA-Z_][a-zA-Z0-9_]*\b # note, no word boundary in the beginning +''') _string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'" r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S) _visibility_re = re.compile(r'\b(public|private|protected)\b') @@ -606,8 +611,7 @@ class ASTIdentifier(ASTBase): reftype='identifier', reftarget=targetText, modname=None, classname=None) - key = symbol.get_lookup_key() - pnode['cpp:parent_key'] = key + pnode['cpp:parent_key'] = symbol.get_lookup_key() if self.is_anon(): pnode += nodes.strong(text="[anonymous]") else: @@ -623,6 +627,19 @@ class ASTIdentifier(ASTBase): signode += nodes.strong(text="[anonymous]") else: signode += nodes.Text(self.identifier) + elif mode == 'udl': + # the target is 'operator""id' instead of just 'id' + assert len(prefix) == 0 + assert len(templateArgs) == 0 + assert not self.is_anon() + targetText = 'operator""' + self.identifier + pnode = addnodes.pending_xref('', refdomain='cpp', + reftype='identifier', + reftarget=targetText, modname=None, + classname=None) + pnode['cpp:parent_key'] = symbol.get_lookup_key() + pnode += nodes.Text(self.identifier) + signode += pnode else: raise Exception('Unknown description mode: %s' % mode) @@ -735,11 +752,17 @@ class ASTNestedName(ASTBase): names = self.names[:-1] if mode == 'lastIsName' else self.names # If lastIsName, then wrap all of the prefix in a desc_addname, # else append directly to signode. - # NOTE: Breathe relies on the prefix being in the desc_addname node, + # NOTE: Breathe previously relied on the prefix being in the desc_addname node, # so it can remove it in inner declarations. dest = signode if mode == 'lastIsName': dest = addnodes.desc_addname() + if self.rooted: + prefix += '::' + if mode == 'lastIsName' and len(names) == 0: + signode += nodes.Text('::') + else: + dest += nodes.Text('::') for i in range(len(names)): nne = names[i] template = self.templates[i] @@ -829,6 +852,7 @@ class ASTNumberLiteral(ASTLiteral): return self.data def get_id(self, version: int) -> str: + # TODO: floats should be mangled by writing the hex of the binary representation return "L%sE" % self.data def describe_signature(self, signode: TextElement, mode: str, @@ -873,6 +897,7 @@ class ASTCharLiteral(ASTLiteral): return self.prefix + "'" + self.data + "'" def get_id(self, version: int) -> str: + # TODO: the ID should be have L E around it return self.type + str(self.value) def describe_signature(self, signode: TextElement, mode: str, @@ -881,6 +906,26 @@ class ASTCharLiteral(ASTLiteral): signode.append(nodes.Text(txt, txt)) +class ASTUserDefinedLiteral(ASTLiteral): + def __init__(self, literal: ASTLiteral, ident: ASTIdentifier): + self.literal = literal + self.ident = ident + + def _stringify(self, transform: StringifyTransform) -> str: + return transform(self.literal) + transform(self.ident) + + def get_id(self, version: int) -> str: + # mangle as if it was a function call: ident(literal) + return 'clL_Zli{}E{}E'.format(self.ident.get_id(version), self.literal.get_id(version)) + + def describe_signature(self, signode: TextElement, mode: str, + env: "BuildEnvironment", symbol: "Symbol") -> None: + self.literal.describe_signature(signode, mode, env, symbol) + self.ident.describe_signature(signode, "udl", env, "", "", symbol) + + +################################################################################ + class ASTThisLiteral(ASTExpression): def _stringify(self, transform: StringifyTransform) -> str: return "this" @@ -1266,7 +1311,7 @@ class ASTNoexceptExpr(ASTExpression): self.expr = expr def _stringify(self, transform: StringifyTransform) -> str: - return "noexcept(" + transform(self.expr) + ")" + return 'noexcept(' + transform(self.expr) + ')' def get_id(self, version: int) -> str: return 'nx' + self.expr.get_id(version) @@ -1812,15 +1857,34 @@ class ASTFunctionParameter(ASTBase): self.arg.describe_signature(signode, mode, env, symbol=symbol) +class ASTNoexceptSpec(ASTBase): + def __init__(self, expr: Optional[ASTExpression]): + self.expr = expr + + def _stringify(self, transform: StringifyTransform) -> str: + if self.expr: + return 'noexcept(' + transform(self.expr) + ')' + return 'noexcept' + + def describe_signature(self, signode: TextElement, mode: str, + env: "BuildEnvironment", symbol: "Symbol") -> None: + signode += addnodes.desc_annotation('noexcept', 'noexcept') + if self.expr: + signode.append(nodes.Text('(')) + self.expr.describe_signature(signode, mode, env, symbol) + signode.append(nodes.Text(')')) + + class ASTParametersQualifiers(ASTBase): - def __init__(self, args: List[ASTFunctionParameter], - volatile: bool, const: bool, refQual: str, - exceptionSpec: str, override: bool, final: bool, initializer: str) -> None: + def __init__(self, args: List[ASTFunctionParameter], volatile: bool, const: bool, + refQual: str, exceptionSpec: ASTNoexceptSpec, trailingReturn: "ASTType", + override: bool, final: bool, initializer: str) -> None: self.args = args self.volatile = volatile self.const = const self.refQual = refQual self.exceptionSpec = exceptionSpec + self.trailingReturn = trailingReturn self.override = override self.final = final self.initializer = initializer @@ -1874,7 +1938,10 @@ class ASTParametersQualifiers(ASTBase): res.append(self.refQual) if self.exceptionSpec: res.append(' ') - res.append(str(self.exceptionSpec)) + res.append(transform(self.exceptionSpec)) + if self.trailingReturn: + res.append(' -> ') + res.append(transform(self.trailingReturn)) if self.final: res.append(' final') if self.override: @@ -1911,7 +1978,11 @@ class ASTParametersQualifiers(ASTBase): if self.refQual: _add_text(signode, self.refQual) if self.exceptionSpec: - _add_anno(signode, str(self.exceptionSpec)) + signode += nodes.Text(' ') + self.exceptionSpec.describe_signature(signode, mode, env, symbol) + if self.trailingReturn: + signode += nodes.Text(' -> ') + self.trailingReturn.describe_signature(signode, mode, env, symbol) if self.final: _add_anno(signode, 'final') if self.override: @@ -2121,6 +2192,10 @@ class ASTDeclarator(ASTBase): def function_params(self) -> List[ASTFunctionParameter]: raise NotImplementedError(repr(self)) + @property + def trailingReturn(self) -> "ASTType": + raise NotImplementedError(repr(self)) + def require_space_after_declSpecs(self) -> bool: raise NotImplementedError(repr(self)) @@ -2164,6 +2239,10 @@ class ASTDeclaratorNameParamQual(ASTDeclarator): def function_params(self) -> List[ASTFunctionParameter]: return self.paramQual.function_params + @property + def trailingReturn(self) -> "ASTType": + return self.paramQual.trailingReturn + # only the modifiers for a function, e.g., def get_modifiers_id(self, version: int) -> str: # cv-qualifiers @@ -2281,6 +2360,10 @@ class ASTDeclaratorPtr(ASTDeclarator): def function_params(self) -> List[ASTFunctionParameter]: return self.next.function_params + @property + def trailingReturn(self) -> "ASTType": + return self.next.trailingReturn + def require_space_after_declSpecs(self) -> bool: return self.next.require_space_after_declSpecs() @@ -2380,6 +2463,10 @@ class ASTDeclaratorRef(ASTDeclarator): def function_params(self) -> List[ASTFunctionParameter]: return self.next.function_params + @property + def trailingReturn(self) -> "ASTType": + return self.next.trailingReturn + def require_space_after_declSpecs(self) -> bool: return self.next.require_space_after_declSpecs() @@ -2436,6 +2523,10 @@ class ASTDeclaratorParamPack(ASTDeclarator): def function_params(self) -> List[ASTFunctionParameter]: return self.next.function_params + @property + def trailingReturn(self) -> "ASTType": + return self.next.trailingReturn + def require_space_after_declSpecs(self) -> bool: return False @@ -2492,6 +2583,10 @@ class ASTDeclaratorMemPtr(ASTDeclarator): def function_params(self) -> List[ASTFunctionParameter]: return self.next.function_params + @property + def trailingReturn(self) -> "ASTType": + return self.next.trailingReturn + def require_space_after_declSpecs(self) -> bool: return True @@ -2580,6 +2675,10 @@ class ASTDeclaratorParen(ASTDeclarator): def function_params(self) -> List[ASTFunctionParameter]: return self.inner.function_params + @property + def trailingReturn(self) -> "ASTType": + return self.inner.trailingReturn + def require_space_after_declSpecs(self) -> bool: return True @@ -2708,6 +2807,10 @@ class ASTType(ASTBase): def function_params(self) -> List[ASTFunctionParameter]: return self.decl.function_params + @property + def trailingReturn(self) -> "ASTType": + return self.decl.trailingReturn + def get_id(self, version: int, objectType: str = None, symbol: "Symbol" = None) -> str: if version == 1: @@ -2744,7 +2847,10 @@ class ASTType(ASTBase): templ = symbol.declaration.templatePrefix if templ is not None: typeId = self.decl.get_ptr_suffix_id(version) - returnTypeId = self.declSpecs.get_id(version) + if self.trailingReturn: + returnTypeId = self.trailingReturn.get_id(version) + else: + returnTypeId = self.declSpecs.get_id(version) res.append(typeId) res.append(returnTypeId) res.append(self.decl.get_param_id(version)) @@ -3465,12 +3571,14 @@ class ASTTemplateDeclarationPrefix(ASTBase): class ASTDeclaration(ASTBase): def __init__(self, objectType: str, directiveType: str, visibility: str, - templatePrefix: ASTTemplateDeclarationPrefix, declaration: Any) -> None: + templatePrefix: ASTTemplateDeclarationPrefix, declaration: Any, + semicolon: bool = False) -> None: self.objectType = objectType self.directiveType = directiveType self.visibility = visibility self.templatePrefix = templatePrefix self.declaration = declaration + self.semicolon = semicolon self.symbol = None # type: Symbol # set by CPPObject._add_enumerator_to_parent @@ -3483,7 +3591,7 @@ class ASTDeclaration(ASTBase): templatePrefixClone = None return ASTDeclaration(self.objectType, self.directiveType, self.visibility, templatePrefixClone, - self.declaration.clone()) + self.declaration.clone(), self.semicolon) @property def name(self) -> ASTNestedName: @@ -3525,6 +3633,8 @@ class ASTDeclaration(ASTBase): if self.templatePrefix: res.append(transform(self.templatePrefix)) res.append(transform(self.declaration)) + if self.semicolon: + res.append(';') return ''.join(res) def describe_signature(self, signode: desc_signature, mode: str, @@ -3578,6 +3688,8 @@ class ASTDeclaration(ASTBase): else: assert False self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol) + if self.semicolon: + mainDeclNode += nodes.Text(';') class ASTNamespace(ASTBase): @@ -3616,8 +3728,8 @@ class LookupKey: class Symbol: debug_indent = 0 debug_indent_string = " " - debug_lookup = False - debug_show_tree = False + debug_lookup = False # overridden by the corresponding config value + debug_show_tree = False # overridden by the corresponding config value @staticmethod def debug_print(*args: Any) -> None: @@ -3636,7 +3748,7 @@ class Symbol: if self.declaration: assert self.docname - def __setattr__(self, key, value): + def __setattr__(self, key: str, value: Any) -> None: if key == "children": assert False else: @@ -3748,7 +3860,7 @@ class Symbol: yield s @property - def children_recurse_anon(self): + def children_recurse_anon(self) -> Generator["Symbol", None, None]: for c in self._children: yield c if not c.identOrOp.is_anon(): @@ -3855,7 +3967,7 @@ class Symbol: if not isSpecialization(): templateArgs = None - def matches(s): + def matches(s: "Symbol") -> bool: if s.identOrOp != identOrOp: return False if (s.templateParams is None) != (templateParams is None): @@ -3877,7 +3989,7 @@ class Symbol: return False return True - def candidates(): + def candidates() -> Generator[Symbol, None, None]: s = self if Symbol.debug_lookup: Symbol.debug_print("searching in self:") @@ -4139,7 +4251,7 @@ class Symbol: # First check if one of those with a declaration matches. # If it's a function, we need to compare IDs, # otherwise there should be only one symbol with a declaration. - def makeCandSymbol(): + def makeCandSymbol() -> "Symbol": if Symbol.debug_lookup: Symbol.debug_print("begin: creating candidate symbol") symbol = Symbol(parent=lookupResult.parentSymbol, @@ -4156,7 +4268,7 @@ class Symbol: else: candSymbol = makeCandSymbol() - def handleDuplicateDeclaration(symbol, candSymbol): + def handleDuplicateDeclaration(symbol: "Symbol", candSymbol: "Symbol") -> None: if Symbol.debug_lookup: Symbol.debug_indent += 1 Symbol.debug_print("redeclaration") @@ -4625,6 +4737,15 @@ class DefinitionParser(BaseParser): # | boolean-literal -> "false" | "true" # | pointer-literal -> "nullptr" # | user-defined-literal + + def _udl(literal: ASTLiteral) -> ASTLiteral: + if not self.match(udl_identifier_re): + return literal + # hmm, should we care if it's a keyword? + # it looks like GCC does not disallow keywords + ident = ASTIdentifier(self.matched_text) + return ASTUserDefinedLiteral(literal, ident) + self.skip_ws() if self.skip_word('nullptr'): return ASTPointerLiteral() @@ -4632,31 +4753,40 @@ class DefinitionParser(BaseParser): return ASTBooleanLiteral(True) if self.skip_word('false'): return ASTBooleanLiteral(False) - for regex in [float_literal_re, binary_literal_re, hex_literal_re, + pos = self.pos + if self.match(float_literal_re): + hasSuffix = self.match(float_literal_suffix_re) + floatLit = ASTNumberLiteral(self.definition[pos:self.pos]) + if hasSuffix: + return floatLit + else: + return _udl(floatLit) + for regex in [binary_literal_re, hex_literal_re, integer_literal_re, octal_literal_re]: - pos = self.pos if self.match(regex): - while self.current_char in 'uUlLfF': - self.pos += 1 - return ASTNumberLiteral(self.definition[pos:self.pos]) + hasSuffix = self.match(integers_literal_suffix_re) + intLit = ASTNumberLiteral(self.definition[pos:self.pos]) + if hasSuffix: + return intLit + else: + return _udl(intLit) string = self._parse_string() if string is not None: - return ASTStringLiteral(string) + return _udl(ASTStringLiteral(string)) # character-literal if self.match(char_literal_re): prefix = self.last_match.group(1) # may be None when no prefix data = self.last_match.group(2) try: - return ASTCharLiteral(prefix, data) + charLit = ASTCharLiteral(prefix, data) except UnicodeDecodeError as e: self.fail("Can not handle character literal. Internal error was: %s" % e) except UnsupportedMultiCharacterCharLiteral: self.fail("Can not handle character literal" " resulting in multiple decoded characters.") - - # TODO: user-defined lit + return _udl(charLit) return None def _parse_fold_or_paren_expression(self) -> ASTExpression: @@ -4852,7 +4982,7 @@ class DefinitionParser(BaseParser): if not self.skip_string("("): self.fail("Expected '(' in '%s'." % cast) - def parser(): + def parser() -> ASTExpression: return self._parse_expression() expr = self._parse_expression_fallback([')'], parser) self.skip_ws() @@ -4873,7 +5003,7 @@ class DefinitionParser(BaseParser): self.pos = pos try: - def parser(): + def parser() -> ASTExpression: return self._parse_expression() expr = self._parse_expression_fallback([')'], parser) prefix = ASTTypeId(expr, isType=False) @@ -5131,7 +5261,7 @@ class DefinitionParser(BaseParser): return ASTBinOpExpr(exprs, ops) return _parse_bin_op_expr(self, 0, inTemplate=inTemplate) - def _parse_conditional_expression_tail(self, orExprHead): + def _parse_conditional_expression_tail(self, orExprHead: Any) -> None: # -> "?" expression ":" assignment-expression return None @@ -5493,15 +5623,22 @@ class DefinitionParser(BaseParser): refQual = '&' exceptionSpec = None - override = None - final = None - initializer = None self.skip_ws() if self.skip_string('noexcept'): - exceptionSpec = 'noexcept' - self.skip_ws() - if self.skip_string('('): - self.fail('Parameterised "noexcept" not yet implemented.') + if self.skip_string_and_ws('('): + expr = self._parse_constant_expression(False) + self.skip_ws() + if not self.skip_string(')'): + self.fail("Expecting ')' to end 'noexcept'.") + exceptionSpec = ASTNoexceptSpec(expr) + else: + exceptionSpec = ASTNoexceptSpec(None) + + self.skip_ws() + if self.skip_string('->'): + trailingReturn = self._parse_type(named=False) + else: + trailingReturn = None self.skip_ws() override = self.skip_word_and_ws('override') @@ -5511,6 +5648,7 @@ class DefinitionParser(BaseParser): 'override') # they can be permuted self.skip_ws() + initializer = None if self.skip_string('='): self.skip_ws() valid = ('0', 'delete', 'default') @@ -5524,8 +5662,8 @@ class DefinitionParser(BaseParser): % '" or "'.join(valid)) return ASTParametersQualifiers( - args, volatile, const, refQual, exceptionSpec, override, final, - initializer) + args, volatile, const, refQual, exceptionSpec, trailingReturn, + override, final, initializer) def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimple: """Just parse the simple ones.""" @@ -5663,7 +5801,7 @@ class DefinitionParser(BaseParser): arrayOps.append(ASTArray(None)) continue - def parser(): + def parser() -> ASTExpression: return self._parse_expression() value = self._parse_expression_fallback([']'], parser) if not self.skip_string(']'): @@ -5846,7 +5984,7 @@ class DefinitionParser(BaseParser): inTemplate = outer == 'templateParam' - def parser(): + def parser() -> ASTExpression: return self._parse_assignment_expression(inTemplate=inTemplate) value = self._parse_expression_fallback(fallbackEnd, parser, allow=allowFallback) return ASTInitializer(value) @@ -5875,7 +6013,7 @@ class DefinitionParser(BaseParser): declSpecs = self._parse_decl_specs(outer=outer, typed=False) decl = self._parse_declarator(named=True, paramMode=outer, typed=False) - self.assert_end() + self.assert_end(allowSemicolon=True) except DefinitionError as exUntyped: if outer == 'type': desc = "If just a name" @@ -6042,7 +6180,7 @@ class DefinitionParser(BaseParser): if self.skip_string('='): self.skip_ws() - def parser(): + def parser() -> ASTExpression: return self._parse_constant_expression(inTemplate=False) initVal = self._parse_expression_fallback([], parser) init = ASTInitializer(initVal) @@ -6286,8 +6424,10 @@ class DefinitionParser(BaseParser): templatePrefix, fullSpecShorthand=False, isMember=objectType == 'member') + self.skip_ws() + semicolon = self.skip_string(';') return ASTDeclaration(objectType, directiveType, visibility, - templatePrefix, declaration) + templatePrefix, declaration, semicolon) def parse_namespace_object(self) -> ASTNamespace: templatePrefix = self._parse_template_declaration_prefix(objectType="namespace") @@ -7249,9 +7389,18 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value("cpp_paren_attributes", [], 'env') app.add_post_transform(AliasTransform) + # debug stuff + app.add_config_value("cpp_debug_lookup", False, '') + app.add_config_value("cpp_debug_show_tree", False, '') + + def setDebugFlags(app): + Symbol.debug_lookup = app.config.cpp_debug_lookup + Symbol.debug_show_tree = app.config.cpp_debug_show_tree + app.connect("builder-inited", setDebugFlags) + return { 'version': 'builtin', - 'env_version': 2, + 'env_version': 3, 'parallel_read_safe': True, 'parallel_write_safe': True, } diff --git a/sphinx/domains/math.py b/sphinx/domains/math.py index 88b6e4eb8..e77bd0ed7 100644 --- a/sphinx/domains/math.py +++ b/sphinx/domains/math.py @@ -142,7 +142,7 @@ class MathDomain(Domain): def add_equation(self, env: BuildEnvironment, docname: str, labelid: str) -> int: warnings.warn('MathDomain.add_equation() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) if labelid in self.equations: path = env.doc2path(self.equations[labelid][0]) msg = __('duplicate label of equation %s, other instance in %s') % (labelid, path) @@ -154,7 +154,7 @@ class MathDomain(Domain): def get_next_equation_number(self, docname: str) -> int: warnings.warn('MathDomain.get_next_equation_number() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) targets = [eq for eq in self.equations.values() if eq[0] == docname] return len(targets) + 1 diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 19da49ac6..fc1136ae2 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -14,7 +14,7 @@ import re import typing import warnings from inspect import Parameter -from typing import Any, Dict, Iterable, Iterator, List, Tuple +from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Tuple from typing import cast from docutils import nodes @@ -67,18 +67,29 @@ pairindextypes = { 'builtin': _('built-in function'), } +ObjectEntry = NamedTuple('ObjectEntry', [('docname', str), + ('node_id', str), + ('objtype', str)]) +ModuleEntry = NamedTuple('ModuleEntry', [('docname', str), + ('node_id', str), + ('synopsis', str), + ('platform', str), + ('deprecated', bool)]) -def _parse_annotation(annotation: str) -> List[Node]: - """Parse type annotation.""" - def make_xref(text: str) -> addnodes.pending_xref: - if text == 'None': - reftype = 'obj' - else: - reftype = 'class' - return pending_xref('', nodes.Text(text), - refdomain='py', reftype=reftype, reftarget=text) +def type_to_xref(text: str) -> addnodes.pending_xref: + """Convert a type string to a cross reference node.""" + if text == 'None': + reftype = 'obj' + else: + reftype = 'class' + return pending_xref('', nodes.Text(text), + refdomain='py', reftype=reftype, reftarget=text) + + +def _parse_annotation(annotation: str) -> List[Node]: + """Parse type annotation.""" def unparse(node: ast.AST) -> List[Node]: if isinstance(node, ast.Attribute): return [nodes.Text("%s.%s" % (unparse(node.value)[0], node.attr))] @@ -124,10 +135,10 @@ def _parse_annotation(annotation: str) -> List[Node]: result = unparse(tree) for i, node in enumerate(result): if isinstance(node, nodes.Text): - result[i] = make_xref(str(node)) + result[i] = type_to_xref(str(node)) return result except SyntaxError: - return [make_xref(annotation)] + return [type_to_xref(annotation)] def _parse_arglist(arglist: str) -> addnodes.desc_parameterlist: @@ -521,10 +532,11 @@ class PyModulelevel(PyObject): if cls.__name__ != 'DirectiveAdapter': warnings.warn('PyModulelevel is deprecated. ' 'Please check the implementation of %s' % cls, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) break else: - warnings.warn('PyModulelevel is deprecated', RemovedInSphinx40Warning) + warnings.warn('PyModulelevel is deprecated', + RemovedInSphinx40Warning, stacklevel=2) return super().run() @@ -611,7 +623,7 @@ class PyVariable(PyObject): typ = self.options.get('type') if typ: - signode += addnodes.desc_annotation(typ, ': ' + typ) + signode += addnodes.desc_annotation(typ, '', nodes.Text(': '), type_to_xref(typ)) value = self.options.get('value') if value: @@ -632,10 +644,18 @@ class PyClasslike(PyObject): Description of a class-like object (classes, interfaces, exceptions). """ + option_spec = PyObject.option_spec.copy() + option_spec.update({ + 'final': directives.flag, + }) + allow_nesting = True def get_signature_prefix(self, sig: str) -> str: - return self.objtype + ' ' + if 'final' in self.options: + return 'final %s ' % self.objtype + else: + return '%s ' % self.objtype def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: if self.objtype == 'class': @@ -658,10 +678,11 @@ class PyClassmember(PyObject): if cls.__name__ != 'DirectiveAdapter': warnings.warn('PyClassmember is deprecated. ' 'Please check the implementation of %s' % cls, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) break else: - warnings.warn('PyClassmember is deprecated', RemovedInSphinx40Warning) + warnings.warn('PyClassmember is deprecated', + RemovedInSphinx40Warning, stacklevel=2) return super().run() @@ -740,6 +761,7 @@ class PyMethod(PyObject): 'abstractmethod': directives.flag, 'async': directives.flag, 'classmethod': directives.flag, + 'final': directives.flag, 'property': directives.flag, 'staticmethod': directives.flag, }) @@ -752,6 +774,8 @@ class PyMethod(PyObject): def get_signature_prefix(self, sig: str) -> str: prefix = [] + if 'final' in self.options: + prefix.append('final') if 'abstractmethod' in self.options: prefix.append('abstract') if 'async' in self.options: @@ -844,7 +868,7 @@ class PyAttribute(PyObject): typ = self.options.get('type') if typ: - signode += addnodes.desc_annotation(typ, ': ' + typ) + signode += addnodes.desc_annotation(typ, '', nodes.Text(': '), type_to_xref(typ)) value = self.options.get('value') if value: @@ -876,10 +900,11 @@ class PyDecoratorMixin: if cls.__name__ != 'DirectiveAdapter': warnings.warn('PyDecoratorMixin is deprecated. ' 'Please check the implementation of %s' % cls, - RemovedInSphinx50Warning) + RemovedInSphinx50Warning, stacklevel=2) break else: - warnings.warn('PyDecoratorMixin is deprecated', RemovedInSphinx50Warning) + warnings.warn('PyDecoratorMixin is deprecated', + RemovedInSphinx50Warning, stacklevel=2) ret = super().handle_signature(sig, signode) # type: ignore signode.insert(0, addnodes.desc_addname('@', '@')) @@ -1134,8 +1159,8 @@ class PythonDomain(Domain): ] @property - def objects(self) -> Dict[str, Tuple[str, str, str]]: - return self.data.setdefault('objects', {}) # fullname -> docname, node_id, objtype + def objects(self) -> Dict[str, ObjectEntry]: + return self.data.setdefault('objects', {}) # fullname -> ObjectEntry def note_object(self, name: str, objtype: str, node_id: str, location: Any = None) -> None: """Note a python object for cross reference. @@ -1143,15 +1168,15 @@ class PythonDomain(Domain): .. versionadded:: 2.1 """ if name in self.objects: - docname = self.objects[name][0] + other = self.objects[name] logger.warning(__('duplicate object description of %s, ' 'other instance in %s, use :noindex: for one of them'), - name, docname, location=location) - self.objects[name] = (self.env.docname, node_id, objtype) + name, other.docname, location=location) + self.objects[name] = ObjectEntry(self.env.docname, node_id, objtype) @property - def modules(self) -> Dict[str, Tuple[str, str, str, str, bool]]: - return self.data.setdefault('modules', {}) # modname -> docname, node_id, synopsis, platform, deprecated # NOQA + def modules(self) -> Dict[str, ModuleEntry]: + return self.data.setdefault('modules', {}) # modname -> ModuleEntry def note_module(self, name: str, node_id: str, synopsis: str, platform: str, deprecated: bool) -> None: @@ -1159,28 +1184,29 @@ class PythonDomain(Domain): .. versionadded:: 2.1 """ - self.modules[name] = (self.env.docname, node_id, synopsis, platform, deprecated) + self.modules[name] = ModuleEntry(self.env.docname, node_id, + synopsis, platform, deprecated) def clear_doc(self, docname: str) -> None: - for fullname, (fn, _x, _x) in list(self.objects.items()): - if fn == docname: + for fullname, obj in list(self.objects.items()): + if obj.docname == docname: del self.objects[fullname] - for modname, (fn, _x, _x, _x, _y) in list(self.modules.items()): - if fn == docname: + for modname, mod in list(self.modules.items()): + if mod.docname == docname: del self.modules[modname] def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: # XXX check duplicates? - for fullname, (fn, node_id, objtype) in otherdata['objects'].items(): - if fn in docnames: - self.objects[fullname] = (fn, node_id, objtype) - for modname, data in otherdata['modules'].items(): - if data[0] in docnames: - self.modules[modname] = data + for fullname, obj in otherdata['objects'].items(): + if obj.docname in docnames: + self.objects[fullname] = obj + for modname, mod in otherdata['modules'].items(): + if mod.docname in docnames: + self.modules[modname] = mod def find_obj(self, env: BuildEnvironment, modname: str, classname: str, name: str, type: str, searchmode: int = 0 - ) -> List[Tuple[str, Tuple[str, str, str]]]: + ) -> List[Tuple[str, ObjectEntry]]: """Find a Python object for "name", perhaps using the given module and/or classname. Returns a list of (name, object entry) tuples. """ @@ -1191,7 +1217,7 @@ class PythonDomain(Domain): if not name: return [] - matches = [] # type: List[Tuple[str, Tuple[str, str, str]]] + matches = [] # type: List[Tuple[str, ObjectEntry]] newname = None if searchmode == 1: @@ -1202,20 +1228,20 @@ class PythonDomain(Domain): if objtypes is not None: if modname and classname: fullname = modname + '.' + classname + '.' + name - if fullname in self.objects and self.objects[fullname][2] in objtypes: + if fullname in self.objects and self.objects[fullname].objtype in objtypes: newname = fullname if not newname: if modname and modname + '.' + name in self.objects and \ - self.objects[modname + '.' + name][2] in objtypes: + self.objects[modname + '.' + name].objtype in objtypes: newname = modname + '.' + name - elif name in self.objects and self.objects[name][2] in objtypes: + elif name in self.objects and self.objects[name].objtype in objtypes: newname = name else: # "fuzzy" searching mode searchname = '.' + name matches = [(oname, self.objects[oname]) for oname in self.objects if oname.endswith(searchname) and - self.objects[oname][2] in objtypes] + self.objects[oname].objtype in objtypes] else: # NOTE: searching for exact match, object type is not considered if name in self.objects: @@ -1283,22 +1309,23 @@ class PythonDomain(Domain): def _make_module_refnode(self, builder: Builder, fromdocname: str, name: str, contnode: Node) -> Element: # get additional info for modules - docname, node_id, synopsis, platform, deprecated = self.modules[name] + module = self.modules[name] title = name - if synopsis: - title += ': ' + synopsis - if deprecated: + if module.synopsis: + title += ': ' + module.synopsis + if module.deprecated: title += _(' (deprecated)') - if platform: - title += ' (' + platform + ')' - return make_refnode(builder, fromdocname, docname, node_id, contnode, title) + if module.platform: + title += ' (' + module.platform + ')' + return make_refnode(builder, fromdocname, module.docname, module.node_id, + contnode, title) def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]: - for modname, info in self.modules.items(): - yield (modname, modname, 'module', info[0], info[1], 0) - for refname, (docname, node_id, type) in self.objects.items(): - if type != 'module': # modules are already handled - yield (refname, refname, type, docname, node_id, 1) + for modname, mod in self.modules.items(): + yield (modname, modname, 'module', mod.docname, mod.node_id, 0) + for refname, obj in self.objects.items(): + if obj.objtype != 'module': # modules are already handled + yield (refname, refname, obj.objtype, obj.docname, obj.node_id, 1) def get_full_qualified_name(self, node: Element) -> str: modname = node.get('py:module') diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index 74e901779..6dc597022 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -292,7 +292,7 @@ def make_glossary_term(env: "BuildEnvironment", textnodes: Iterable[Node], index document.note_explicit_target(term) else: warnings.warn('make_glossary_term() expects document is passed as an argument.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) gloss_entries = env.temp_data.setdefault('gloss_entries', set()) node_id = nodes.make_id('term-' + termtext) if node_id == 'term': @@ -660,7 +660,7 @@ class StandardDomain(Domain): def add_object(self, objtype: str, name: str, docname: str, labelid: str) -> None: warnings.warn('StandardDomain.add_object() is deprecated.', - RemovedInSphinx50Warning) + RemovedInSphinx50Warning, stacklevel=2) self.objects[objtype, name] = (docname, labelid) @property @@ -786,7 +786,7 @@ class StandardDomain(Domain): resolver = self._resolve_option_xref elif typ == 'citation': warnings.warn('pending_xref(domain=std, type=citation) is deprecated: %r' % node, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) domain = env.get_domain('citation') return domain.resolve_xref(env, fromdocname, builder, typ, target, node, contnode) elif typ == 'term': @@ -1082,15 +1082,15 @@ class StandardDomain(Domain): def note_citations(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA warnings.warn('StandardDomain.note_citations() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) def note_citation_refs(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA warnings.warn('StandardDomain.note_citation_refs() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) def note_labels(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA warnings.warn('StandardDomain.note_labels() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) def setup(app: "Sphinx") -> Dict[str, Any]: diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index c8735461d..6584ac6d8 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -331,10 +331,10 @@ class BuildEnvironment: """ if suffix: warnings.warn('The suffix argument for doc2path() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) if base not in (True, False, None): warnings.warn('The string style base argument for doc2path() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) pathname = self.project.doc2path(docname, base is True) if suffix: diff --git a/sphinx/environment/adapters/toctree.py b/sphinx/environment/adapters/toctree.py index bd3abd9ed..9a1ef73d4 100644 --- a/sphinx/environment/adapters/toctree.py +++ b/sphinx/environment/adapters/toctree.py @@ -153,7 +153,7 @@ class TocTree: logger.warning(__('circular toctree references ' 'detected, ignoring: %s <- %s'), ref, ' <- '.join(parents), - location=ref) + location=ref, type='toc', subtype='circular') continue refdoc = ref toc = self.env.tocs[ref].deepcopy() diff --git a/sphinx/environment/collectors/indexentries.py b/sphinx/environment/collectors/indexentries.py index 2ef59909b..a4c0450d2 100644 --- a/sphinx/environment/collectors/indexentries.py +++ b/sphinx/environment/collectors/indexentries.py @@ -29,7 +29,7 @@ class IndexEntriesCollector(EnvironmentCollector): def __init__(self) -> None: warnings.warn('IndexEntriesCollector is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None: env.indexentries.pop(docname, None) diff --git a/sphinx/errors.py b/sphinx/errors.py index a9d027cb8..d9a83712c 100644 --- a/sphinx/errors.py +++ b/sphinx/errors.py @@ -116,7 +116,8 @@ class PycodeError(Exception): class NoUri(Exception): - """Raised by builder.get_relative_uri() if there is no URI available.""" + """Raised by builder.get_relative_uri() or from missing-reference handlers + if there is no URI available.""" pass diff --git a/sphinx/events.py b/sphinx/events.py index ff49f290c..0911dfaaa 100644 --- a/sphinx/events.py +++ b/sphinx/events.py @@ -13,15 +13,16 @@ import warnings from collections import defaultdict from operator import attrgetter -from typing import Any, Callable, Dict, List, NamedTuple +from typing import Any, Callable, Dict, List, NamedTuple, Tuple from sphinx.deprecation import RemovedInSphinx40Warning -from sphinx.errors import ExtensionError +from sphinx.errors import ExtensionError, SphinxError from sphinx.locale import __ from sphinx.util import logging if False: # For type annotation + from typing import Type # for python3.5.1 from sphinx.application import Sphinx @@ -88,7 +89,8 @@ class EventManager: if listener.id == listener_id: listeners.remove(listener) - def emit(self, name: str, *args: Any) -> List: + def emit(self, name: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> List: """Emit a Sphinx event.""" try: logger.debug('[app] emitting event: %r%s', name, repr(args)[:100]) @@ -100,19 +102,29 @@ class EventManager: results = [] listeners = sorted(self.listeners[name], key=attrgetter("priority")) for listener in listeners: - if self.app is None: - # for compatibility; RemovedInSphinx40Warning - results.append(listener.handler(*args)) - else: - results.append(listener.handler(self.app, *args)) + try: + if self.app is None: + # for compatibility; RemovedInSphinx40Warning + results.append(listener.handler(*args)) + else: + results.append(listener.handler(self.app, *args)) + except allowed_exceptions: + # pass through the errors specified as *allowed_exceptions* + raise + except SphinxError: + raise + except Exception as exc: + raise ExtensionError(__("Handler %r for event %r threw an exception") % + (listener.handler, name)) from exc return results - def emit_firstresult(self, name: str, *args: Any) -> Any: + def emit_firstresult(self, name: str, *args: Any, + allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> Any: """Emit a Sphinx event and returns first result. This returns the result of the first handler that doesn't return ``None``. """ - for result in self.emit(name, *args): + for result in self.emit(name, *args, allowed_exceptions=allowed_exceptions): if result is not None: return result return None diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 23be0a00a..b01604617 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -54,7 +54,7 @@ template_dir = path.join(package_dir, 'templates', 'apidoc') def makename(package: str, module: str) -> str: """Join package and module with a dot.""" warnings.warn('makename() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) # Both package and module can be None/empty. if package: name = package @@ -112,7 +112,7 @@ def write_file(name: str, text: str, opts: Any) -> None: def format_heading(level: int, text: str, escape: bool = True) -> str: """Create a heading of <level> [1, 2 or 3 supported].""" warnings.warn('format_warning() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) if escape: text = rst.escape(text) underlining = ['=', '-', '~', ][level - 1] * len(text) @@ -122,7 +122,7 @@ def format_heading(level: int, text: str, escape: bool = True) -> str: def format_directive(module: str, package: str = None) -> str: """Create the automodule directive and add the options.""" warnings.warn('format_directive() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) directive = '.. automodule:: %s\n' % module_join(package, module) for option in OPTIONS: directive += ' :%s:\n' % option @@ -209,7 +209,7 @@ def create_modules_toc_file(modules: List[str], opts: Any, name: str = 'modules' def shall_skip(module: str, opts: Any, excludes: List[str] = []) -> bool: """Check if we want to skip this module.""" warnings.warn('shall_skip() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) # skip if the file doesn't exist and not using implicit namespaces if not opts.implicit_namespaces and not path.exists(module): return True diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 855b86d87..e247d3bd2 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -13,16 +13,17 @@ import importlib import re import warnings -from inspect import Parameter +from inspect import Parameter, Signature from types import ModuleType -from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union -from unittest.mock import patch +from typing import ( + Any, Callable, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Type, Union +) from docutils.statemachine import StringList import sphinx from sphinx.application import Sphinx -from sphinx.config import ENUM +from sphinx.config import Config, ENUM from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.environment import BuildEnvironment from sphinx.ext.autodoc.importer import import_object, get_module_members, get_object_members @@ -31,7 +32,7 @@ from sphinx.locale import _, __ from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.util import inspect from sphinx.util import logging -from sphinx.util import rpartition +from sphinx.util import split_full_qualified_name from sphinx.util.docstrings import extract_metadata, prepare_docstring from sphinx.util.inspect import getdoc, object_description, safe_getattr, stringify_signature from sphinx.util.typing import stringify as stringify_typehint @@ -66,6 +67,7 @@ def identity(x: Any) -> Any: ALL = object() +UNINITIALIZED_ATTR = object() INSTANCEATTR = object() SLOTSATTR = object() @@ -92,6 +94,16 @@ def inherited_members_option(arg: Any) -> Union[object, Set[str]]: return arg +def member_order_option(arg: Any) -> Optional[str]: + """Used to convert the :members: option to auto directives.""" + if arg is None: + return None + elif arg in ('alphabetical', 'bysource', 'groupwise'): + return arg + else: + raise ValueError(__('invalid value for member-order option: %s') % arg) + + SUPPRESS = object() @@ -311,7 +323,8 @@ class Documenter: modname = None parents = [] - self.modname, self.objpath = self.resolve_name(modname, parents, path, base) + with mock(self.env.config.autodoc_mock_imports): + self.modname, self.objpath = self.resolve_name(modname, parents, path, base) if not self.modname: return False @@ -379,6 +392,17 @@ class Documenter: # directives of course) return '.'.join(self.objpath) or self.modname + def _call_format_args(self, **kwargs: Any) -> str: + if kwargs: + try: + return self.format_args(**kwargs) + except TypeError: + # avoid chaining exceptions, by putting nothing here + pass + + # retry without arguments for old documenters + return self.format_args() + def format_signature(self, **kwargs: Any) -> str: """Format the signature (arguments and return annotation) of the object. @@ -387,21 +411,22 @@ class Documenter: if self.args is not None: # signature given explicitly args = "(%s)" % self.args + retann = self.retann else: # try to introspect the signature try: - try: - args = self.format_args(**kwargs) - except TypeError: - # retry without arguments for old documenters - args = self.format_args() - except Exception as err: - logger.warning(__('error while formatting arguments for %s: %s') % - (self.fullname, err), type='autodoc') + retann = None + args = self._call_format_args(**kwargs) + if args: + matched = re.match(r'^(\(.*\))\s+->\s+(.*)$', args) + if matched: + args = matched.group(1) + retann = matched.group(2) + except Exception: + logger.warning(__('error while formatting arguments for %s:') % + self.fullname, type='autodoc', exc_info=True) args = None - retann = self.retann - result = self.env.events.emit_firstresult('autodoc-process-signature', self.objtype, self.fullname, self.object, self.options, args, retann) @@ -419,8 +444,15 @@ class Documenter: directive = getattr(self, 'directivetype', self.objtype) name = self.format_name() sourcename = self.get_sourcename() - self.add_line('.. %s:%s:: %s%s' % (domain, directive, name, sig), - sourcename) + + # one signature per line, indented by column + prefix = '.. %s:%s:: ' % (domain, directive) + for i, sig_line in enumerate(sig.split("\n")): + self.add_line('%s%s%s' % (prefix, name, sig_line), + sourcename) + if i == 0: + prefix = " " * len(prefix) + if self.options.noindex: self.add_line(' :noindex:', sourcename) if self.objpath: @@ -428,14 +460,19 @@ class Documenter: # etc. don't support a prepended module name self.add_line(' :module: %s' % self.modname, sourcename) - def get_doc(self, encoding: str = None, ignore: int = 1) -> List[List[str]]: + def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]: """Decode and return lines of the docstring(s) for the object.""" if encoding is not None: warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated." % self.__class__.__name__, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) + if ignore is not None: + warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated." + % self.__class__.__name__, + RemovedInSphinx50Warning, stacklevel=2) docstring = getdoc(self.object, self.get_attr, - self.env.config.autodoc_inherit_docstrings) + self.env.config.autodoc_inherit_docstrings, + self.parent, self.object_name) if docstring: tab_width = self.directive.state.document.settings.tab_width return [prepare_docstring(docstring, ignore, tab_width)] @@ -466,7 +503,10 @@ class Documenter: key = ('.'.join(self.objpath[:-1]), self.objpath[-1]) if key in attr_docs: no_docstring = True - docstrings = [attr_docs[key]] + # make a copy of docstring for attributes to avoid cache + # the change of autodoc-process-docstring event. + docstrings = [list(attr_docs[key])] + for i, line in enumerate(self.process_doc(docstrings)): self.add_line(line, sourcename, i) @@ -505,12 +545,12 @@ class Documenter: else: logger.warning(__('missing attribute %s in object %s') % (name, self.fullname), type='autodoc') - return False, sorted(selected) + return False, selected elif self.options.inherited_members: - return False, sorted((m.name, m.value) for m in members.values()) + return False, [(m.name, m.value) for m in members.values()] else: - return False, sorted((m.name, m.value) for m in members.values() - if m.directly_defined) + return False, [(m.name, m.value) for m in members.values() + if m.directly_defined] def filter_members(self, members: List[Tuple[str, Any]], want_all: bool ) -> List[Tuple[str, Any, bool]]: @@ -556,7 +596,8 @@ class Documenter: else: isattr = False - doc = getdoc(member, self.get_attr, self.env.config.autodoc_inherit_docstrings) + doc = getdoc(member, self.get_attr, self.env.config.autodoc_inherit_docstrings, + self.parent, self.object_name) if not isinstance(doc, str): # Ignore non-string __doc__ doc = None @@ -574,6 +615,9 @@ class Documenter: if 'private' in metadata: # consider a member private if docstring has "private" metadata isprivate = True + elif 'public' in metadata: + # consider a member public if docstring has "public" metadata + isprivate = False else: isprivate = membername.startswith('_') @@ -676,20 +720,9 @@ class Documenter: '.'.join(self.objpath + [mname]) documenter = classes[-1](self.directive, full_mname, self.indent) memberdocumenters.append((documenter, isattr)) - member_order = self.options.member_order or \ - self.env.config.autodoc_member_order - if member_order == 'groupwise': - # sort by group; relies on stable sort to keep items in the - # same group sorted alphabetically - memberdocumenters.sort(key=lambda e: e[0].member_order) - elif member_order == 'bysource' and self.analyzer: - # sort by source order, by virtue of the module analyzer - tagorder = self.analyzer.tagorder - def keyfunc(entry: Tuple[Documenter, bool]) -> int: - fullname = entry[0].name.split('::')[1] - return tagorder.get(fullname, len(tagorder)) - memberdocumenters.sort(key=keyfunc) + member_order = self.options.member_order or self.env.config.autodoc_member_order + memberdocumenters = self.sort_members(memberdocumenters, member_order) for documenter, isattr in memberdocumenters: documenter.generate( @@ -700,6 +733,31 @@ class Documenter: self.env.temp_data['autodoc:module'] = None self.env.temp_data['autodoc:class'] = None + def sort_members(self, documenters: List[Tuple["Documenter", bool]], + order: str) -> List[Tuple["Documenter", bool]]: + """Sort the given member list.""" + if order == 'groupwise': + # sort by group; alphabetically within groups + documenters.sort(key=lambda e: (e[0].member_order, e[0].name)) + elif order == 'bysource': + if self.analyzer: + # sort by source order, by virtue of the module analyzer + tagorder = self.analyzer.tagorder + + def keyfunc(entry: Tuple[Documenter, bool]) -> int: + fullname = entry[0].name.split('::')[1] + return tagorder.get(fullname, len(tagorder)) + documenters.sort(key=keyfunc) + else: + # Assume that member discovery order matches source order. + # This is a reasonable assumption in Python 3.6 and up, where + # module.__dict__ is insertion-ordered. + pass + else: # alphabetical + documenters.sort(key=lambda e: e[0].name) + + return documenters + def generate(self, more_content: Any = None, real_modname: str = None, check_module: bool = False, all_members: bool = False) -> None: """Generate reST for the object given by *self.name*, and possibly for @@ -728,7 +786,8 @@ class Documenter: # where the attribute documentation would actually be found in. # This is used for situations where you have a module that collects the # functions and classes of internal submodules. - self.real_modname = real_modname or self.get_real_modname() # type: str + guess_modname = self.get_real_modname() + self.real_modname = real_modname or guess_modname # try to also get a source code analyzer for attribute docs try: @@ -736,8 +795,8 @@ class Documenter: # parse right now, to get PycodeErrors on parsing (results will # be cached anyway) self.analyzer.find_attr_docs() - except PycodeError as err: - logger.debug('[autodoc] module analyzer failed: %s', err) + except PycodeError: + logger.debug('[autodoc] module analyzer failed:', exc_info=True) # no source file -- e.g. for builtin and C modules self.analyzer = None # at least add the module.__file__ as a dependency @@ -746,6 +805,14 @@ class Documenter: else: self.directive.filename_set.add(self.analyzer.srcname) + if self.real_modname != guess_modname: + # Add module to dependency list if target object is defined in other module. + try: + analyzer = ModuleAnalyzer.for_module(guess_modname) + self.directive.filename_set.add(analyzer.srcname) + except PycodeError: + pass + # check __module__ of object (for members not given explicitly) if check_module: if not self.check_module(): @@ -788,7 +855,7 @@ class ModuleDocumenter(Documenter): 'noindex': bool_option, 'inherited-members': inherited_members_option, 'show-inheritance': bool_option, 'synopsis': identity, 'platform': identity, 'deprecated': bool_option, - 'member-order': identity, 'exclude-members': members_set_option, + 'member-order': member_order_option, 'exclude-members': members_set_option, 'private-members': bool_option, 'special-members': members_option, 'imported-members': bool_option, 'ignore-module-all': bool_option } # type: Dict[str, Callable] @@ -796,6 +863,7 @@ class ModuleDocumenter(Documenter): def __init__(self, *args: Any) -> None: super().__init__(*args) merge_special_members_option(self.options) + self.__all__ = None @classmethod def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any @@ -818,6 +886,30 @@ class ModuleDocumenter(Documenter): type='autodoc') return ret + def import_object(self) -> Any: + def is_valid_module_all(__all__: Any) -> bool: + """Check the given *__all__* is valid for a module.""" + if (isinstance(__all__, (list, tuple)) and + all(isinstance(e, str) for e in __all__)): + return True + else: + return False + + ret = super().import_object() + + if not self.options.ignore_module_all: + __all__ = getattr(self.object, '__all__', None) + if is_valid_module_all(__all__): + # valid __all__ found. copy it to self.__all__ + self.__all__ = __all__ + elif __all__: + # invalid __all__ found. + logger.warning(__('__all__ should be a list of strings, not %r ' + '(in module %s) -- ignoring __all__') % + (__all__, self.fullname), type='autodoc') + + return ret + def add_directive_header(self, sig: str) -> None: Documenter.add_directive_header(self, sig) @@ -831,26 +923,14 @@ class ModuleDocumenter(Documenter): if self.options.deprecated: self.add_line(' :deprecated:', sourcename) - def get_object_members(self, want_all: bool) -> Tuple[bool, List[Tuple[str, object]]]: + def get_object_members(self, want_all: bool) -> Tuple[bool, List[Tuple[str, Any]]]: if want_all: - if (self.options.ignore_module_all or not - hasattr(self.object, '__all__')): + if self.__all__: + memberlist = self.__all__ + else: # for implicit module members, check __module__ to avoid # documenting imported objects return True, get_module_members(self.object) - else: - memberlist = self.object.__all__ - # Sometimes __all__ is broken... - if not isinstance(memberlist, (list, tuple)) or not \ - all(isinstance(entry, str) for entry in memberlist): - logger.warning( - __('__all__ should be a list of strings, not %r ' - '(in module %s) -- ignoring __all__') % - (memberlist, self.fullname), - type='autodoc' - ) - # fall back to all members - return True, get_module_members(self.object) else: memberlist = self.options.members or [] ret = [] @@ -866,6 +946,25 @@ class ModuleDocumenter(Documenter): ) return False, ret + def sort_members(self, documenters: List[Tuple["Documenter", bool]], + order: str) -> List[Tuple["Documenter", bool]]: + if order == 'bysource' and self.__all__: + # Sort alphabetically first (for members not listed on the __all__) + documenters.sort(key=lambda e: e[0].name) + + # Sort by __all__ + def keyfunc(entry: Tuple[Documenter, bool]) -> int: + name = entry[0].name.split('::')[1] + if name in self.__all__: + return self.__all__.index(name) + else: + return len(self.__all__) + documenters.sort(key=keyfunc) + + return documenters + else: + return super().sort_members(documenters, order) + class ModuleLevelDocumenter(Documenter): """ @@ -876,8 +975,14 @@ class ModuleLevelDocumenter(Documenter): ) -> Tuple[str, List[str]]: if modname is None: if path: - modname = path.rstrip('.') - else: + stripped = path.rstrip('.') + modname, qualname = split_full_qualified_name(stripped) + if qualname: + parents = qualname.split(".") + else: + parents = [] + + if modname is None: # if documenting a toplevel object without explicit module, # it can be contained in another auto directive ... modname = self.env.temp_data.get('autodoc:module') @@ -910,8 +1015,13 @@ class ClassLevelDocumenter(Documenter): # ... if still None, there's no way to know if mod_cls is None: return None, [] - modname, cls = rpartition(mod_cls, '.') - parents = [cls] + + try: + modname, qualname = split_full_qualified_name(mod_cls) + parents = qualname.split(".") if qualname else [] + except ImportError: + parents = mod_cls.split(".") + # if the module name is still missing, get it like above if not modname: modname = self.env.temp_data.get('autodoc:module') @@ -926,49 +1036,80 @@ class DocstringSignatureMixin: Mixin for FunctionDocumenter and MethodDocumenter to provide the feature of reading the signature from the docstring. """ + _new_docstrings = None # type: List[List[str]] + _signatures = None # type: List[str] def _find_signature(self, encoding: str = None) -> Tuple[str, str]: if encoding is not None: warnings.warn("The 'encoding' argument to autodoc.%s._find_signature() is " "deprecated." % self.__class__.__name__, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) + + # candidates of the object name + valid_names = [self.objpath[-1]] # type: ignore + if isinstance(self, ClassDocumenter): + valid_names.append('__init__') + if hasattr(self.object, '__mro__'): + valid_names.extend(cls.__name__ for cls in self.object.__mro__) + docstrings = self.get_doc() self._new_docstrings = docstrings[:] + self._signatures = [] result = None for i, doclines in enumerate(docstrings): - # no lines in docstring, no match - if not doclines: - continue - # match first line of docstring against signature RE - match = py_ext_sig_re.match(doclines[0]) - if not match: - continue - exmod, path, base, args, retann = match.groups() - # the base name must match ours - valid_names = [self.objpath[-1]] # type: ignore - if isinstance(self, ClassDocumenter): - valid_names.append('__init__') - if hasattr(self.object, '__mro__'): - valid_names.extend(cls.__name__ for cls in self.object.__mro__) - if base not in valid_names: - continue - # re-prepare docstring to ignore more leading indentation - tab_width = self.directive.state.document.settings.tab_width # type: ignore - self._new_docstrings[i] = prepare_docstring('\n'.join(doclines[1:]), - tabsize=tab_width) - result = args, retann - # don't look any further - break + for j, line in enumerate(doclines): + if not line: + # no lines in docstring, no match + break + + if line.endswith('\\'): + multiline = True + line = line.rstrip('\\').rstrip() + else: + multiline = False + + # match first line of docstring against signature RE + match = py_ext_sig_re.match(line) + if not match: + continue + exmod, path, base, args, retann = match.groups() + + # the base name must match ours + if base not in valid_names: + continue + + # re-prepare docstring to ignore more leading indentation + tab_width = self.directive.state.document.settings.tab_width # type: ignore + self._new_docstrings[i] = prepare_docstring('\n'.join(doclines[j + 1:]), + tabsize=tab_width) + + if result is None: + # first signature + result = args, retann + else: + # subsequent signatures + self._signatures.append("(%s) -> %s" % (args, retann)) + + if multiline: + # the signature have multiple signatures on docstring + continue + else: + # don't look any further + break + + if result: + # finish the loop when signature found + break + return result - def get_doc(self, encoding: str = None, ignore: int = 1) -> List[List[str]]: + def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]: if encoding is not None: warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated." % self.__class__.__name__, - RemovedInSphinx40Warning) - lines = getattr(self, '_new_docstrings', None) - if lines is not None: - return lines + RemovedInSphinx40Warning, stacklevel=2) + if self._new_docstrings is not None: + return self._new_docstrings return super().get_doc(None, ignore) # type: ignore def format_signature(self, **kwargs: Any) -> str: @@ -978,7 +1119,11 @@ class DocstringSignatureMixin: result = self._find_signature() if result is not None: self.args, self.retann = result - return super().format_signature(**kwargs) # type: ignore + sig = super().format_signature(**kwargs) # type: ignore + if self._signatures: + return "\n".join([sig] + self._signatures) + else: + return sig class DocstringStripSignatureMixin(DocstringSignatureMixin): @@ -1017,43 +1162,19 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ if self.env.config.autodoc_typehints in ('none', 'description'): kwargs.setdefault('show_annotation', False) - unwrapped = inspect.unwrap(self.object) - if ((inspect.isbuiltin(unwrapped) or inspect.ismethoddescriptor(unwrapped)) and - not inspect.is_cython_function_or_method(unwrapped)): - # cannot introspect arguments of a C function or method - return None try: - if (not inspect.isfunction(unwrapped) and - not inspect.ismethod(unwrapped) and - not inspect.isbuiltin(unwrapped) and - not inspect.is_cython_function_or_method(unwrapped) and - not inspect.isclass(unwrapped) and - hasattr(unwrapped, '__call__')): - self.env.app.emit('autodoc-before-process-signature', - unwrapped.__call__, False) - sig = inspect.signature(unwrapped.__call__) + self.env.app.emit('autodoc-before-process-signature', self.object, False) + if inspect.is_singledispatch_function(self.object): + sig = inspect.signature(self.object, follow_wrapped=True) else: - self.env.app.emit('autodoc-before-process-signature', unwrapped, False) - sig = inspect.signature(unwrapped) + sig = inspect.signature(self.object) args = stringify_signature(sig, **kwargs) - except TypeError: - if (inspect.is_builtin_class_method(unwrapped, '__new__') and - inspect.is_builtin_class_method(unwrapped, '__init__')): - raise TypeError('%r is a builtin class' % unwrapped) - - # if a class should be documented as function (yay duck - # typing) we try to use the constructor signature as function - # signature without the first argument. - try: - self.env.app.emit('autodoc-before-process-signature', - unwrapped.__new__, True) - sig = inspect.signature(unwrapped.__new__, bound_method=True) - args = stringify_signature(sig, show_return_annotation=False, **kwargs) - except TypeError: - self.env.app.emit('autodoc-before-process-signature', - unwrapped.__init__, True) - sig = inspect.signature(unwrapped.__init__, bound_method=True) - args = stringify_signature(sig, show_return_annotation=False, **kwargs) + except TypeError as exc: + logger.warning(__("Failed to get a function signature for %s: %s"), + self.fullname, exc) + return None + except ValueError: + args = '' if self.env.config.strip_signature_backslash: # escape backslashes for reST @@ -1070,51 +1191,24 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ if inspect.iscoroutinefunction(self.object): self.add_line(' :async:', sourcename) + def format_signature(self, **kwargs: Any) -> str: + sig = super().format_signature(**kwargs) + sigs = [sig] + + if inspect.is_singledispatch_function(self.object): + # append signature of singledispatch'ed functions + for typ, func in self.object.registry.items(): + if typ is object: + pass # default implementation. skipped. + else: + self.annotate_to_first_argument(func, typ) -class SingledispatchFunctionDocumenter(FunctionDocumenter): - """ - Specialized Documenter subclass for singledispatch'ed functions. - """ - objtype = 'singledispatch_function' - directivetype = 'function' - member_order = 30 - - # before FunctionDocumenter - priority = FunctionDocumenter.priority + 1 - - @classmethod - def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any - ) -> bool: - return (super().can_document_member(member, membername, isattr, parent) and - inspect.is_singledispatch_function(member)) - - def add_directive_header(self, sig: str) -> None: - sourcename = self.get_sourcename() - - # intercept generated directive headers - # TODO: It is very hacky to use mock to intercept header generation - with patch.object(self, 'add_line') as add_line: - super().add_directive_header(sig) - - # output first line of header - self.add_line(*add_line.call_args_list[0][0]) - - # inserts signature of singledispatch'ed functions - for typ, func in self.object.registry.items(): - if typ is object: - pass # default implementation. skipped. - else: - self.annotate_to_first_argument(func, typ) - - documenter = FunctionDocumenter(self.directive, '') - documenter.object = func - self.add_line(' %s%s' % (self.format_name(), - documenter.format_signature()), - sourcename) + documenter = FunctionDocumenter(self.directive, '') + documenter.object = func + documenter.objpath = [None] + sigs.append(documenter.format_signature()) - # output remains of directive header - for call in add_line.call_args_list[1:]: - self.add_line(*call[0]) + return "\n".join(sigs) def annotate_to_first_argument(self, func: Callable, typ: Type) -> None: """Annotate type hint to the first argument of function if needed.""" @@ -1128,6 +1222,14 @@ class SingledispatchFunctionDocumenter(FunctionDocumenter): func.__signature__ = sig.replace(parameters=params) # type: ignore +class SingledispatchFunctionDocumenter(FunctionDocumenter): + """ + Used to be a specialized Documenter subclass for singledispatch'ed functions. + + Retained for backwards compatibility, now does the same as the FunctionDocumenter + """ + + class DecoratorDocumenter(FunctionDocumenter): """ Specialized Documenter subclass for decorator functions. @@ -1145,6 +1247,14 @@ class DecoratorDocumenter(FunctionDocumenter): return None +# Types which have confusing metaclass signatures it would be best not to show. +# These are listed by name, rather than storing the objects themselves, to avoid +# needing to import the modules. +_METACLASS_CALL_BLACKLIST = [ + 'enum.EnumMeta.__call__', +] + + class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: ignore """ Specialized Documenter subclass for classes. @@ -1154,7 +1264,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: option_spec = { 'members': members_option, 'undoc-members': bool_option, 'noindex': bool_option, 'inherited-members': inherited_members_option, - 'show-inheritance': bool_option, 'member-order': identity, + 'show-inheritance': bool_option, 'member-order': member_order_option, 'exclude-members': members_set_option, 'private-members': bool_option, 'special-members': members_option, } # type: Dict[str, Callable] @@ -1179,27 +1289,83 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: self.doc_as_attr = True return ret + def _get_signature(self) -> Optional[Signature]: + def get_user_defined_function_or_method(obj: Any, attr: str) -> Any: + """ Get the `attr` function or method from `obj`, if it is user-defined. """ + if inspect.is_builtin_class_method(obj, attr): + return None + attr = self.get_attr(obj, attr, None) + if not (inspect.ismethod(attr) or inspect.isfunction(attr)): + return None + return attr + + # This sequence is copied from inspect._signature_from_callable. + # ValueError means that no signature could be found, so we keep going. + + # First, let's see if it has an overloaded __call__ defined + # in its metaclass + call = get_user_defined_function_or_method(type(self.object), '__call__') + + if call is not None: + if "{0.__module__}.{0.__qualname__}".format(call) in _METACLASS_CALL_BLACKLIST: + call = None + + if call is not None: + self.env.app.emit('autodoc-before-process-signature', call, True) + try: + return inspect.signature(call, bound_method=True) + except ValueError: + pass + + # Now we check if the 'obj' class has a '__new__' method + new = get_user_defined_function_or_method(self.object, '__new__') + if new is not None: + self.env.app.emit('autodoc-before-process-signature', new, True) + try: + return inspect.signature(new, bound_method=True) + except ValueError: + pass + + # Finally, we should have at least __init__ implemented + init = get_user_defined_function_or_method(self.object, '__init__') + if init is not None: + self.env.app.emit('autodoc-before-process-signature', init, True) + try: + return inspect.signature(init, bound_method=True) + except ValueError: + pass + + # None of the attributes are user-defined, so fall back to let inspect + # handle it. + # We don't know the exact method that inspect.signature will read + # the signature from, so just pass the object itself to our hook. + self.env.app.emit('autodoc-before-process-signature', self.object, False) + try: + return inspect.signature(self.object, bound_method=False) + except ValueError: + pass + + # Still no signature: happens e.g. for old-style classes + # with __init__ in C and no `__text_signature__`. + return None + def format_args(self, **kwargs: Any) -> str: if self.env.config.autodoc_typehints in ('none', 'description'): kwargs.setdefault('show_annotation', False) - # for classes, the relevant signature is the __init__ method's - initmeth = self.get_attr(self.object, '__init__', None) - # classes without __init__ method, default __init__ or - # __init__ written in C? - if initmeth is None or \ - inspect.is_builtin_class_method(self.object, '__init__') or \ - not(inspect.ismethod(initmeth) or inspect.isfunction(initmeth)): - return None try: - self.env.app.emit('autodoc-before-process-signature', initmeth, True) - sig = inspect.signature(initmeth, bound_method=True) - return stringify_signature(sig, show_return_annotation=False, **kwargs) - except TypeError: - # still not possible: happens e.g. for old-style classes - # with __init__ in C + sig = self._get_signature() + except TypeError as exc: + # __signature__ attribute contained junk + logger.warning(__("Failed to get a constructor signature for %s: %s"), + self.fullname, exc) + return None + + if sig is None: return None + return stringify_signature(sig, show_return_annotation=False, **kwargs) + def format_signature(self, **kwargs: Any) -> str: if self.doc_as_attr: return '' @@ -1207,10 +1373,15 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: return super().format_signature(**kwargs) def add_directive_header(self, sig: str) -> None: + sourcename = self.get_sourcename() + if self.doc_as_attr: self.directivetype = 'attribute' super().add_directive_header(sig) + if self.analyzer and '.'.join(self.objpath) in self.analyzer.finals: + self.add_line(' :final:', sourcename) + # add inheritance info, if wanted if not self.doc_as_attr and self.options.show_inheritance: sourcename = self.get_sourcename() @@ -1223,11 +1394,11 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: self.add_line(' ' + _('Bases: %s') % ', '.join(bases), sourcename) - def get_doc(self, encoding: str = None, ignore: int = 1) -> List[List[str]]: + def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]: if encoding is not None: warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated." % self.__class__.__name__, - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) lines = getattr(self, '_new_docstrings', None) if lines is not None: return lines @@ -1244,7 +1415,8 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: if content in ('both', 'init'): __init__ = self.get_attr(self.object, '__init__', None) initdocstring = getdoc(__init__, self.get_attr, - self.env.config.autodoc_inherit_docstrings) + self.env.config.autodoc_inherit_docstrings, + self.parent, self.object_name) # for new-style classes, no __init__ means default __init__ if (initdocstring is not None and (initdocstring == object.__init__.__doc__ or # for pypy @@ -1254,7 +1426,8 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: # try __new__ __new__ = self.get_attr(self.object, '__new__', None) initdocstring = getdoc(__new__, self.get_attr, - self.env.config.autodoc_inherit_docstrings) + self.env.config.autodoc_inherit_docstrings, + self.parent, self.object_name) # for new-style classes, no __new__ means default __new__ if (initdocstring is not None and (initdocstring == object.__new__.__doc__ or # for pypy @@ -1348,8 +1521,11 @@ class DataDocumenter(ModuleLevelDocumenter): sourcename) try: - objrepr = object_description(self.object) - self.add_line(' :value: ' + objrepr, sourcename) + if self.object is UNINITIALIZED_ATTR: + pass + else: + objrepr = object_description(self.object) + self.add_line(' :value: ' + objrepr, sourcename) except ValueError: pass elif self.options.annotation is SUPPRESS: @@ -1390,6 +1566,7 @@ class DataDeclarationDocumenter(DataDocumenter): """Never import anything.""" # disguise as a data self.objtype = 'data' + self.object = UNINITIALIZED_ATTR try: # import module to obtain type annotation self.parent = importlib.import_module(self.modname) @@ -1403,6 +1580,30 @@ class DataDeclarationDocumenter(DataDocumenter): super().add_content(more_content, no_docstring=True) +class GenericAliasDocumenter(DataDocumenter): + """ + Specialized Documenter subclass for GenericAliases. + """ + + objtype = 'genericalias' + directivetype = 'data' + priority = DataDocumenter.priority + 1 + + @classmethod + def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any + ) -> bool: + return inspect.isgenericalias(member) + + def add_directive_header(self, sig: str) -> None: + self.options.annotation = SUPPRESS # type: ignore + super().add_directive_header(sig) + + def add_content(self, more_content: Any, no_docstring: bool = False) -> None: + name = stringify_typehint(self.object) + content = StringList([_('alias of %s') % name], source='') + super().add_content(content) + + class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: ignore """ Specialized Documenter subclass for methods (normal, static and class). @@ -1439,18 +1640,33 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: if self.env.config.autodoc_typehints in ('none', 'description'): kwargs.setdefault('show_annotation', False) - unwrapped = inspect.unwrap(self.object) - if ((inspect.isbuiltin(unwrapped) or inspect.ismethoddescriptor(unwrapped)) and - not inspect.is_cython_function_or_method(unwrapped)): - # can never get arguments of a C function or method + try: + if self.object == object.__init__ and self.parent != object: + # Classes not having own __init__() method are shown as no arguments. + # + # Note: The signature of object.__init__() is (self, /, *args, **kwargs). + # But it makes users confused. + args = '()' + else: + if inspect.isstaticmethod(self.object, cls=self.parent, name=self.object_name): + self.env.app.emit('autodoc-before-process-signature', self.object, False) + sig = inspect.signature(self.object, bound_method=False) + else: + self.env.app.emit('autodoc-before-process-signature', self.object, True) + + meth = self.parent.__dict__.get(self.objpath[-1], None) + if meth and inspect.is_singledispatch_method(meth): + sig = inspect.signature(self.object, bound_method=True, + follow_wrapped=True) + else: + sig = inspect.signature(self.object, bound_method=True) + args = stringify_signature(sig, **kwargs) + except TypeError as exc: + logger.warning(__("Failed to get a method signature for %s: %s"), + self.fullname, exc) return None - if inspect.isstaticmethod(unwrapped, cls=self.parent, name=self.object_name): - self.env.app.emit('autodoc-before-process-signature', unwrapped, False) - sig = inspect.signature(unwrapped, bound_method=False) - else: - self.env.app.emit('autodoc-before-process-signature', unwrapped, True) - sig = inspect.signature(unwrapped, bound_method=True) - args = stringify_signature(sig, **kwargs) + except ValueError: + args = '' if self.env.config.strip_signature_backslash: # escape backslashes for reST @@ -1470,59 +1686,32 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: self.add_line(' :classmethod:', sourcename) if inspect.isstaticmethod(obj, cls=self.parent, name=self.object_name): self.add_line(' :staticmethod:', sourcename) + if self.analyzer and '.'.join(self.objpath) in self.analyzer.finals: + self.add_line(' :final:', sourcename) def document_members(self, all_members: bool = False) -> None: pass + def format_signature(self, **kwargs: Any) -> str: + sig = super().format_signature(**kwargs) + sigs = [sig] -class SingledispatchMethodDocumenter(MethodDocumenter): - """ - Specialized Documenter subclass for singledispatch'ed methods. - """ - objtype = 'singledispatch_method' - directivetype = 'method' - member_order = 50 - - # before MethodDocumenter - priority = MethodDocumenter.priority + 1 - - @classmethod - def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any - ) -> bool: - if super().can_document_member(member, membername, isattr, parent) and parent.object: - meth = parent.object.__dict__.get(membername) - return inspect.is_singledispatch_method(meth) - else: - return False - - def add_directive_header(self, sig: str) -> None: - sourcename = self.get_sourcename() - - # intercept generated directive headers - # TODO: It is very hacky to use mock to intercept header generation - with patch.object(self, 'add_line') as add_line: - super().add_directive_header(sig) - - # output first line of header - self.add_line(*add_line.call_args_list[0][0]) - - # inserts signature of singledispatch'ed functions meth = self.parent.__dict__.get(self.objpath[-1]) - for typ, func in meth.dispatcher.registry.items(): - if typ is object: - pass # default implementation. skipped. - else: - self.annotate_to_first_argument(func, typ) + if inspect.is_singledispatch_method(meth): + # append signature of singledispatch'ed functions + for typ, func in meth.dispatcher.registry.items(): + if typ is object: + pass # default implementation. skipped. + else: + self.annotate_to_first_argument(func, typ) - documenter = MethodDocumenter(self.directive, '') - documenter.object = func - self.add_line(' %s%s' % (self.format_name(), - documenter.format_signature()), - sourcename) + documenter = MethodDocumenter(self.directive, '') + documenter.parent = self.parent + documenter.object = func + documenter.objpath = [None] + sigs.append(documenter.format_signature()) - # output remains of directive header - for call in add_line.call_args_list[1:]: - self.add_line(*call[0]) + return "\n".join(sigs) def annotate_to_first_argument(self, func: Callable, typ: Type) -> None: """Annotate type hint to the first argument of function if needed.""" @@ -1536,6 +1725,14 @@ class SingledispatchMethodDocumenter(MethodDocumenter): func.__signature__ = sig.replace(parameters=params) # type: ignore +class SingledispatchMethodDocumenter(MethodDocumenter): + """ + Used to be a specialized Documenter subclass for singledispatch'ed methods. + + Retained for backwards compatibility, now does the same as the MethodDocumenter + """ + + class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore """ Specialized Documenter subclass for attributes. @@ -1587,21 +1784,25 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): super().add_directive_header(sig) sourcename = self.get_sourcename() if not self.options.annotation: - if not self._datadescriptor: - # obtain annotation for this attribute - annotations = getattr(self.parent, '__annotations__', {}) - if annotations and self.objpath[-1] in annotations: - objrepr = stringify_typehint(annotations.get(self.objpath[-1])) - self.add_line(' :type: ' + objrepr, sourcename) - else: - key = ('.'.join(self.objpath[:-1]), self.objpath[-1]) - if self.analyzer and key in self.analyzer.annotations: - self.add_line(' :type: ' + self.analyzer.annotations[key], - sourcename) + # obtain type annotation for this attribute + annotations = getattr(self.parent, '__annotations__', {}) + if annotations and self.objpath[-1] in annotations: + objrepr = stringify_typehint(annotations.get(self.objpath[-1])) + self.add_line(' :type: ' + objrepr, sourcename) + else: + key = ('.'.join(self.objpath[:-1]), self.objpath[-1]) + if self.analyzer and key in self.analyzer.annotations: + self.add_line(' :type: ' + self.analyzer.annotations[key], + sourcename) + # data descriptors do not have useful values + if not self._datadescriptor: try: - objrepr = object_description(self.object) - self.add_line(' :value: ' + objrepr, sourcename) + if self.object is INSTANCEATTR: + pass + else: + objrepr = object_description(self.object) + self.add_line(' :value: ' + objrepr, sourcename) except ValueError: pass elif self.options.annotation is SUPPRESS: @@ -1672,6 +1873,7 @@ class InstanceAttributeDocumenter(AttributeDocumenter): """Never import anything.""" # disguise as an attribute self.objtype = 'attribute' + self.object = INSTANCEATTR self._datadescriptor = False return True @@ -1716,8 +1918,12 @@ class SlotsAttributeDocumenter(AttributeDocumenter): self.env.note_reread() return False - def get_doc(self, encoding: str = None, ignore: int = 1) -> List[List[str]]: + def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]: """Decode and return lines of the docstring(s) for the object.""" + if ignore is not None: + warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated." + % self.__class__.__name__, + RemovedInSphinx50Warning, stacklevel=2) name = self.objpath[-1] __slots__ = safe_getattr(self.parent, '__slots__', []) if isinstance(__slots__, dict) and isinstance(__slots__.get(name), str): @@ -1729,7 +1935,7 @@ class SlotsAttributeDocumenter(AttributeDocumenter): def get_documenters(app: Sphinx) -> Dict[str, "Type[Documenter]"]: """Returns registered Documenter classes""" - warnings.warn("get_documenters() is deprecated.", RemovedInSphinx50Warning) + warnings.warn("get_documenters() is deprecated.", RemovedInSphinx50Warning, stacklevel=2) return app.registry.documenters @@ -1742,25 +1948,32 @@ def autodoc_attrgetter(app: Sphinx, obj: Any, name: str, *defargs: Any) -> Any: return safe_getattr(obj, name, *defargs) +def migrate_autodoc_member_order(app: Sphinx, config: Config) -> None: + if config.autodoc_member_order == 'alphabetic': + # RemovedInSphinx50Warning + logger.warning(__('autodoc_member_order now accepts "alphabetical" ' + 'instead of "alphabetic". Please update your setting.')) + config.autodoc_member_order = 'alphabetical' # type: ignore + + def setup(app: Sphinx) -> Dict[str, Any]: app.add_autodocumenter(ModuleDocumenter) app.add_autodocumenter(ClassDocumenter) app.add_autodocumenter(ExceptionDocumenter) app.add_autodocumenter(DataDocumenter) app.add_autodocumenter(DataDeclarationDocumenter) + app.add_autodocumenter(GenericAliasDocumenter) app.add_autodocumenter(FunctionDocumenter) - app.add_autodocumenter(SingledispatchFunctionDocumenter) app.add_autodocumenter(DecoratorDocumenter) app.add_autodocumenter(MethodDocumenter) - app.add_autodocumenter(SingledispatchMethodDocumenter) app.add_autodocumenter(AttributeDocumenter) app.add_autodocumenter(PropertyDocumenter) app.add_autodocumenter(InstanceAttributeDocumenter) app.add_autodocumenter(SlotsAttributeDocumenter) - app.add_config_value('autoclass_content', 'class', True) - app.add_config_value('autodoc_member_order', 'alphabetic', True) - app.add_config_value('autodoc_default_flags', [], True) + app.add_config_value('autoclass_content', 'class', True, ENUM('both', 'class', 'init')) + app.add_config_value('autodoc_member_order', 'alphabetical', True, + ENUM('alphabetic', 'alphabetical', 'bysource', 'groupwise')) app.add_config_value('autodoc_default_options', {}, True) app.add_config_value('autodoc_docstring_signature', True, True) app.add_config_value('autodoc_mock_imports', [], True) @@ -1773,6 +1986,8 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_event('autodoc-process-signature') app.add_event('autodoc-skip-member') + app.connect('config-inited', migrate_autodoc_member_order, priority=800) + app.setup_extension('sphinx.ext.autodoc.type_comment') app.setup_extension('sphinx.ext.autodoc.typehints') diff --git a/sphinx/ext/autodoc/directive.py b/sphinx/ext/autodoc/directive.py index 3be19f089..9a3428f5d 100644 --- a/sphinx/ext/autodoc/directive.py +++ b/sphinx/ext/autodoc/directive.py @@ -66,7 +66,7 @@ class DocumenterBridge: else: # create fake object for self.state.document.settings.tab_width warnings.warn('DocumenterBridge requires a state object on instantiation.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) settings = Struct(tab_width=8) document = Struct(settings=settings) self.state = Struct(document=document) diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index e98b97915..cdccf710d 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -11,10 +11,10 @@ import importlib import traceback import warnings -from collections import namedtuple -from typing import Any, Callable, Dict, List, Mapping, Tuple +from typing import Any, Callable, Dict, List, Mapping, NamedTuple, Tuple from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias +from sphinx.pycode import ModuleAnalyzer from sphinx.util import logging from sphinx.util.inspect import isclass, isenumclass, safe_getattr @@ -122,11 +122,13 @@ def get_module_members(module: Any) -> List[Tuple[str, Any]]: return sorted(list(members.values())) -Attribute = namedtuple('Attribute', ['name', 'directly_defined', 'value']) +Attribute = NamedTuple('Attribute', [('name', str), + ('directly_defined', bool), + ('value', Any)]) def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable, - analyzer: Any = None) -> Dict[str, Attribute]: + analyzer: ModuleAnalyzer = None) -> Dict[str, Attribute]: """Get members and attributes of target object.""" from sphinx.ext.autodoc import INSTANCEATTR @@ -142,8 +144,9 @@ def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable, members[name] = Attribute(name, True, value) superclass = subject.__mro__[1] - for name, value in obj_dict.items(): + for name in obj_dict: if name not in superclass.__dict__: + value = safe_getattr(subject, name) members[name] = Attribute(name, True, value) # members in __slots__ diff --git a/sphinx/ext/autodoc/typehints.py b/sphinx/ext/autodoc/typehints.py index f917dbdf3..b763bdfc7 100644 --- a/sphinx/ext/autodoc/typehints.py +++ b/sphinx/ext/autodoc/typehints.py @@ -104,24 +104,16 @@ def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> No continue arg = arguments.get(name, {}) - field = nodes.field() - if arg.get('param') and arg.get('type'): - # both param and type are already filled manually - continue - elif arg.get('param'): - # only param: fill type field + if not arg.get('type'): + field = nodes.field() field += nodes.field_name('', 'type ' + name) field += nodes.field_body('', nodes.paragraph('', annotation)) - elif arg.get('type'): - # only type: It's odd... + node += field + if not arg.get('param'): + field = nodes.field() field += nodes.field_name('', 'param ' + name) field += nodes.field_body('', nodes.paragraph('', '')) - else: - # both param and type are not found - field += nodes.field_name('', 'param ' + annotation + ' ' + name) - field += nodes.field_body('', nodes.paragraph('', '')) - - node += field + node += field if 'return' in annotations and 'return' not in arguments: field = nodes.field() diff --git a/sphinx/ext/autosectionlabel.py b/sphinx/ext/autosectionlabel.py index 9890cdf7d..4bb401791 100644 --- a/sphinx/ext/autosectionlabel.py +++ b/sphinx/ext/autosectionlabel.py @@ -15,6 +15,7 @@ from docutils import nodes from docutils.nodes import Node from sphinx.application import Sphinx +from sphinx.domains.std import StandardDomain from sphinx.locale import __ from sphinx.util import logging from sphinx.util.nodes import clean_astext @@ -33,8 +34,7 @@ def get_node_depth(node: Node) -> int: def register_sections_as_label(app: Sphinx, document: Node) -> None: - labels = app.env.domaindata['std']['labels'] - anonlabels = app.env.domaindata['std']['anonlabels'] + domain = cast(StandardDomain, app.env.get_domain('std')) for node in document.traverse(nodes.section): if (app.config.autosectionlabel_maxdepth and get_node_depth(node) >= app.config.autosectionlabel_maxdepth): @@ -49,13 +49,13 @@ def register_sections_as_label(app: Sphinx, document: Node) -> None: name = nodes.fully_normalize_name(ref_name) sectname = clean_astext(title) - if name in labels: + if name in domain.labels: logger.warning(__('duplicate label %s, other instance in %s'), - name, app.env.doc2path(labels[name][0]), + name, app.env.doc2path(domain.labels[name][0]), location=node, type='autosectionlabel', subtype=docname) - anonlabels[name] = docname, labelid - labels[name] = docname, labelid, sectname + domain.anonlabels[name] = docname, labelid + domain.labels[name] = docname, labelid, sectname def setup(app: Sphinx) -> Dict[str, Any]: diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index ee44e77d3..162b6868c 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -81,7 +81,7 @@ from sphinx.ext.autodoc.importer import import_module from sphinx.ext.autodoc.mock import mock from sphinx.locale import __ from sphinx.pycode import ModuleAnalyzer, PycodeError -from sphinx.util import import_object, rst, logging +from sphinx.util import rst, logging from sphinx.util.docutils import ( NullReporter, SphinxDirective, SphinxRole, new_document, switch_source_input ) @@ -228,8 +228,10 @@ class Autosummary(SphinxDirective): final_argument_whitespace = False has_content = True option_spec = { + 'caption': directives.unchanged_required, 'toctree': directives.unchanged, 'nosignatures': directives.flag, + 'recursive': directives.flag, 'template': directives.unchanged, } @@ -252,14 +254,13 @@ class Autosummary(SphinxDirective): docname = posixpath.join(tree_prefix, real_name) docname = posixpath.normpath(posixpath.join(dirname, docname)) if docname not in self.env.found_docs: - location = self.state_machine.get_source_and_line(self.lineno) if excluded(self.env.doc2path(docname, None)): msg = __('autosummary references excluded document %r. Ignored.') else: msg = __('autosummary: stub file not found %r. ' 'Check your autosummary_generate setting.') - logger.warning(msg, real_name, location=location) + logger.warning(msg, real_name, location=self.get_source_info()) continue docnames.append(docname) @@ -270,9 +271,14 @@ class Autosummary(SphinxDirective): tocnode['entries'] = [(None, docn) for docn in docnames] tocnode['maxdepth'] = -1 tocnode['glob'] = None + tocnode['caption'] = self.options.get('caption') nodes.append(autosummary_toc('', '', tocnode)) + if 'toctree' not in self.options and 'caption' in self.options: + logger.warning(__('A captioned autosummary requires :toctree: option. ignored.'), + location=nodes[-1]) + return nodes def get_items(self, names: List[str]) -> List[Tuple[str, str, str, str]]: @@ -295,8 +301,8 @@ class Autosummary(SphinxDirective): with mock(self.config.autosummary_mock_imports): real_name, obj, parent, modname = import_by_name(name, prefixes=prefixes) except ImportError: - logger.warning(__('failed to import %s'), name) - items.append((name, '', '', name)) + logger.warning(__('autosummary: failed to import %s'), name, + location=self.get_source_info()) continue self.bridge.result = StringList() # initialize for each documenter @@ -310,11 +316,13 @@ class Autosummary(SphinxDirective): doccls = get_documenter(self.env.app, obj, parent) documenter = doccls(self.bridge, full_name) if not documenter.parse_name(): - logger.warning(__('failed to parse name %s'), real_name) + logger.warning(__('failed to parse name %s'), real_name, + location=self.get_source_info()) items.append((display_name, '', '', real_name)) continue if not documenter.import_object(): - logger.warning(__('failed to import object %s'), real_name) + logger.warning(__('failed to import object %s'), real_name, + location=self.get_source_info()) items.append((display_name, '', '', real_name)) continue if documenter.options.members and not documenter.check_module(): @@ -652,7 +660,7 @@ def autolink_role(typ: str, rawtext: str, etext: str, lineno: int, inliner: Inli Expands to ':obj:`text`' if `text` is an object that can be imported; otherwise expands to '*text*'. """ - warnings.warn('autolink_role() is deprecated.', RemovedInSphinx40Warning) + warnings.warn('autolink_role() is deprecated.', RemovedInSphinx40Warning, stacklevel=2) env = inliner.document.settings.env pyobj_role = env.get_domain('py').role('obj') objects, msg = pyobj_role('obj', rawtext, etext, lineno, inliner, options, content) @@ -703,8 +711,6 @@ def get_rst_suffix(app: Sphinx) -> str: parser_class = app.registry.get_source_parsers().get(suffix) if parser_class is None: return ('restructuredtext',) - if isinstance(parser_class, str): - parser_class = import_object(parser_class, 'source parser') return parser_class.supported suffix = None # type: str @@ -747,8 +753,7 @@ def process_generate_options(app: Sphinx) -> None: imported_members = app.config.autosummary_imported_members with mock(app.config.autosummary_mock_imports): - generate_autosummary_docs(genfiles, builder=app.builder, - suffix=suffix, base_path=app.srcdir, + generate_autosummary_docs(genfiles, suffix=suffix, base_path=app.srcdir, app=app, imported_members=imported_members, overwrite=app.config.autosummary_generate_overwrite) @@ -771,6 +776,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_directive('autosummary', Autosummary) app.add_role('autolink', AutoLink()) app.connect('builder-inited', process_generate_options) + app.add_config_value('autosummary_context', {}, True) app.add_config_value('autosummary_generate', [], True, [bool]) app.add_config_value('autosummary_generate_overwrite', True, False) app.add_config_value('autosummary_mock_imports', diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 932856aa6..4dde73829 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -18,31 +18,39 @@ """ import argparse +import inspect import locale import os +import pkgutil import pydoc import re import sys import warnings -from typing import Any, Callable, Dict, List, NamedTuple, Set, Tuple +from gettext import NullTranslations +from os import path +from typing import Any, Callable, Dict, List, NamedTuple, Set, Tuple, Union -from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound +from jinja2 import TemplateNotFound from jinja2.sandbox import SandboxedEnvironment import sphinx.locale from sphinx import __display_version__ from sphinx import package_dir +from sphinx.application import Sphinx from sphinx.builders import Builder -from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.config import Config +from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.ext.autodoc import Documenter from sphinx.ext.autosummary import import_by_name, get_documenter -from sphinx.jinja2glue import BuiltinTemplateLoader from sphinx.locale import __ +from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.registry import SphinxComponentRegistry from sphinx.util import logging from sphinx.util import rst +from sphinx.util import split_full_qualified_name from sphinx.util.inspect import safe_getattr from sphinx.util.osutil import ensuredir +from sphinx.util.template import SphinxTemplateLoader if False: # For type annotation @@ -55,20 +63,27 @@ logger = logging.getLogger(__name__) class DummyApplication: """Dummy Application class for sphinx-autogen command.""" - def __init__(self) -> None: + def __init__(self, translator: NullTranslations) -> None: + self.config = Config() self.registry = SphinxComponentRegistry() self.messagelog = [] # type: List[str] + self.srcdir = "/" + self.translator = translator self.verbosity = 0 self._warncount = 0 self.warningiserror = False + self.config.add('autosummary_context', {}, True, None) + self.config.init_values() + def emit_firstresult(self, *args: Any) -> None: pass AutosummaryEntry = NamedTuple('AutosummaryEntry', [('name', str), ('path', str), - ('template', str)]) + ('template', str), + ('recursive', bool)]) def setup_documenters(app: Any) -> None: @@ -76,14 +91,14 @@ def setup_documenters(app: Any) -> None: ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, FunctionDocumenter, MethodDocumenter, AttributeDocumenter, InstanceAttributeDocumenter, DecoratorDocumenter, PropertyDocumenter, - SlotsAttributeDocumenter, DataDeclarationDocumenter, + SlotsAttributeDocumenter, DataDeclarationDocumenter, GenericAliasDocumenter, SingledispatchFunctionDocumenter, ) documenters = [ ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, FunctionDocumenter, MethodDocumenter, AttributeDocumenter, InstanceAttributeDocumenter, DecoratorDocumenter, PropertyDocumenter, - SlotsAttributeDocumenter, DataDeclarationDocumenter, + SlotsAttributeDocumenter, DataDeclarationDocumenter, GenericAliasDocumenter, SingledispatchFunctionDocumenter, ] # type: List[Type[Documenter]] for documenter in documenters: @@ -107,25 +122,37 @@ def _underline(title: str, line: str = '=') -> str: class AutosummaryRenderer: """A helper class for rendering.""" - def __init__(self, builder: Builder, template_dir: str) -> None: - loader = None # type: BaseLoader - template_dirs = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')] - if builder is None: - if template_dir: - template_dirs.insert(0, template_dir) - loader = FileSystemLoader(template_dirs) - else: - # allow the user to override the templates - loader = BuiltinTemplateLoader() - loader.init(builder, dirs=template_dirs) + def __init__(self, app: Union[Builder, Sphinx], template_dir: str = None) -> None: + if isinstance(app, Builder): + warnings.warn('The first argument for AutosummaryRenderer has been ' + 'changed to Sphinx object', + RemovedInSphinx50Warning, stacklevel=2) + if template_dir: + warnings.warn('template_dir argument for AutosummaryRenderer is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) + + system_templates_path = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')] + loader = SphinxTemplateLoader(app.srcdir, app.config.templates_path, + system_templates_path) self.env = SandboxedEnvironment(loader=loader) self.env.filters['escape'] = rst.escape self.env.filters['e'] = rst.escape self.env.filters['underline'] = _underline + if isinstance(app, (Sphinx, DummyApplication)): + if app.translator: + self.env.add_extension("jinja2.ext.i18n") + self.env.install_gettext_translations(app.translator) # type: ignore + elif isinstance(app, Builder): + if app.app.translator: + self.env.add_extension("jinja2.ext.i18n") + self.env.install_gettext_translations(app.app.translator) # type: ignore + def exists(self, template_name: str) -> bool: """Check if template file exists.""" + warnings.warn('AutosummaryRenderer.exists() is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) try: self.env.get_template(template_name) return True @@ -134,22 +161,78 @@ class AutosummaryRenderer: def render(self, template_name: str, context: Dict) -> str: """Render a template file.""" - return self.env.get_template(template_name).render(context) + try: + template = self.env.get_template(template_name) + except TemplateNotFound: + try: + # objtype is given as template_name + template = self.env.get_template('autosummary/%s.rst' % template_name) + except TemplateNotFound: + # fallback to base.rst + template = self.env.get_template('autosummary/base.rst') + + return template.render(context) # -- Generating output --------------------------------------------------------- +class ModuleScanner: + def __init__(self, app: Any, obj: Any) -> None: + self.app = app + self.object = obj + + def get_object_type(self, name: str, value: Any) -> str: + return get_documenter(self.app, value, self.object).objtype + + def is_skipped(self, name: str, value: Any, objtype: str) -> bool: + try: + return self.app.emit_firstresult('autodoc-skip-member', objtype, + name, value, False, {}) + except Exception as exc: + logger.warning(__('autosummary: failed to determine %r to be documented, ' + 'the following exception was raised:\n%s'), + name, exc, type='autosummary') + return False + + def scan(self, imported_members: bool) -> List[str]: + members = [] + for name in dir(self.object): + try: + value = safe_getattr(self.object, name) + except AttributeError: + value = None + + objtype = self.get_object_type(name, value) + if self.is_skipped(name, value, objtype): + continue + + try: + if inspect.ismodule(value): + imported = True + elif safe_getattr(value, '__module__') != self.object.__name__: + imported = True + else: + imported = False + except AttributeError: + imported = False + + if imported_members: + # list all members up + members.append(name) + elif imported is False: + # list not-imported members up + members.append(name) + + return members + + def generate_autosummary_content(name: str, obj: Any, parent: Any, template: AutosummaryRenderer, template_name: str, - imported_members: bool, app: Any) -> str: + imported_members: bool, app: Any, + recursive: bool, context: Dict) -> str: doc = get_documenter(app, obj, parent) - if template_name is None: - template_name = 'autosummary/%s.rst' % doc.objtype - if not template.exists(template_name): - template_name = 'autosummary/base.rst' - def skip_member(obj: Any, name: str, objtype: str) -> bool: try: return app.emit_firstresult('autodoc-skip-member', objtype, name, @@ -187,16 +270,46 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, public.append(name) return public, items + def get_module_attrs(members: Any) -> Tuple[List[str], List[str]]: + """Find module attributes with docstrings.""" + attrs, public = [], [] + try: + analyzer = ModuleAnalyzer.for_module(name) + attr_docs = analyzer.find_attr_docs() + for namespace, attr_name in attr_docs: + if namespace == '' and attr_name in members: + attrs.append(attr_name) + if not attr_name.startswith('_'): + public.append(attr_name) + except PycodeError: + pass # give up if ModuleAnalyzer fails to parse code + return public, attrs + + def get_modules(obj: Any) -> Tuple[List[str], List[str]]: + items = [] # type: List[str] + for _, modname, ispkg in pkgutil.iter_modules(obj.__path__): + fullname = name + '.' + modname + items.append(fullname) + public = [x for x in items if not x.split('.')[-1].startswith('_')] + return public, items + ns = {} # type: Dict[str, Any] + ns.update(context) if doc.objtype == 'module': - ns['members'] = dir(obj) + scanner = ModuleScanner(app, obj) + ns['members'] = scanner.scan(imported_members) ns['functions'], ns['all_functions'] = \ get_members(obj, {'function'}, imported=imported_members) ns['classes'], ns['all_classes'] = \ get_members(obj, {'class'}, imported=imported_members) ns['exceptions'], ns['all_exceptions'] = \ get_members(obj, {'exception'}, imported=imported_members) + ns['attributes'], ns['all_attributes'] = \ + get_module_attrs(ns['members']) + ispackage = hasattr(obj, '__path__') + if ispackage and recursive: + ns['modules'], ns['all_modules'] = get_modules(obj) elif doc.objtype == 'class': ns['members'] = dir(obj) ns['inherited_members'] = \ @@ -206,24 +319,27 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, ns['attributes'], ns['all_attributes'] = \ get_members(obj, {'attribute', 'property'}) - parts = name.split('.') + modname, qualname = split_full_qualified_name(name) if doc.objtype in ('method', 'attribute', 'property'): - mod_name = '.'.join(parts[:-2]) - cls_name = parts[-2] - obj_name = '.'.join(parts[-2:]) - ns['class'] = cls_name + ns['class'] = qualname.rsplit(".", 1)[0] + + if doc.objtype in ('class',): + shortname = qualname else: - mod_name, obj_name = '.'.join(parts[:-1]), parts[-1] + shortname = qualname.rsplit(".", 1)[-1] ns['fullname'] = name - ns['module'] = mod_name - ns['objname'] = obj_name - ns['name'] = parts[-1] + ns['module'] = modname + ns['objname'] = qualname + ns['name'] = shortname ns['objtype'] = doc.objtype ns['underline'] = len(name) * '=' - return template.render(template_name, ns) + if template_name: + return template.render(template_name, ns) + else: + return template.render(doc.objtype, ns) def generate_autosummary_docs(sources: List[str], output_dir: str = None, @@ -234,18 +350,26 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None, overwrite: bool = True) -> None: if info: warnings.warn('info argument for generate_autosummary_docs() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) _info = info else: _info = logger.info if warn: warnings.warn('warn argument for generate_autosummary_docs() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) _warn = warn else: _warn = logger.warning + if builder: + warnings.warn('builder argument for generate_autosummary_docs() is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) + + if template_dir: + warnings.warn('template_dir argument for generate_autosummary_docs() is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) + showed_sources = list(sorted(sources)) if len(showed_sources) > 20: showed_sources = showed_sources[:10] + ['...'] + showed_sources[-10:] @@ -258,7 +382,7 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None, if base_path is not None: sources = [os.path.join(base_path, filename) for filename in sources] - template = AutosummaryRenderer(builder, template_dir) + template = AutosummaryRenderer(app) # read items = find_autosummary_in_files(sources) @@ -282,8 +406,12 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None, _warn(__('[autosummary] failed to import %r: %s') % (entry.name, e)) continue + context = {} + if app: + context.update(app.config.autosummary_context) + content = generate_autosummary_content(name, obj, parent, template, entry.template, - imported_members, app) + imported_members, app, entry.recursive, context) filename = os.path.join(path, name + suffix) if os.path.isfile(filename): @@ -305,8 +433,7 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None, if new_files: generate_autosummary_docs(new_files, output_dir=output_dir, suffix=suffix, warn=warn, info=info, - base_path=base_path, builder=builder, - template_dir=template_dir, + base_path=base_path, imported_members=imported_members, app=app, overwrite=overwrite) @@ -326,12 +453,16 @@ def find_autosummary_in_files(filenames: List[str]) -> List[AutosummaryEntry]: return documented -def find_autosummary_in_docstring(name: str, module: Any = None, filename: str = None +def find_autosummary_in_docstring(name: str, module: str = None, filename: str = None ) -> List[AutosummaryEntry]: """Find out what items are documented in the given object's docstring. See `find_autosummary_in_lines`. """ + if module: + warnings.warn('module argument for find_autosummary_in_docstring() is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) + try: real_name, obj, parent, modname = import_by_name(name) lines = pydoc.getdoc(obj).splitlines() @@ -346,7 +477,7 @@ def find_autosummary_in_docstring(name: str, module: Any = None, filename: str = return [] -def find_autosummary_in_lines(lines: List[str], module: Any = None, filename: str = None +def find_autosummary_in_lines(lines: List[str], module: str = None, filename: str = None ) -> List[AutosummaryEntry]: """Find out what items appear in autosummary:: directives in the given lines. @@ -364,11 +495,13 @@ def find_autosummary_in_lines(lines: List[str], module: Any = None, filename: st module_re = re.compile( r'^\s*\.\.\s+(current)?module::\s*([a-zA-Z0-9_.]+)\s*$') autosummary_item_re = re.compile(r'^\s+(~?[_a-zA-Z][a-zA-Z0-9_.]*)\s*.*?') + recursive_arg_re = re.compile(r'^\s+:recursive:\s*$') toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$') template_arg_re = re.compile(r'^\s+:template:\s*(.*?)\s*$') documented = [] # type: List[AutosummaryEntry] + recursive = False toctree = None # type: str template = None current_module = module @@ -377,6 +510,11 @@ def find_autosummary_in_lines(lines: List[str], module: Any = None, filename: st for line in lines: if in_autosummary: + m = recursive_arg_re.match(line) + if m: + recursive = True + continue + m = toctree_arg_re.match(line) if m: toctree = m.group(1) @@ -401,7 +539,7 @@ def find_autosummary_in_lines(lines: List[str], module: Any = None, filename: st if current_module and \ not name.startswith(current_module + '.'): name = "%s.%s" % (current_module, name) - documented.append(AutosummaryEntry(name, toctree, template)) + documented.append(AutosummaryEntry(name, toctree, template, recursive)) continue if not line.strip() or line.startswith(base_indent + " "): @@ -413,6 +551,7 @@ def find_autosummary_in_lines(lines: List[str], module: Any = None, filename: st if m: in_autosummary = True base_indent = m.group(1) + recursive = False toctree = None template = None continue @@ -478,14 +617,18 @@ The format of the autosummary directive is documented in the def main(argv: List[str] = sys.argv[1:]) -> None: sphinx.locale.setlocale(locale.LC_ALL, '') sphinx.locale.init_console(os.path.join(package_dir, 'locale'), 'sphinx') + translator, _ = sphinx.locale.init([], None) - app = DummyApplication() + app = DummyApplication(translator) logging.setup(app, sys.stdout, sys.stderr) # type: ignore setup_documenters(app) args = get_parser().parse_args(argv) + + if args.templates: + app.config.templates_path.append(path.abspath(args.templates)) + generate_autosummary_docs(args.source_file, args.output_dir, '.' + args.suffix, - template_dir=args.templates, imported_members=args.imported_members, app=app) diff --git a/sphinx/ext/autosummary/templates/autosummary/class.rst b/sphinx/ext/autosummary/templates/autosummary/class.rst index 8861b79a9..0f7d6f32e 100644 --- a/sphinx/ext/autosummary/templates/autosummary/class.rst +++ b/sphinx/ext/autosummary/templates/autosummary/class.rst @@ -8,7 +8,7 @@ .. automethod:: __init__ {% if methods %} - .. rubric:: Methods + .. rubric:: {{ _('Methods') }} .. autosummary:: {% for item in methods %} @@ -19,7 +19,7 @@ {% block attributes %} {% if attributes %} - .. rubric:: Attributes + .. rubric:: {{ _('Attributes') }} .. autosummary:: {% for item in attributes %} diff --git a/sphinx/ext/autosummary/templates/autosummary/module.rst b/sphinx/ext/autosummary/templates/autosummary/module.rst index 6ec89e05e..3a93e872a 100644 --- a/sphinx/ext/autosummary/templates/autosummary/module.rst +++ b/sphinx/ext/autosummary/templates/autosummary/module.rst @@ -2,9 +2,20 @@ .. automodule:: {{ fullname }} + {% block attributes %} + {% if attributes %} + .. rubric:: Module Attributes + + .. autosummary:: + {% for item in attributes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + {% block functions %} {% if functions %} - .. rubric:: Functions + .. rubric:: {{ _('Functions') }} .. autosummary:: {% for item in functions %} @@ -15,7 +26,7 @@ {% block classes %} {% if classes %} - .. rubric:: Classes + .. rubric:: {{ _('Classes') }} .. autosummary:: {% for item in classes %} @@ -26,7 +37,7 @@ {% block exceptions %} {% if exceptions %} - .. rubric:: Exceptions + .. rubric:: {{ _('Exceptions') }} .. autosummary:: {% for item in exceptions %} @@ -34,3 +45,16 @@ {%- endfor %} {% endif %} {% endblock %} + +{% block modules %} +{% if modules %} +.. rubric:: Modules + +.. autosummary:: + :toctree: + :recursive: +{% for item in modules %} + {{ item }} +{%- endfor %} +{% endif %} +{% endblock %} diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index 645521f9b..26966016d 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -47,7 +47,7 @@ doctestopt_re = re.compile(r'#\s*doctest:.+$', re.MULTILINE) def doctest_encode(text: str, encoding: str) -> str: warnings.warn('doctest_encode() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) return text diff --git a/sphinx/ext/imgconverter.py b/sphinx/ext/imgconverter.py index 3af93b642..bf4b9b9d1 100644 --- a/sphinx/ext/imgconverter.py +++ b/sphinx/ext/imgconverter.py @@ -9,6 +9,7 @@ """ import subprocess +import sys from subprocess import CalledProcessError, PIPE from typing import Any, Dict @@ -74,8 +75,17 @@ class ImagemagickConverter(ImageConverter): def setup(app: Sphinx) -> Dict[str, Any]: app.add_post_transform(ImagemagickConverter) - app.add_config_value('image_converter', 'convert', 'env') - app.add_config_value('image_converter_args', [], 'env') + if sys.platform == 'win32': + # On Windows, we use Imagemagik v7 by default to avoid the trouble for + # convert.exe bundled with Windows. + app.add_config_value('image_converter', 'magick', 'env') + app.add_config_value('image_converter_args', ['convert'], 'env') + else: + # On other platform, we use Imagemagick v6 by default. Especially, + # Debian/Ubuntu are still based of v6. So we can't use "magick" command + # for these platforms. + app.add_config_value('image_converter', 'convert', 'env') + app.add_config_value('image_converter_args', [], 'env') return { 'version': 'builtin', diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py index e13dcbeb7..cc3cd4ba3 100644 --- a/sphinx/ext/mathjax.py +++ b/sphinx/ext/mathjax.py @@ -96,7 +96,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: # more information for mathjax secure url is here: # https://docs.mathjax.org/en/latest/start.html#secure-access-to-the-cdn app.add_config_value('mathjax_path', - 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?' + 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?' 'config=TeX-AMS-MML_HTMLorMML', 'html') app.add_config_value('mathjax_options', {}, 'html') app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html') diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py index 10b1ff3a3..9b41152fc 100644 --- a/sphinx/ext/napoleon/__init__.py +++ b/sphinx/ext/napoleon/__init__.py @@ -168,11 +168,10 @@ class Config: **If False**:: .. attribute:: attr1 + :type: int Description of `attr1` - :type: int - napoleon_use_param : :obj:`bool` (Defaults to True) True to use a ``:param:`` role for each function parameter. False to use a single ``:parameters:`` role for all the parameters. diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py index 820de6ee4..32edd7f8f 100644 --- a/sphinx/ext/napoleon/docstring.py +++ b/sphinx/ext/napoleon/docstring.py @@ -30,7 +30,9 @@ _google_section_regex = re.compile(r'^(\s|\w)+:\s*$') _google_typed_arg_regex = re.compile(r'\s*(.+?)\s*\(\s*(.*[^\s]+)\s*\)') _numpy_section_regex = re.compile(r'^[=\-`:\'"~^_*+#<>]{2,}\s*$') _single_colon_regex = re.compile(r'(?<!:):(?!:)') -_xref_regex = re.compile(r'(:(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:`.+?`)') +_xref_or_code_regex = re.compile( + r'((?::(?:[a-zA-Z0-9]+[\-_+:.])*[a-zA-Z0-9]+:`.+?`)|' + r'(?:``.+``))') _bullet_list_regex = re.compile(r'^(\*|\+|\-)(\s+\S|\s*$)') _enumerated_list_regex = re.compile( r'^(?P<paren>\()?' @@ -316,7 +318,7 @@ class GoogleDocstring: return [line[min_indent:] for line in lines] def _escape_args_and_kwargs(self, name: str) -> str: - if name.endswith('_'): + if name.endswith('_') and getattr(self._config, 'strip_signature_backslash', False): name = name[:-1] + r'\_' if name[:2] == '**': @@ -586,13 +588,12 @@ class GoogleDocstring: lines.append('.. attribute:: ' + _name) if self._opt and 'noindex' in self._opt: lines.append(' :noindex:') + if _type: + lines.extend(self._indent([':type: %s' % _type], 3)) lines.append('') fields = self._format_field('', '', _desc) lines.extend(self._indent(fields, 3)) - if _type: - lines.append('') - lines.extend(self._indent([':type: %s' % _type], 3)) lines.append('') if self._config.napoleon_use_ivar: lines.append('') @@ -728,7 +729,7 @@ class GoogleDocstring: after_colon = [] colon = '' found_colon = False - for i, source in enumerate(_xref_regex.split(line)): + for i, source in enumerate(_xref_or_code_regex.split(line)): if found_colon: after_colon.append(source) else: diff --git a/sphinx/ext/napoleon/iterators.py b/sphinx/ext/napoleon/iterators.py index e91a3ec14..fc41afdb3 100644 --- a/sphinx/ext/napoleon/iterators.py +++ b/sphinx/ext/napoleon/iterators.py @@ -11,7 +11,7 @@ """ import collections -from typing import Any, Iterable +from typing import Any, Iterable, Optional class peek_iter: @@ -62,7 +62,7 @@ class peek_iter: def __next__(self, n: int = None) -> Any: return self.next(n) - def _fillcache(self, n: int) -> None: + def _fillcache(self, n: Optional[int]) -> None: """Cache `n` items. If `n` is 0 or None, then 1 item is cached.""" if not n: n = 1 @@ -123,7 +123,7 @@ class peek_iter: result = [self._cache.popleft() for i in range(n)] return result - def peek(self, n: int = None) -> Any: + def peek(self, n: Optional[int] = None) -> Any: """Preview the next item or `n` items of the iterator. The iterator is not advanced when peek is called. @@ -220,7 +220,7 @@ class modify_iter(peek_iter): 'modifier must be callable') super().__init__(*args) - def _fillcache(self, n: int) -> None: + def _fillcache(self, n: Optional[int]) -> None: """Cache `n` modified items. If `n` is 0 or None, 1 item is cached. Each item returned by the iterator is passed through the diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py index c5cacc437..bfb46903f 100644 --- a/sphinx/ext/todo.py +++ b/sphinx/ext/todo.py @@ -105,7 +105,7 @@ class TodoDomain(Domain): def process_todos(app: Sphinx, doctree: nodes.document) -> None: - warnings.warn('process_todos() is deprecated.', RemovedInSphinx40Warning) + warnings.warn('process_todos() is deprecated.', RemovedInSphinx40Warning, stacklevel=2) # collect all todos in the environment # this is not done in the directive itself because it some transformations # must have already been run, e.g. substitutions @@ -221,7 +221,8 @@ def process_todo_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str) - """Replace all todolist nodes with a list of the collected todos. Augment each todo with a backlink to the original location. """ - warnings.warn('process_todo_nodes() is deprecated.', RemovedInSphinx40Warning) + warnings.warn('process_todo_nodes() is deprecated.', + RemovedInSphinx40Warning, stacklevel=2) domain = cast(TodoDomain, app.env.get_domain('todo')) todos = sum(domain.todos.values(), []) # type: List[todo_node] @@ -273,7 +274,7 @@ def process_todo_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str) - def purge_todos(app: Sphinx, env: BuildEnvironment, docname: str) -> None: - warnings.warn('purge_todos() is deprecated.', RemovedInSphinx40Warning) + warnings.warn('purge_todos() is deprecated.', RemovedInSphinx40Warning, stacklevel=2) if not hasattr(env, 'todo_all_todos'): return env.todo_all_todos = [todo for todo in env.todo_all_todos # type: ignore @@ -282,7 +283,7 @@ def purge_todos(app: Sphinx, env: BuildEnvironment, docname: str) -> None: def merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str], other: BuildEnvironment) -> None: - warnings.warn('merge_info() is deprecated.', RemovedInSphinx40Warning) + warnings.warn('merge_info() is deprecated.', RemovedInSphinx40Warning, stacklevel=2) if not hasattr(other, 'todo_all_todos'): return if not hasattr(env, 'todo_all_todos'): diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index dc24a1993..a2eeb7891 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -131,8 +131,10 @@ def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str], def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnode: Node ) -> Node: - # resolve our "viewcode" reference nodes -- they need special treatment - if node['reftype'] == 'viewcode': + if app.builder.format != 'html': + return None + elif node['reftype'] == 'viewcode': + # resolve our "viewcode" reference nodes -- they need special treatment return make_refnode(app.builder, node['refdoc'], node['reftarget'], node['refid'], contnode) diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index 9812355ca..385ca3566 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -12,12 +12,12 @@ import gettext import locale from collections import UserString, defaultdict from gettext import NullTranslations -from typing import Any, Callable, Dict, Iterable, List, Tuple, Union +from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union class _TranslationProxy(UserString): """ - Class for proxy strings from gettext translations. This is a helper for the + Class for proxy strings from gettext translations. This is a helper for the lazy_* functions from this module. The proxy implementation attempts to be as complete as possible, so that @@ -109,7 +109,7 @@ translators = defaultdict(NullTranslations) # type: Dict[Tuple[str, str], NullT def init(locale_dirs: List[str], language: str, catalog: str = 'sphinx', namespace: str = 'general') -> Tuple[NullTranslations, bool]: """Look for message catalogs in `locale_dirs` and *ensure* that there is at - least a NullTranslations catalog set in `translators`. If called multiple + least a NullTranslations catalog set in `translators`. If called multiple times or if several ``.mo`` files are found, their contents are merged together (thus making ``init`` reentrant). """ @@ -173,7 +173,7 @@ def init_console(locale_dir: str, catalog: str) -> Tuple[NullTranslations, bool] """ try: # encoding is ignored - language, _ = locale.getlocale(locale.LC_MESSAGES) + language, _ = locale.getlocale(locale.LC_MESSAGES) # type: Tuple[Optional[str], Any] except AttributeError: # LC_MESSAGES is not always defined. Fallback to the default language # in case it is not. diff --git a/sphinx/locale/ar/LC_MESSAGES/sphinx.po b/sphinx/locale/ar/LC_MESSAGES/sphinx.po index 7c5e68004..bd69d2aeb 100644 --- a/sphinx/locale/ar/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ar/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "تشغيل Sphinx v%s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/bg/LC_MESSAGES/sphinx.po b/sphinx/locale/bg/LC_MESSAGES/sphinx.po index 0f59aac78..79329a57a 100644 --- a/sphinx/locale/bg/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/bg/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/bn/LC_MESSAGES/sphinx.po b/sphinx/locale/bn/LC_MESSAGES/sphinx.po index c4c4fbc53..63aae6877 100644 --- a/sphinx/locale/bn/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/bn/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/ca/LC_MESSAGES/sphinx.po b/sphinx/locale/ca/LC_MESSAGES/sphinx.po index 08d882a09..6a8e317b1 100644 --- a/sphinx/locale/ca/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ca/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/cak/LC_MESSAGES/sphinx.po b/sphinx/locale/cak/LC_MESSAGES/sphinx.po index 0fb5d1b93..b729d5f1f 100644 --- a/sphinx/locale/cak/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/cak/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "Rusachoj kamulunem:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "Ruch'ab'äl samaj" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/cs/LC_MESSAGES/sphinx.po b/sphinx/locale/cs/LC_MESSAGES/sphinx.po index 1f6ec0753..8952713e1 100644 --- a/sphinx/locale/cs/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/cs/LC_MESSAGES/sphinx.po @@ -42,7 +42,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1132,7 +1132,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1169,7 +1169,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1456,7 +1456,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1485,7 +1485,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/cy/LC_MESSAGES/sphinx.po b/sphinx/locale/cy/LC_MESSAGES/sphinx.po index 6830334d8..12f2aecd2 100644 --- a/sphinx/locale/cy/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/cy/LC_MESSAGES/sphinx.po @@ -42,7 +42,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1132,7 +1132,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1169,7 +1169,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1456,7 +1456,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1485,7 +1485,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/da/LC_MESSAGES/sphinx.po b/sphinx/locale/da/LC_MESSAGES/sphinx.po index 1948fa632..317b832d2 100644 --- a/sphinx/locale/da/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/da/LC_MESSAGES/sphinx.po @@ -43,7 +43,7 @@ msgstr "Kører Sphinx v%s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1133,7 +1133,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1170,7 +1170,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1457,7 +1457,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1486,7 +1486,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/de/LC_MESSAGES/sphinx.po b/sphinx/locale/de/LC_MESSAGES/sphinx.po index da1d031bd..8d5cd4e43 100644 --- a/sphinx/locale/de/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/de/LC_MESSAGES/sphinx.po @@ -44,7 +44,7 @@ msgstr "Sphinx v%s in Verwendung" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1134,7 +1134,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1171,7 +1171,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1458,7 +1458,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1487,7 +1487,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/el/LC_MESSAGES/sphinx.mo b/sphinx/locale/el/LC_MESSAGES/sphinx.mo Binary files differindex e1d1d4a21..d40fcac72 100644 --- a/sphinx/locale/el/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/el/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/el/LC_MESSAGES/sphinx.po b/sphinx/locale/el/LC_MESSAGES/sphinx.po index 7555009b1..54eb341ec 100644 --- a/sphinx/locale/el/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/el/LC_MESSAGES/sphinx.po @@ -42,7 +42,7 @@ msgstr "ΕκτÎλεση Sphinx Îκδοση %s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1132,7 +1132,7 @@ msgstr "Σφάλμα αναδÏομής:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "Αυτό μποÏεί να συμβεί με Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î± ή βαθιά εμφωλιασμÎνα αÏχεία πηγής. ΜποÏείτε Ï€Ïοσεκτικά να αυξήσετε την Ï€ÏοεπιλεγμÎνη τιμή αναδÏομικότητας Python στο conf.py με Ï€.χ.:" @@ -1169,7 +1169,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1456,7 +1456,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1485,7 +1485,7 @@ msgstr "Γλώσσα ÎÏγου" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 @@ -2447,7 +2447,7 @@ msgstr "τοποθÎτηση βιβλιογÏαφίας δομοστοιχείο msgid "" "interpret module paths according to PEP-0420 implicit namespaces " "specification" -msgstr "εÏμηνεία μονοπατιών δομοστοιχείων σÏμφωνα με την Ï€ÏοδιαγÏαφή POP-0420 αυτονόητων namespaces" +msgstr "εÏμηνεία μονοπατιών δομοστοιχείων σÏμφωνα με την Ï€ÏοδιαγÏαφή POP-0420 αυτονόητων namespaces" #: sphinx/ext/apidoc.py:411 msgid "file suffix (default: rst)" diff --git a/sphinx/locale/eo/LC_MESSAGES/sphinx.po b/sphinx/locale/eo/LC_MESSAGES/sphinx.po index 32bc8114a..6c94360c6 100644 --- a/sphinx/locale/eo/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/eo/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/es/LC_MESSAGES/sphinx.mo b/sphinx/locale/es/LC_MESSAGES/sphinx.mo Binary files differindex 05ac10c87..bd4be1841 100644 --- a/sphinx/locale/es/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/es/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/es/LC_MESSAGES/sphinx.po b/sphinx/locale/es/LC_MESSAGES/sphinx.po index 5153023e5..be149e88a 100644 --- a/sphinx/locale/es/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/es/LC_MESSAGES/sphinx.po @@ -47,7 +47,7 @@ msgstr "Ejecutando Sphinx v%s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "Por razones de seguridad, el modo paralelo está deshabilitado en macOS y python3.8 y superior. Para más detalles, lea https://github.com/sphinx-doc/sphinx/issues/6803" @@ -154,7 +154,7 @@ msgid "" "the %s extension does not declare if it is safe for parallel reading, " "assuming it isn't - please ask the extension author to check and make it " "explicit" -msgstr "la extensión de %s no declara si es seguro para la lectura en paralelo, asumiendo que no es - consulte con el autor de la extensión para comprobar y hacer explÃcito" +msgstr "la extensión de %s no declara si es seguro para la lectura en paralelo, asumiendo que no es - consulte con el autor de la extensión para comprobar y hacer explÃcito" #: sphinx/application.py:1128 #, python-format @@ -1137,7 +1137,7 @@ msgstr "Error de recursión:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "Esto puede suceder con archivos fuente muy grandes o profundamente anidados. Puede aumentar cuidadosamente el lÃmite de recursión de Python predeterminado de 1000 en el archivo conf.py con, por ejemplo:" @@ -1174,7 +1174,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1184,7 +1184,7 @@ msgid "" "\n" "By default, everything that is outdated is built. Output only for selected\n" "files can be built by specifying individual filenames.\n" -msgstr "\nGenerar documentación a partir de archivos fuente.\n\nsphinx-build genera documentación de los archivos en SOURCEDIR y la coloca\nen OUTPUTDIR. Busca el archivo 'conf.py' en SOURCEDIR para los ajustes de la \nconfiguración. La herramienta 'sphinx-quickstart' puede usarse para generar archivos de plantilla,\nincluyendo el archivo 'conf.py'\n\nsphinx-build puede crear documentación en diferentes formatos. Un formato es\nseleccionado especificando el nombre del constructor en la lÃnea de comando; por defecto es\nHTML. Los constructores también pueden realizar otras tareas relacionadas con la\ndocumentación.\n\nPor defecto, todo lo que está desactualizado está construido. Salida solo para los archivos\nseleccionados se pueden construir especificando nombres de archivo individuales.\n" +msgstr "\nGenerar documentación a partir de archivos fuente.\n\nsphinx-build genera documentación de los archivos en SOURCEDIR y la coloca\nen OUTPUTDIR. Busca el archivo 'conf.py' en SOURCEDIR para los ajustes de la \nconfiguración. La herramienta 'sphinx-quickstart' puede usarse para generar archivos de plantilla,\nincluyendo el archivo 'conf.py'\n\nsphinx-build puede crear documentación en diferentes formatos. Un formato es\nseleccionado especificando el nombre del constructor en la lÃnea de comando; por defecto es\nHTML. Los constructores también pueden realizar otras tareas relacionadas con la\ndocumentación.\n\nPor defecto, todo lo que está desactualizado está construido. Salida solo para los archivos\nseleccionados se pueden construir especificando nombres de archivo individuales.\n" #: sphinx/cmd/build.py:122 msgid "path to documentation source files" @@ -1461,7 +1461,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "Sphinx tiene la noción de una \"version\" y un \"release\" para el\nsoftware. Cada versión puede tener múltiples versiones. Por ejemplo, para\nPython la versión es algo asà como 2.5 o 3.0, mientras que el lanzamiento es\nalgo asà como 2.5.1 o 3.0a1. Si no necesita esta estructura dual,\nsolo establezca ambos en el mismo valor." @@ -1490,7 +1490,7 @@ msgstr "Lenguaje del proyecto" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "El sufijo del nombre de archivo para los archivos de origen. Comúnmente, esto es \".txt\"\no \".rst\". Solo los archivos con este sufijo se consideran documentos." #: sphinx/cmd/quickstart.py:300 @@ -2617,7 +2617,7 @@ msgstr "[gráfica]" #: sphinx/ext/imgconverter.py:41 sphinx/ext/imgconverter.py:65 #, python-format msgid "convert command %r cannot be run, check the image_converter setting" -msgstr "el comando convert %r no puede ejecutar, compruebe el valor de configuración image_converter" +msgstr "el comando convert %r no puede ejecutar, compruebe el valor de configuración image_converter" #: sphinx/ext/imgconverter.py:46 sphinx/ext/imgconverter.py:70 #, python-format diff --git a/sphinx/locale/et/LC_MESSAGES/sphinx.mo b/sphinx/locale/et/LC_MESSAGES/sphinx.mo Binary files differindex 0a01f5047..b5d83dbf8 100644 --- a/sphinx/locale/et/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/et/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/et/LC_MESSAGES/sphinx.po b/sphinx/locale/et/LC_MESSAGES/sphinx.po index def0d2e34..a87de4d11 100644 --- a/sphinx/locale/et/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/et/LC_MESSAGES/sphinx.po @@ -44,7 +44,7 @@ msgstr "Sphinx v%s käitamine" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1134,7 +1134,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1171,7 +1171,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1458,7 +1458,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1487,7 +1487,7 @@ msgstr "Projekti keel" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/eu/LC_MESSAGES/sphinx.po b/sphinx/locale/eu/LC_MESSAGES/sphinx.po index a72468c9a..80dbae5a3 100644 --- a/sphinx/locale/eu/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/eu/LC_MESSAGES/sphinx.po @@ -42,7 +42,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1132,7 +1132,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1169,7 +1169,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1456,7 +1456,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1485,7 +1485,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/fa/LC_MESSAGES/sphinx.po b/sphinx/locale/fa/LC_MESSAGES/sphinx.po index 6f1c35df2..ddca8112c 100644 --- a/sphinx/locale/fa/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/fa/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/fi/LC_MESSAGES/sphinx.po b/sphinx/locale/fi/LC_MESSAGES/sphinx.po index 3d004d801..19233894d 100644 --- a/sphinx/locale/fi/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/fi/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/fr/LC_MESSAGES/sphinx.mo b/sphinx/locale/fr/LC_MESSAGES/sphinx.mo Binary files differindex 848d762c8..25bdd0d82 100644 --- a/sphinx/locale/fr/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/fr/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/fr/LC_MESSAGES/sphinx.po b/sphinx/locale/fr/LC_MESSAGES/sphinx.po index 2252e8a19..b01d956c0 100644 --- a/sphinx/locale/fr/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/fr/LC_MESSAGES/sphinx.po @@ -61,7 +61,7 @@ msgstr "Sphinx v%s en cours d'exécution" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -321,7 +321,7 @@ msgstr "Nom d'évènement inconnu : %s" msgid "" "The %s extension is required by needs_extensions settings, but it is not " "loaded." -msgstr "L'extension %s est exigée par le paramètre needs_extensions, mais n'est pas chargée." +msgstr "L'extension %s est exigée par le paramètre needs_extensions, mais n'est pas chargée." #: sphinx/extension.py:56 #, python-format @@ -1151,7 +1151,7 @@ msgstr "Erreur de récursion :" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "Cela peut se produire avec des fichiers sources très volumineux ou profondément imbriqués. Vous pouvez soigneusement augmenter la limite de récursivité par défaut de Python de 1000 dans conf.py avec p. ex. :" @@ -1188,7 +1188,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1475,7 +1475,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1504,7 +1504,7 @@ msgstr "Langue du projet" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 @@ -2611,7 +2611,7 @@ msgstr "dot a terminé avec une erreur :\n[stderr]\n%r\n[stdout]\n%r" #: sphinx/ext/graphviz.py:269 #, python-format msgid "graphviz_output_format must be one of 'png', 'svg', but is %r" -msgstr "graphviz_output_format doit être « png » ou « svg », mais est %r" +msgstr "graphviz_output_format doit être « png » ou « svg », mais est %r" #: sphinx/ext/graphviz.py:273 sphinx/ext/graphviz.py:324 #: sphinx/ext/graphviz.py:361 diff --git a/sphinx/locale/he/LC_MESSAGES/sphinx.po b/sphinx/locale/he/LC_MESSAGES/sphinx.po index 159c60070..7332af27f 100644 --- a/sphinx/locale/he/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/he/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/hi/LC_MESSAGES/sphinx.mo b/sphinx/locale/hi/LC_MESSAGES/sphinx.mo Binary files differindex 56881c96f..d93d5cf7d 100644 --- a/sphinx/locale/hi/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/hi/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/hi/LC_MESSAGES/sphinx.po b/sphinx/locale/hi/LC_MESSAGES/sphinx.po index 6409fb8a6..7fd40316b 100644 --- a/sphinx/locale/hi/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/hi/LC_MESSAGES/sphinx.po @@ -44,7 +44,7 @@ msgstr "सà¥à¤«à¤¿à¤‚कà¥à¤¸ %s संसà¥à¤•à¤°à¤£ चल रहा हॠ#: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "सà¥à¤°à¤•à¥à¤·à¤¾ कारण वरà¥à¤· macOS तथा python 3.8 और अधिक, के साथ समानांतर कारà¥à¤¯ शैली कि सà¥à¤µà¤¿à¤§à¤¾ उपलबà¥à¤§ नहीं हैं | अधिक जानकारी के लिà¤, कृपया \"https://github.com/sphinx-doc/sphinx/issues/6803\" पà¥à¥‡ |" @@ -1134,7 +1134,7 @@ msgstr "पà¥à¤¨à¤°à¤¾à¤µà¤°à¥à¤¤à¤¨ तà¥à¤°à¥à¤Ÿà¤¿:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "à¤à¤¸à¤¾ बहà¥à¤¤ बड़ी अथवा गहरे सà¥à¤¤à¤° तक गई सà¥à¤°à¥‹à¤¤ फाइलों से संà¤à¤µ है. आप सà¥à¤µà¤¤à¤ƒ मानक पाइथन पà¥à¤¨à¤°à¤¾à¤µà¤°à¥à¤¤à¤¨ सीमा 1000 को conf.py में बाधा सकते हैं. जैसे कि:" @@ -1171,7 +1171,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1458,7 +1458,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "सà¥à¤«à¤¿à¤‚कà¥à¤¸ सॉफà¥à¤Ÿà¤µà¥‡à¤¯à¤° के लिठसंसà¥à¤•à¤°à¤£ और आवृतà¥à¤¤à¤¿ को मानà¥à¤¯à¤¤à¤¾ देता है.\nहर संसà¥à¤•à¤°à¤£ की कई आवृतà¥à¤¤à¤¿à¤¯à¤¾à¤ हो सकती हैं. उदाहरण के लिà¤,\nपाइथन संसà¥à¤•à¤°à¤£ 2.5 अथवा 3.0 आदि हैं, और आवृतà¥à¤¤à¤¿\n2.5.1 अथवा 3.0a1 आदि हैं. यदि आपको इसे दो सà¥à¤¤à¤° पर रखना नहीं चाहिà¤\nतो दोनों मान à¤à¤• ही रख दें." @@ -1487,7 +1487,7 @@ msgstr "परियोजना की à¤à¤¾à¤·à¤¾" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 @@ -2789,7 +2789,7 @@ msgstr "सà¥à¤µà¤¤à¤ƒ-पà¥à¤°à¤à¤¾à¤— %s के लिठहसà¥à¤¤à¤¾à¤ msgid "" "__all__ should be a list of strings, not %r (in module %s) -- ignoring " "__all__" -msgstr "__all__ अंतिम अकà¥à¤·à¤°à¤®à¤¾à¤²à¤¾ होनी चाहिà¤, न कि %r (%s पà¥à¤°à¤à¤¾à¤— में) -- __all__ की उपेकà¥à¤·à¤¾ की जाà¤à¤—ी" +msgstr "__all__ अंतिम अकà¥à¤·à¤°à¤®à¤¾à¤²à¤¾ होनी चाहिà¤, न कि %r (%s पà¥à¤°à¤à¤¾à¤— में) -- __all__ की उपेकà¥à¤·à¤¾ की जाà¤à¤—ी" #: sphinx/ext/autodoc/__init__.py:852 #, python-format diff --git a/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po b/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po index 11a951750..78f66e29e 100644 --- a/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/hr/LC_MESSAGES/sphinx.mo b/sphinx/locale/hr/LC_MESSAGES/sphinx.mo Binary files differindex 999b8cada..777096ba6 100644 --- a/sphinx/locale/hr/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/hr/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/hr/LC_MESSAGES/sphinx.po b/sphinx/locale/hr/LC_MESSAGES/sphinx.po index 81e7e9bf3..c1f1d4be0 100644 --- a/sphinx/locale/hr/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/hr/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "Izrada pomoću Sphinx v%s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -449,7 +449,7 @@ msgstr "%s proÅ¡irenje traži Sphinx verzije v%s; stoga projekt ne može biti iz msgid "" "extension %r returned an unsupported object from its setup() function; it " "should return None or a metadata dictionary" -msgstr "proÅ¡irenje %r vratio je nepodržan objekt iz setup() funkcije; rezultat treba biti None ili rijeÄnik metapodataka" +msgstr "proÅ¡irenje %r vratio je nepodržan objekt iz setup() funkcije; rezultat treba biti None ili rijeÄnik metapodataka" #: sphinx/roles.py:221 sphinx/roles.py:271 #, python-format @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/hu/LC_MESSAGES/sphinx.po b/sphinx/locale/hu/LC_MESSAGES/sphinx.po index e9e7a5291..fe58d1895 100644 --- a/sphinx/locale/hu/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/hu/LC_MESSAGES/sphinx.po @@ -45,7 +45,7 @@ msgstr "Sphinx %s verzió futtatása" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1135,7 +1135,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1172,7 +1172,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1459,7 +1459,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1488,7 +1488,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/id/LC_MESSAGES/sphinx.mo b/sphinx/locale/id/LC_MESSAGES/sphinx.mo Binary files differindex cdc79da48..01095a9db 100644 --- a/sphinx/locale/id/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/id/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/id/LC_MESSAGES/sphinx.po b/sphinx/locale/id/LC_MESSAGES/sphinx.po index ce2847c33..d11a59d35 100644 --- a/sphinx/locale/id/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/id/LC_MESSAGES/sphinx.po @@ -45,9 +45,9 @@ msgstr "Menjalankan Sphinx v%s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" -msgstr "Untuk alasan keamanan, mode paralel dinonaktifkan di macOS dan python3.8 dan di atasnya. Untuk detail lebih lanjut, silakan baca https://github.com/sphinx-doc/sphinx/issues/6803" +msgstr "Untuk alasan keamanan, mode paralel dinonaktifkan di macOS dan python3.8 dan di atasnya. Untuk detail lebih lanjut, silakan baca https://github.com/sphinx-doc/sphinx/issues/6803" #: sphinx/application.py:226 #, python-format @@ -1135,7 +1135,7 @@ msgstr "Kesalahan rekursi:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "Hal ini dapat terjadi dengan berkas sumber yang besar atau sangat dalam bertingkat. Anda dapat secara hati-hati meningkatkan batas standar recursi Python dari 1000 di conf.py contohnya:" @@ -1172,7 +1172,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1182,7 +1182,7 @@ msgid "" "\n" "By default, everything that is outdated is built. Output only for selected\n" "files can be built by specifying individual filenames.\n" -msgstr "\nMenghasilkan dokumentasi ari berkas sumber.\n\nsphinx-build menghasilkan dokumentasi dari berkas-berkas di SOURCEDIR dan menyimpannya\ndi OUTPUTDIR. Program tersebut mencari berkas 'conf.py' di SOURCEDIR untuk pengaturan\nkonfigurasinya. Alat 'sphinx-quickstart' dapat digunakan untuk menghasilkan berkas templat,\ntermasuk 'conf.py'\n\nsphinx-build dapat membuat dokumentasi dalam beragam format. Sebuah format\ndipilih berdasarkan nama builder pada command line; standarnya\nHTML. Builders pun dapat menjalankan tugas lainnya berhubungan dengan pemrosesan\ndocumentasi.\n\nSecara umum, semua yang usang akan dibuat. Output hanya untuk berkas\npilihan dapat dibuat dengan menentukan berkas satuan.\n" +msgstr "\nMenghasilkan dokumentasi ari berkas sumber.\n\nsphinx-build menghasilkan dokumentasi dari berkas-berkas di SOURCEDIR dan menyimpannya\ndi OUTPUTDIR. Program tersebut mencari berkas 'conf.py' di SOURCEDIR untuk pengaturan\nkonfigurasinya. Alat 'sphinx-quickstart' dapat digunakan untuk menghasilkan berkas templat,\ntermasuk 'conf.py'\n\nsphinx-build dapat membuat dokumentasi dalam beragam format. Sebuah format\ndipilih berdasarkan nama builder pada command line; standarnya\nHTML. Builders pun dapat menjalankan tugas lainnya berhubungan dengan pemrosesan\ndocumentasi.\n\nSecara umum, semua yang usang akan dibuat. Output hanya untuk berkas\npilihan dapat dibuat dengan menentukan berkas satuan.\n" #: sphinx/cmd/build.py:122 msgid "path to documentation source files" @@ -1459,7 +1459,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1488,7 +1488,7 @@ msgstr "Bahasa proyek" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/it/LC_MESSAGES/sphinx.po b/sphinx/locale/it/LC_MESSAGES/sphinx.po index bf9e5c33b..9c871d0d2 100644 --- a/sphinx/locale/it/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/it/LC_MESSAGES/sphinx.po @@ -45,7 +45,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1135,7 +1135,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1172,7 +1172,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1459,7 +1459,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1488,7 +1488,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/ja/LC_MESSAGES/sphinx.mo b/sphinx/locale/ja/LC_MESSAGES/sphinx.mo Binary files differindex 58ac45caa..6d27b0775 100644 --- a/sphinx/locale/ja/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/ja/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/ja/LC_MESSAGES/sphinx.po b/sphinx/locale/ja/LC_MESSAGES/sphinx.po index bec0732d3..d9299e58c 100644 --- a/sphinx/locale/ja/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ja/LC_MESSAGES/sphinx.po @@ -55,7 +55,7 @@ msgstr "Sphinx v%s を実行ä¸" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "ã‚»ã‚ュリティ上ã®ç†ç”±ã‹ã‚‰ã€macOSãŠã‚ˆã³python3.8以é™ã§ã¯ä¸¦åˆ—モードãŒç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚ 詳細ã«ã¤ã„ã¦ã¯ https://github.com/sphinx-doc/sphinx/issues/6803 ã‚’ã”覧ãã ã•ã„。" @@ -1145,7 +1145,7 @@ msgstr "å†èµ·å‘¼ã³å‡ºã—エラー:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "ã“ã®ä¾‹å¤–エラーã¯ã€éžå¸¸ã«å¤§ããªã€ã¾ãŸã¯æ·±ããƒã‚¹ãƒˆã•ã‚ŒãŸã‚½ãƒ¼ã‚¹ãƒ•ã‚¡ã‚¤ãƒ«ã§ç™ºç”Ÿã™ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚å†å¸°å‡¦ç†ã®å‘¼ã³å‡ºã—ã®ä¸Šé™å€¤ 1000 㯠conf.py ã§å¤‰æ›´ã§ãã¾ã™ãŒã€æ…Žé‡ã«è¡Œã£ã¦ãã ã•ã„。" @@ -1182,7 +1182,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1469,7 +1469,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "Sphinx ã«ã¯ã€ã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢ã«å¯¾ã—㦠\"ãƒãƒ¼ã‚¸ãƒ§ãƒ³\" 㨠\"リリース\" ã¨ã„ã†æ¦‚念ãŒ\nã‚ã‚Šã¾ã™ã€‚å„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¯è¤‡æ•°ã®ãƒªãƒªãƒ¼ã‚¹ã‚’æŒã¤ã“ã¨ãŒã§ãã¾ã™ã€‚\n例ãˆã°ã€Python ã ã¨ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒ 2.5 ã‚„ 3.0 ã®ã‚ˆã†ã«åˆ†ã‹ã‚Œã¦ã„るよã†ã«ã€\nリリースも 2.5.1 ã‚„ 3.0a1 ã®ã‚ˆã†ã«åˆ†ã‘ã¦æŒã¤ã“ã¨ãŒã§ãã¾ã™ã€‚ã‚‚ã—ã“ã®ã‚ˆã†ãªå¤šé‡æ§‹æˆãŒå¿…è¦ãªã„å ´åˆã¯ã€\n両方をåŒã˜å€¤ã«è¨å®šã™ã‚‹ã ã‘ã§ã™ã€‚" @@ -1498,7 +1498,7 @@ msgstr "プãƒã‚¸ã‚§ã‚¯ãƒˆã®è¨€èªž" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "æ‹¡å¼µåã®åå‰ã¯ã‚½ãƒ¼ã‚¹ãƒ•ã‚¡ã‚¤ãƒ«ã«ä½¿ã„ã¾ã™ã€‚\n通常㯠\".txt\" ã¾ãŸã¯ \".rst\" ã§ã™ã€‚ã“れらã®æ‹¡å¼µåã‚’æŒã¤ãƒ•ã‚¡ã‚¤ãƒ«ã®ã¿ãŒãƒ‰ã‚ュメントã¨è¦‹ãªã•ã‚Œã¾ã™ã€‚" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/ko/LC_MESSAGES/sphinx.mo b/sphinx/locale/ko/LC_MESSAGES/sphinx.mo Binary files differindex a9573bea1..baf3b48ca 100644 --- a/sphinx/locale/ko/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/ko/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/ko/LC_MESSAGES/sphinx.po b/sphinx/locale/ko/LC_MESSAGES/sphinx.po index 93c285e9b..bf3bbe78e 100644 --- a/sphinx/locale/ko/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ko/LC_MESSAGES/sphinx.po @@ -42,7 +42,7 @@ msgstr "Sphinx ë²„ì „ %s 실행 중" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1132,7 +1132,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1169,7 +1169,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1456,7 +1456,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1485,7 +1485,7 @@ msgstr "프로ì 트 언어" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/lt/LC_MESSAGES/sphinx.po b/sphinx/locale/lt/LC_MESSAGES/sphinx.po index 75f4f340f..fbf5b0a1d 100644 --- a/sphinx/locale/lt/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/lt/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/lv/LC_MESSAGES/sphinx.po b/sphinx/locale/lv/LC_MESSAGES/sphinx.po index 83edbcbfc..a3968756d 100644 --- a/sphinx/locale/lv/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/lv/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/mk/LC_MESSAGES/sphinx.po b/sphinx/locale/mk/LC_MESSAGES/sphinx.po index 7ca7371a7..5543d45fd 100644 --- a/sphinx/locale/mk/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/mk/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po b/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po index d91029b1a..b061b0361 100644 --- a/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/ne/LC_MESSAGES/sphinx.po b/sphinx/locale/ne/LC_MESSAGES/sphinx.po index 41c06cd81..46590097d 100644 --- a/sphinx/locale/ne/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ne/LC_MESSAGES/sphinx.po @@ -42,7 +42,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1132,7 +1132,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1169,7 +1169,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1456,7 +1456,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1485,7 +1485,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/nl/LC_MESSAGES/sphinx.po b/sphinx/locale/nl/LC_MESSAGES/sphinx.po index fab7b5cbf..d5eb16c6f 100644 --- a/sphinx/locale/nl/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/nl/LC_MESSAGES/sphinx.po @@ -46,7 +46,7 @@ msgstr "Sphinx v%s start op" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1136,7 +1136,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1173,7 +1173,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1460,7 +1460,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1489,7 +1489,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/pl/LC_MESSAGES/sphinx.po b/sphinx/locale/pl/LC_MESSAGES/sphinx.po index 97762625f..ac8488a45 100644 --- a/sphinx/locale/pl/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/pl/LC_MESSAGES/sphinx.po @@ -44,7 +44,7 @@ msgstr "Uruchamianie Sphinksa v%s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1134,7 +1134,7 @@ msgstr "BÅ‚Ä…d rekursji:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1171,7 +1171,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1458,7 +1458,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1487,7 +1487,7 @@ msgstr "JÄ™zyk projektu" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/pt/LC_MESSAGES/sphinx.po b/sphinx/locale/pt/LC_MESSAGES/sphinx.po index f8d4c9538..4b0c30cb7 100644 --- a/sphinx/locale/pt/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/pt/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo Binary files differindex 2dbc5028b..7cfa989d3 100644 --- a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po index eaed82dc2..dba58f93e 100644 --- a/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po @@ -46,7 +46,7 @@ msgstr "Executando Sphinx v%s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "Por motivos de segurança, o modo paralelo está desativado no macOS e python3.8 e superior. Para mais detalhes, leia https://github.com/sphinx-doc/sphinx/issues/6803" @@ -1136,7 +1136,7 @@ msgstr "Erro de recursão:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "Isso pode acontecer com arquivos-fonte muito grandes ou profundamente aninhados. Você pode aumentar cuidadosamente o limite de recursão padrão do Python de 1000 em conf.py, p.ex.:" @@ -1173,7 +1173,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1460,7 +1460,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "Sphinx tem a noção de uma \"versão\" e uma \"lançamento\" para o software.\nCada versão pode ter vários lançamentos. Por exemplo, para Python, a\nversão é algo como 2.5 ou 3.0, enquanto o lançamento é algo como 2.5.1\nou 3.0a1. Se você não precisar dessa estrutura dupla, basta definir as\nduas para o mesmo valor." @@ -1489,7 +1489,7 @@ msgstr "Idioma do projeto" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "O sufixo do nome do arquivo para os arquivos-fonte. Geralmente ele é\n\".txt\" ou \".rst\". Somente arquivos com esse sufixo são considerados\ndocumentos." #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po b/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po index 397e8eba6..7d219561a 100644 --- a/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po @@ -42,7 +42,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1132,7 +1132,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1169,7 +1169,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1456,7 +1456,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1485,7 +1485,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/ro/LC_MESSAGES/sphinx.po b/sphinx/locale/ro/LC_MESSAGES/sphinx.po index 01d623736..6a4591643 100644 --- a/sphinx/locale/ro/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ro/LC_MESSAGES/sphinx.po @@ -42,7 +42,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1132,7 +1132,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1169,7 +1169,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1456,7 +1456,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1485,7 +1485,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/ru/LC_MESSAGES/sphinx.po b/sphinx/locale/ru/LC_MESSAGES/sphinx.po index 525962670..e69207f4e 100644 --- a/sphinx/locale/ru/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ru/LC_MESSAGES/sphinx.po @@ -46,7 +46,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1136,7 +1136,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1173,7 +1173,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1460,7 +1460,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1489,7 +1489,7 @@ msgstr "Язык проекта" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/si/LC_MESSAGES/sphinx.po b/sphinx/locale/si/LC_MESSAGES/sphinx.po index 7f74034fd..a257711c5 100644 --- a/sphinx/locale/si/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/si/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/sk/LC_MESSAGES/sphinx.po b/sphinx/locale/sk/LC_MESSAGES/sphinx.po index 4e64c80a8..7d4bb2118 100644 --- a/sphinx/locale/sk/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sk/LC_MESSAGES/sphinx.po @@ -43,7 +43,7 @@ msgstr "Spúšťanie Sphinx v%s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1133,7 +1133,7 @@ msgstr "Chyba rekurzie:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1170,7 +1170,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1457,7 +1457,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1486,7 +1486,7 @@ msgstr "Jazyk projektu" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/sl/LC_MESSAGES/sphinx.po b/sphinx/locale/sl/LC_MESSAGES/sphinx.po index 3989e7f3e..80dde8bd0 100644 --- a/sphinx/locale/sl/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sl/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/sphinx.pot b/sphinx/locale/sphinx.pot index 39ed7ccca..4c47a9fb9 100644 --- a/sphinx/locale/sphinx.pot +++ b/sphinx/locale/sphinx.pot @@ -1136,7 +1136,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1174,7 +1174,7 @@ msgid "" "sphinx-build generates documentation from the files in SOURCEDIR and " "places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template " +"settings. The 'sphinx-quickstart' tool may be used to generate template " "files,\n" "including 'conf.py'\n" "\n" @@ -1467,7 +1467,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" diff --git a/sphinx/locale/sq/LC_MESSAGES/sphinx.mo b/sphinx/locale/sq/LC_MESSAGES/sphinx.mo Binary files differindex 5c0fa25ac..a3d4b12a9 100644 --- a/sphinx/locale/sq/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/sq/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/sq/LC_MESSAGES/sphinx.po b/sphinx/locale/sq/LC_MESSAGES/sphinx.po index 8d432f7ba..bf21f378d 100644 --- a/sphinx/locale/sq/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sq/LC_MESSAGES/sphinx.po @@ -40,9 +40,9 @@ msgstr "Po xhirohet Sphinx v%s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" -msgstr "Për arsye sigurie, mënyra paralele është e çaktivizuar në macOS dhe python3.8 dhe më sipër. Për më tepër hollësi, ju lutemi, lexoni https://github.com/sphinx-doc/sphinx/issues/6803" +msgstr "Për arsye sigurie, mënyra paralele është e çaktivizuar në macOS dhe python3.8 dhe më sipër. Për më tepër hollësi, ju lutemi, lexoni https://github.com/sphinx-doc/sphinx/issues/6803" #: sphinx/application.py:226 #, python-format @@ -1130,10 +1130,10 @@ msgstr "Gabim përsëritje:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" -msgstr "Kjo mund të ndodhë me kartela burim shumë të mëdha ose të futura thellë brenda njëra-tjetrës. Mund të rrisni me kujdes kufirin parazgjedhje për ripërsëritje Python prej 1000 te conf.py me p.sh.:" +msgstr "Kjo mund të ndodhë me kartela burim shumë të mëdha ose të futura thellë brenda njëra-tjetrës. Mund të rrisni me kujdes kufirin parazgjedhje për ripërsëritje Python prej 1000 te conf.py me p.sh.:" #: sphinx/cmd/build.py:67 msgid "Exception occurred:" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,9 +1454,9 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." -msgstr "Sphinx-i përdor nocionet e një \"versioni\" dhe një \"hedhjeje në qarkullim\" për\nsoftware-in. Çdo version mund të ketë hedhje të shumta në qarkullim. Bie\nfjala, për Python-in versionet ngjajnë me 2.5 ose 3.0, teksa hedhja në\nqarkullim ngjan me 2.5.1 ose 3.0a1. Nëse s’ju hyn në punë kjo strukturë\nduale, thjesht vëruni të dyjave të njëjtën vlerë." +msgstr "Sphinx-i përdor nocionet e një \"versioni\" dhe një \"hedhjeje në qarkullim\" për\nsoftware-in. Çdo version mund të ketë hedhje të shumta në qarkullim. Bie\nfjala, për Python-in versionet ngjajnë me 2.5 ose 3.0, teksa hedhja në\nqarkullim ngjan me 2.5.1 ose 3.0a1. Nëse s’ju hyn në punë kjo strukturë\nduale, thjesht vëruni të dyjave të njëjtën vlerë." #: sphinx/cmd/quickstart.py:280 msgid "Project version" @@ -1483,8 +1483,8 @@ msgstr "Gjuhë projekti" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." -msgstr "Prapashtesa e emrave të kartelave për kartela burim. Zakonisht, kjo\nështë ose \".txt\", ose \".rst\". Vetëm kartelat me këtë prapashtesë\nmerren si dokumente." +"or \".rst\". Only files with this suffix are considered documents." +msgstr "Prapashtesa e emrave të kartelave për kartela burim. Zakonisht, kjo\nështë ose \".txt\", ose \".rst\". Vetëm kartelat me këtë prapashtesë\nmerren si dokumente." #: sphinx/cmd/quickstart.py:300 msgid "Source file suffix" diff --git a/sphinx/locale/sr/LC_MESSAGES/sphinx.po b/sphinx/locale/sr/LC_MESSAGES/sphinx.po index 0aa8cef91..1df55881c 100644 --- a/sphinx/locale/sr/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sr/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "Покрећем Sphinx v%s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po b/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po index 4b92f65f2..a7b82e633 100644 --- a/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po b/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po index 1def1329a..dad4f3542 100644 --- a/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/sv/LC_MESSAGES/sphinx.po b/sphinx/locale/sv/LC_MESSAGES/sphinx.po index 32a761254..bbf5e5ff1 100644 --- a/sphinx/locale/sv/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/sv/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/ta/LC_MESSAGES/sphinx.po b/sphinx/locale/ta/LC_MESSAGES/sphinx.po index 1cab45ce5..bb1c77f28 100644 --- a/sphinx/locale/ta/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ta/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/te/LC_MESSAGES/sphinx.po b/sphinx/locale/te/LC_MESSAGES/sphinx.po index e96c8859c..c6c3c45f1 100644 --- a/sphinx/locale/te/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/te/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/tr/LC_MESSAGES/sphinx.mo b/sphinx/locale/tr/LC_MESSAGES/sphinx.mo Binary files differindex 1147c43f3..f8d5ed28d 100644 --- a/sphinx/locale/tr/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/tr/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/tr/LC_MESSAGES/sphinx.po b/sphinx/locale/tr/LC_MESSAGES/sphinx.po index 2acf25505..996d6e67c 100644 --- a/sphinx/locale/tr/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/tr/LC_MESSAGES/sphinx.po @@ -43,7 +43,7 @@ msgstr "Sphinx s%s çalışıyor" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "Güvenlik nedeni ile macOS ve python 3.8 ve üzerinde paralel kip etkisizleÅŸtirildi. Daha fazla bilgi için lütfen https://github.com/sphinx-doc/sphinx/issues/6803 adresindekileri okuyun" @@ -1133,7 +1133,7 @@ msgstr "Tekrarlama hatası:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "Bu, çok büyük veya çok fazla iç içe girmiÅŸ kaynak dosyaları ile olabilir. Varsayılan Python tekrarlama sınırını conf.py dosyasında ÅŸu örnekle 1000'e kadar dikkatlice artırabilirsiniz:" @@ -1170,7 +1170,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1457,7 +1457,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "Sphinx, yazılım için bir \"sürüm\" ve bir \"yayım\" kavramına sahiptir.\nHer sürümün birden çok yayımı olabilir. ÖrneÄŸin, Python için\nsürüm 2.5 veya 3.0 gibi bir ÅŸeydir, yayım ise 2.5.1 veya 3.0a1 gibi\nbir ÅŸeydir. EÄŸer bu çift yapıya ihtiyacınız yoksa, her ikisini de aynı\ndeÄŸere ayarlayın." @@ -1486,7 +1486,7 @@ msgstr "Proje dili" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "Kaynak dosyalar için dosya adı soneki. Genellikle, bu ya \".txt\" ya da\n\".rst\"dir. Sadece bu soneki içeren dosyalar belgeler olarak kabul edilir." #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po b/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po index 050a1a5af..2b43faa32 100644 --- a/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/ur/LC_MESSAGES/sphinx.po b/sphinx/locale/ur/LC_MESSAGES/sphinx.po index b4a3e3ba3..c674b9283 100644 --- a/sphinx/locale/ur/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/ur/LC_MESSAGES/sphinx.po @@ -40,7 +40,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1130,7 +1130,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1167,7 +1167,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1454,7 +1454,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1483,7 +1483,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/vi/LC_MESSAGES/sphinx.po b/sphinx/locale/vi/LC_MESSAGES/sphinx.po index 0e2821a5e..83b579ea4 100644 --- a/sphinx/locale/vi/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/vi/LC_MESSAGES/sphinx.po @@ -41,7 +41,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1131,7 +1131,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1168,7 +1168,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1455,7 +1455,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo b/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo Binary files differindex 1a6476dcd..33222138a 100644 --- a/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +++ b/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo diff --git a/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po b/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po index 22fd15f9b..47cb76210 100644 --- a/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po @@ -52,7 +52,7 @@ msgstr "æ£åœ¨è¿è¡Œ Sphinx v%s" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -495,7 +495,7 @@ msgstr "ä¸æ”¯æŒçš„主题选项 %r" #: sphinx/theming.py:228 #, python-format msgid "file %r on theme path is not a valid zipfile or contains no theme" -msgstr "主题路径指定的文件 %r æ˜¯ä¸€ä¸ªæ— æ•ˆçš„æˆ–ä¸åŒ…å«ä¸»é¢˜çš„ zip 文件" +msgstr "主题路径指定的文件 %r æ˜¯ä¸€ä¸ªæ— æ•ˆçš„æˆ–ä¸åŒ…å«ä¸»é¢˜çš„ zip 文件" #: sphinx/theming.py:243 msgid "" @@ -1142,7 +1142,7 @@ msgstr "递归错误:" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "在æºæ–‡ä»¶è¿‡å¤§æˆ–嵌套层数过深时会出现æ¤é”™è¯¯ã€‚ä½ å¯ä»¥åœ¨ conf.py ä¸å¢žå¤§é»˜è®¤çš„Python 递归 1000 层é™åˆ¶ï¼Œåƒè¿™æ ·ï¼š" @@ -1179,7 +1179,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1466,7 +1466,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1495,7 +1495,7 @@ msgstr "项目è¯ç§" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po b/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po index fc603b6db..67b4d2b81 100644 --- a/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +++ b/sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po @@ -46,7 +46,7 @@ msgstr "" #: sphinx/application.py:202 msgid "" "For security reason, parallel mode is disabled on macOS and python3.8 and " -"above. For more details, please read https://github.com/sphinx-" +"above. For more details, please read https://github.com/sphinx-" "doc/sphinx/issues/6803" msgstr "" @@ -1136,7 +1136,7 @@ msgstr "" #: sphinx/cmd/build.py:62 msgid "" -"This can happen with very large or deeply nested source files. You can " +"This can happen with very large or deeply nested source files. You can " "carefully increase the default Python recursion limit of 1000 in conf.py " "with e.g.:" msgstr "" @@ -1173,7 +1173,7 @@ msgid "" "\n" "sphinx-build generates documentation from the files in SOURCEDIR and places it\n" "in OUTPUTDIR. It looks for 'conf.py' in SOURCEDIR for the configuration\n" -"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" +"settings. The 'sphinx-quickstart' tool may be used to generate template files,\n" "including 'conf.py'\n" "\n" "sphinx-build can create documentation in different formats. A format is\n" @@ -1460,7 +1460,7 @@ msgid "" "Sphinx has the notion of a \"version\" and a \"release\" for the\n" "software. Each version can have multiple releases. For example, for\n" "Python the version is something like 2.5 or 3.0, while the release is\n" -"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" +"something like 2.5.1 or 3.0a1. If you don't need this dual structure,\n" "just set both to the same value." msgstr "" @@ -1489,7 +1489,7 @@ msgstr "" #: sphinx/cmd/quickstart.py:298 msgid "" "The file name suffix for source files. Commonly, this is either \".txt\"\n" -"or \".rst\". Only files with this suffix are considered documents." +"or \".rst\". Only files with this suffix are considered documents." msgstr "" #: sphinx/cmd/quickstart.py:300 diff --git a/sphinx/parsers.py b/sphinx/parsers.py index 3974d1c66..6a07d1801 100644 --- a/sphinx/parsers.py +++ b/sphinx/parsers.py @@ -64,7 +64,7 @@ class Parser(docutils.parsers.Parser): @property def app(self) -> "Sphinx": - warnings.warn('parser.app is deprecated.', RemovedInSphinx50Warning) + warnings.warn('parser.app is deprecated.', RemovedInSphinx50Warning, stacklevel=2) return self._app diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py index 55d5d2c1d..4879fb349 100644 --- a/sphinx/pycode/__init__.py +++ b/sphinx/pycode/__init__.py @@ -133,7 +133,7 @@ class ModuleAnalyzer: pos = source.tell() if not decoded: warnings.warn('decode option for ModuleAnalyzer is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) self._encoding, _ = tokenize.detect_encoding(source.readline) source.seek(pos) self.code = source.read().decode(self._encoding) @@ -144,6 +144,7 @@ class ModuleAnalyzer: # will be filled by parse() self.annotations = None # type: Dict[Tuple[str, str], str] self.attr_docs = None # type: Dict[Tuple[str, str], List[str]] + self.finals = None # type: List[str] self.tagorder = None # type: Dict[str, int] self.tags = None # type: Dict[str, Tuple[str, int, int]] @@ -161,6 +162,7 @@ class ModuleAnalyzer: self.attr_docs[scope] = [''] self.annotations = parser.annotations + self.finals = parser.finals self.tags = parser.definitions self.tagorder = parser.deforders except Exception as exc: @@ -183,5 +185,5 @@ class ModuleAnalyzer: @property def encoding(self) -> str: warnings.warn('ModuleAnalyzer.encoding is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) return self._encoding diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py index fb2a7152d..9bafff11c 100644 --- a/sphinx/pycode/ast.py +++ b/sphinx/pycode/ast.py @@ -9,7 +9,7 @@ """ import sys -from typing import Dict, List, Type +from typing import Dict, List, Type, Optional if sys.version_info > (3, 8): import ast @@ -58,126 +58,148 @@ def parse(code: str, mode: str = 'exec') -> "ast.AST": return ast.parse(code, mode=mode) -def unparse(node: ast.AST) -> str: +def unparse(node: Optional[ast.AST]) -> Optional[str]: """Unparse an AST to string.""" if node is None: return None elif isinstance(node, str): return node - elif node.__class__ in OPERATORS: + return _UnparseVisitor().visit(node) + + +# a greatly cut-down version of `ast._Unparser` +class _UnparseVisitor(ast.NodeVisitor): + + def _visit_op(self, node: ast.AST) -> str: return OPERATORS[node.__class__] - elif isinstance(node, ast.arg): + for _op in OPERATORS: + locals()['visit_{}'.format(_op.__name__)] = _visit_op + + def visit_arg(self, node: ast.arg) -> str: if node.annotation: - return "%s: %s" % (node.arg, unparse(node.annotation)) + return "%s: %s" % (node.arg, self.visit(node.annotation)) else: return node.arg - elif isinstance(node, ast.arguments): - return unparse_arguments(node) - elif isinstance(node, ast.Attribute): - return "%s.%s" % (unparse(node.value), node.attr) - elif isinstance(node, ast.BinOp): - return " ".join(unparse(e) for e in [node.left, node.op, node.right]) - elif isinstance(node, ast.BoolOp): - op = " %s " % unparse(node.op) - return op.join(unparse(e) for e in node.values) - elif isinstance(node, ast.Bytes): - return repr(node.s) - elif isinstance(node, ast.Call): - args = ([unparse(e) for e in node.args] + - ["%s=%s" % (k.arg, unparse(k.value)) for k in node.keywords]) - return "%s(%s)" % (unparse(node.func), ", ".join(args)) - elif isinstance(node, ast.Dict): - keys = (unparse(k) for k in node.keys) - values = (unparse(v) for v in node.values) + + def _visit_arg_with_default(self, arg: ast.arg, default: Optional[ast.AST]) -> str: + """Unparse a single argument to a string.""" + name = self.visit(arg) + if default: + if arg.annotation: + name += " = %s" % self.visit(default) + else: + name += "=%s" % self.visit(default) + return name + + def visit_arguments(self, node: ast.arguments) -> str: + defaults = list(node.defaults) + positionals = len(node.args) + posonlyargs = 0 + if hasattr(node, "posonlyargs"): # for py38+ + posonlyargs += len(node.posonlyargs) # type:ignore + positionals += posonlyargs + for _ in range(len(defaults), positionals): + defaults.insert(0, None) + + kw_defaults = list(node.kw_defaults) + for _ in range(len(kw_defaults), len(node.kwonlyargs)): + kw_defaults.insert(0, None) + + args = [] # type: List[str] + if hasattr(node, "posonlyargs"): # for py38+ + for i, arg in enumerate(node.posonlyargs): # type: ignore + args.append(self._visit_arg_with_default(arg, defaults[i])) + + if node.posonlyargs: # type: ignore + args.append('/') + + for i, arg in enumerate(node.args): + args.append(self._visit_arg_with_default(arg, defaults[i + posonlyargs])) + + if node.vararg: + args.append("*" + self.visit(node.vararg)) + + if node.kwonlyargs and not node.vararg: + args.append('*') + for i, arg in enumerate(node.kwonlyargs): + args.append(self._visit_arg_with_default(arg, kw_defaults[i])) + + if node.kwarg: + args.append("**" + self.visit(node.kwarg)) + + return ", ".join(args) + + def visit_Attribute(self, node: ast.Attribute) -> str: + return "%s.%s" % (self.visit(node.value), node.attr) + + def visit_BinOp(self, node: ast.BinOp) -> str: + return " ".join(self.visit(e) for e in [node.left, node.op, node.right]) + + def visit_BoolOp(self, node: ast.BoolOp) -> str: + op = " %s " % self.visit(node.op) + return op.join(self.visit(e) for e in node.values) + + def visit_Call(self, node: ast.Call) -> str: + args = ([self.visit(e) for e in node.args] + + ["%s=%s" % (k.arg, self.visit(k.value)) for k in node.keywords]) + return "%s(%s)" % (self.visit(node.func), ", ".join(args)) + + def visit_Dict(self, node: ast.Dict) -> str: + keys = (self.visit(k) for k in node.keys) + values = (self.visit(v) for v in node.values) items = (k + ": " + v for k, v in zip(keys, values)) return "{" + ", ".join(items) + "}" - elif isinstance(node, ast.Ellipsis): - return "..." - elif isinstance(node, ast.Index): - return unparse(node.value) - elif isinstance(node, ast.Lambda): - return "lambda %s: ..." % unparse(node.args) - elif isinstance(node, ast.List): - return "[" + ", ".join(unparse(e) for e in node.elts) + "]" - elif isinstance(node, ast.Name): + + def visit_Index(self, node: ast.Index) -> str: + return self.visit(node.value) + + def visit_Lambda(self, node: ast.Lambda) -> str: + return "lambda %s: ..." % self.visit(node.args) + + def visit_List(self, node: ast.List) -> str: + return "[" + ", ".join(self.visit(e) for e in node.elts) + "]" + + def visit_Name(self, node: ast.Name) -> str: return node.id - elif isinstance(node, ast.NameConstant): - return repr(node.value) - elif isinstance(node, ast.Num): - return repr(node.n) - elif isinstance(node, ast.Set): - return "{" + ", ".join(unparse(e) for e in node.elts) + "}" - elif isinstance(node, ast.Str): - return repr(node.s) - elif isinstance(node, ast.Subscript): - return "%s[%s]" % (unparse(node.value), unparse(node.slice)) - elif isinstance(node, ast.UnaryOp): - return "%s %s" % (unparse(node.op), unparse(node.operand)) - elif isinstance(node, ast.Tuple): + + def visit_Set(self, node: ast.Set) -> str: + return "{" + ", ".join(self.visit(e) for e in node.elts) + "}" + + def visit_Subscript(self, node: ast.Subscript) -> str: + return "%s[%s]" % (self.visit(node.value), self.visit(node.slice)) + + def visit_UnaryOp(self, node: ast.UnaryOp) -> str: + return "%s %s" % (self.visit(node.op), self.visit(node.operand)) + + def visit_Tuple(self, node: ast.Tuple) -> str: if node.elts: - return ", ".join(unparse(e) for e in node.elts) + return ", ".join(self.visit(e) for e in node.elts) else: return "()" - elif sys.version_info > (3, 6) and isinstance(node, ast.Constant): - # this branch should be placed at last - return repr(node.value) - else: - raise NotImplementedError('Unable to parse %s object' % type(node).__name__) - -def unparse_arguments(node: ast.arguments) -> str: - """Unparse an arguments to string.""" - defaults = list(node.defaults) - positionals = len(node.args) - posonlyargs = 0 - if hasattr(node, "posonlyargs"): # for py38+ - posonlyargs += len(node.posonlyargs) # type:ignore - positionals += posonlyargs - for _ in range(len(defaults), positionals): - defaults.insert(0, None) - - kw_defaults = list(node.kw_defaults) - for _ in range(len(kw_defaults), len(node.kwonlyargs)): - kw_defaults.insert(0, None) - - args = [] # type: List[str] - if hasattr(node, "posonlyargs"): # for py38+ - for i, arg in enumerate(node.posonlyargs): # type: ignore - name = unparse(arg) - if defaults[i]: - if arg.annotation: - name += " = %s" % unparse(defaults[i]) - else: - name += "=%s" % unparse(defaults[i]) - args.append(name) - - if node.posonlyargs: # type: ignore - args.append('/') - - for i, arg in enumerate(node.args): - name = unparse(arg) - if defaults[i + posonlyargs]: - if arg.annotation: - name += " = %s" % unparse(defaults[i + posonlyargs]) + if sys.version_info >= (3, 6): + def visit_Constant(self, node: ast.Constant) -> str: + if node.value is Ellipsis: + return "..." else: - name += "=%s" % unparse(defaults[i + posonlyargs]) - args.append(name) + return repr(node.value) - if node.vararg: - args.append("*" + unparse(node.vararg)) + if sys.version_info < (3, 8): + # these ast nodes were deprecated in python 3.8 + def visit_Bytes(self, node: ast.Bytes) -> str: + return repr(node.s) - if node.kwonlyargs and not node.vararg: - args.append('*') - for i, arg in enumerate(node.kwonlyargs): - name = unparse(arg) - if kw_defaults[i]: - if arg.annotation: - name += " = %s" % unparse(kw_defaults[i]) - else: - name += "=%s" % unparse(kw_defaults[i]) - args.append(name) + def visit_Ellipsis(self, node: ast.Ellipsis) -> str: + return "..." + + def visit_NameConstant(self, node: ast.NameConstant) -> str: + return repr(node.value) - if node.kwarg: - args.append("**" + unparse(node.kwarg)) + def visit_Num(self, node: ast.Num) -> str: + return repr(node.n) - return ", ".join(args) + def visit_Str(self, node: ast.Str) -> str: + return repr(node.s) + + def generic_visit(self, node): + raise NotImplementedError('Unable to parse %s object' % type(node).__name__) diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py index cb3cf0cc1..3762c72cc 100644 --- a/sphinx/pycode/parser.py +++ b/sphinx/pycode/parser.py @@ -14,7 +14,7 @@ import sys import tokenize from token import NAME, NEWLINE, INDENT, DEDENT, NUMBER, OP, STRING from tokenize import COMMENT, NL -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, List, Optional, Tuple from sphinx.pycode.ast import ast # for py37 or older from sphinx.pycode.ast import parse, unparse @@ -231,43 +231,59 @@ class VariableCommentPicker(ast.NodeVisitor): self.annotations = {} # type: Dict[Tuple[str, str], str] self.previous = None # type: ast.AST self.deforders = {} # type: Dict[str, int] + self.finals = [] # type: List[str] + self.typing = None # type: str + self.typing_final = None # type: str super().__init__() - def add_entry(self, name: str) -> None: + def get_qualname_for(self, name: str) -> Optional[List[str]]: + """Get qualified name for given object as a list of string.""" if self.current_function: if self.current_classes and self.context[-1] == "__init__": # store variable comments inside __init__ method of classes - definition = self.context[:-1] + [name] + return self.context[:-1] + [name] else: - return + return None else: - definition = self.context + [name] + return self.context + [name] - self.deforders[".".join(definition)] = next(self.counter) + def add_entry(self, name: str) -> None: + qualname = self.get_qualname_for(name) + if qualname: + self.deforders[".".join(qualname)] = next(self.counter) - def add_variable_comment(self, name: str, comment: str) -> None: - if self.current_function: - if self.current_classes and self.context[-1] == "__init__": - # store variable comments inside __init__ method of classes - context = ".".join(self.context[:-1]) - else: - return - else: - context = ".".join(self.context) + def add_final_entry(self, name: str) -> None: + qualname = self.get_qualname_for(name) + if qualname: + self.finals.append(".".join(qualname)) - self.comments[(context, name)] = comment + def add_variable_comment(self, name: str, comment: str) -> None: + qualname = self.get_qualname_for(name) + if qualname: + basename = ".".join(qualname[:-1]) + self.comments[(basename, name)] = comment def add_variable_annotation(self, name: str, annotation: ast.AST) -> None: - if self.current_function: - if self.current_classes and self.context[-1] == "__init__": - # store variable comments inside __init__ method of classes - context = ".".join(self.context[:-1]) - else: - return - else: - context = ".".join(self.context) + qualname = self.get_qualname_for(name) + if qualname: + basename = ".".join(qualname[:-1]) + self.annotations[(basename, name)] = unparse(annotation) + + def is_final(self, decorators: List[ast.expr]) -> bool: + final = [] + if self.typing: + final.append('%s.final' % self.typing) + if self.typing_final: + final.append(self.typing_final) + + for decorator in decorators: + try: + if unparse(decorator) in final: + return True + except NotImplementedError: + pass - self.annotations[(context, name)] = unparse(annotation) + return False def get_self(self) -> ast.arg: """Returns the name of first argument if in function.""" @@ -288,18 +304,20 @@ class VariableCommentPicker(ast.NodeVisitor): def visit_Import(self, node: ast.Import) -> None: """Handles Import node and record it to definition orders.""" for name in node.names: - if name.asname: - self.add_entry(name.asname) - else: - self.add_entry(name.name) + self.add_entry(name.asname or name.name) + + if name.name == 'typing': + self.typing = name.asname or name.name + elif name.name == 'typing.final': + self.typing_final = name.asname or name.name - def visit_ImportFrom(self, node: ast.Import) -> None: + def visit_ImportFrom(self, node: ast.ImportFrom) -> None: """Handles Import node and record it to definition orders.""" for name in node.names: - if name.asname: - self.add_entry(name.asname) - else: - self.add_entry(name.name) + self.add_entry(name.asname or name.name) + + if node.module == 'typing' and name.name == 'final': + self.typing_final = name.asname or name.name def visit_Assign(self, node: ast.Assign) -> None: """Handles Assign node and pick up a variable comment.""" @@ -384,6 +402,8 @@ class VariableCommentPicker(ast.NodeVisitor): """Handles ClassDef node and set context.""" self.current_classes.append(node.name) self.add_entry(node.name) + if self.is_final(node.decorator_list): + self.add_final_entry(node.name) self.context.append(node.name) self.previous = node for child in node.body: @@ -395,6 +415,8 @@ class VariableCommentPicker(ast.NodeVisitor): """Handles FunctionDef node and set context.""" if self.current_function is None: self.add_entry(node.name) # should be called before setting self.current_function + if self.is_final(node.decorator_list): + self.add_final_entry(node.name) self.context.append(node.name) self.current_function = node for child in node.body: @@ -495,6 +517,7 @@ class Parser: self.comments = {} # type: Dict[Tuple[str, str], str] self.deforders = {} # type: Dict[str, int] self.definitions = {} # type: Dict[str, Tuple[str, int, int]] + self.finals = [] # type: List[str] def parse(self) -> None: """Parse the source code.""" @@ -509,6 +532,7 @@ class Parser: self.annotations = picker.annotations self.comments = picker.comments self.deforders = picker.deforders + self.finals = picker.finals def parse_definition(self) -> None: """Parse the location of definitions from the code.""" diff --git a/sphinx/registry.py b/sphinx/registry.py index 200f59d42..cad74559c 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -98,6 +98,8 @@ class SphinxComponentRegistry: #: LaTeX packages; list of package names and its options self.latex_packages = [] # type: List[Tuple[str, str]] + self.latex_packages_after_hyperref = [] # type: List[Tuple[str, str]] + #: post transforms; list of transforms self.post_transforms = [] # type: List[Type[Transform]] @@ -363,9 +365,12 @@ class SphinxComponentRegistry: logger.debug('[app] adding js_file: %r, %r', filename, attributes) self.js_files.append((filename, attributes)) - def add_latex_package(self, name: str, options: str) -> None: + def add_latex_package(self, name: str, options: str, after_hyperref: bool = False) -> None: logger.debug('[app] adding latex package: %r', name) - self.latex_packages.append((name, options)) + if after_hyperref: + self.latex_packages_after_hyperref.append((name, options)) + else: + self.latex_packages.append((name, options)) def add_enumerable_node(self, node: "Type[Node]", figtype: str, title_getter: TitleGetter = None, override: bool = False) -> None: diff --git a/sphinx/roles.py b/sphinx/roles.py index ff24fcf55..57d11c269 100644 --- a/sphinx/roles.py +++ b/sphinx/roles.py @@ -574,7 +574,7 @@ def index_role(typ: str, rawtext: str, text: str, lineno: int, inliner: Inliner, class Index(ReferenceRole): def run(self) -> Tuple[List[Node], List[system_message]]: - warnings.warn('Index role is deprecated.', RemovedInSphinx40Warning) + warnings.warn('Index role is deprecated.', RemovedInSphinx40Warning, stacklevel=2) target_id = 'index-%s' % self.env.new_serialno('index') if self.has_explicit_title: # if an explicit target is given, process it as a full entry diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py index d9853ff06..74fbaade9 100644 --- a/sphinx/search/__init__.py +++ b/sphinx/search/__init__.py @@ -23,7 +23,7 @@ from sphinx import package_dir from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.environment import BuildEnvironment from sphinx.search.jssplitter import splitter_code -from sphinx.util import jsdump, rpartition +from sphinx.util import jsdump if False: # For type annotation @@ -203,7 +203,7 @@ class WordCollector(nodes.NodeVisitor): def is_meta_keywords(self, node: addnodes.meta, nodetype: Any = None) -> bool: if nodetype is not None: warnings.warn('"nodetype" argument for WordCollector.is_meta_keywords() ' - 'is deprecated.', RemovedInSphinx40Warning) + 'is deprecated.', RemovedInSphinx40Warning, stacklevel=2) if isinstance(node, addnodes.meta) and node.get('name') == 'keywords': meta_lang = node.get('lang') @@ -333,7 +333,7 @@ class IndexBuilder: continue fullname = html.escape(fullname) dispname = html.escape(dispname) - prefix, name = rpartition(dispname, '.') + prefix, _, name = dispname.rpartition('.') pdict = rv.setdefault(prefix, {}) try: typeindex = otypes[domainname, type] diff --git a/sphinx/templates/latex/latex.tex_t b/sphinx/templates/latex/latex.tex_t index a0a5a26b1..5082254e7 100644 --- a/sphinx/templates/latex/latex.tex_t +++ b/sphinx/templates/latex/latex.tex_t @@ -46,6 +46,14 @@ <%- endfor %> <%= hyperref %> +<%- for name, option in packages_after_hyperref %> +<%- if option %> +\usepackage[<%= option %>]{<%= name %>} +<%- else %> +\usepackage{<%= name %>} +<%- endif %> +<%- endfor %> + <%= contentsname %> \usepackage{sphinxmessages} <%= tocdepth %> diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t index 774585566..830cf656e 100644 --- a/sphinx/templates/quickstart/make.bat_t +++ b/sphinx/templates/quickstart/make.bat_t @@ -27,9 +27,9 @@ if "%1" == "help" ( echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and an HTML help project - echo. qthelp to make HTML files and a qthelp project + echo. qthelp to make HTML files and a Qt help project echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub + echo. epub to make an EPUB echo. latex to make LaTeX files (you can set PAPER=a4 or PAPER=letter) echo. latexpdf to make LaTeX files and then PDFs out of them echo. text to make text files @@ -69,7 +69,7 @@ if errorlevel 9009 ( echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ + echo.https://sphinx-doc.org/ exit /b 1 ) diff --git a/sphinx/themes/basic/genindex.html b/sphinx/themes/basic/genindex.html index 690823d64..fb769737f 100644 --- a/sphinx/themes/basic/genindex.html +++ b/sphinx/themes/basic/genindex.html @@ -7,6 +7,9 @@ :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} +{%- extends "layout.html" %} +{% set title = _('Index') %} + {% macro indexentries(firstname, links) %} {%- if links -%} <a href="{{ links[0][1] }}"> @@ -26,8 +29,6 @@ {%- endif %} {% endmacro %} -{%- extends "layout.html" %} -{% set title = _('Index') %} {% block body %} <h1 id="index">{{ _('Index') }}</h1> diff --git a/sphinx/themes/basic/globaltoc.html b/sphinx/themes/basic/globaltoc.html index 59cab989b..2f16655cf 100644 --- a/sphinx/themes/basic/globaltoc.html +++ b/sphinx/themes/basic/globaltoc.html @@ -8,4 +8,4 @@ :license: BSD, see LICENSE for details. #} <h3><a href="{{ pathto(master_doc)|e }}">{{ _('Table of Contents') }}</a></h3> -{{ toctree() }} +{{ toctree(includehidden=theme_globaltoc_includehidden, collapse=theme_globaltoc_collapse) }} diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html index 0ab2afe35..50feffd71 100644 --- a/sphinx/themes/basic/layout.html +++ b/sphinx/themes/basic/layout.html @@ -42,6 +42,7 @@ {%- for parent in parents %} <li class="nav-item nav-item-{{ loop.index }}"><a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a>{{ reldelim1 }}</li> {%- endfor %} + <li class="nav-item nav-item-this"><a href="{{ link|e }}">{{ title }}</a></li> {%- block relbaritems %} {% endblock %} </ul> </div> @@ -119,6 +120,7 @@ {%- else %} <meta http-equiv="Content-Type" content="text/html; charset={{ encoding }}" /> {%- endif %} + <meta name="viewport" content="width=device-width, initial-scale=1.0"> {{- metatags }} {%- block htmltitle %} <title>{{ title|striptags|e }}{{ titlesuffix }}</title> @@ -131,7 +133,7 @@ {{- script() }} {%- endblock %} {%- if pageurl %} - <link rel="canonical" href="{{ pageurl }}" /> + <link rel="canonical" href="{{ pageurl|e }}" /> {%- endif %} {%- if use_opensearch %} <link rel="search" type="application/opensearchdescription+xml" @@ -180,6 +182,7 @@ {%- endif %} <div class="body" role="main"> {% block body %} {% endblock %} + <div class="clearer"></div> </div> {%- if render_sidebar %} </div> @@ -207,7 +210,7 @@ {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %} {%- endif %} {%- if show_sphinx %} - {% trans sphinx_version=sphinx_version|e %}Created using <a href="http://sphinx-doc.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %} + {% trans sphinx_version=sphinx_version|e %}Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %} {%- endif %} </div> {%- endblock %} diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index e72db1249..45908ece1 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -320,18 +320,25 @@ div.sidebar { background-color: #ffe; width: 40%; float: right; + clear: right; + overflow-x: auto; } p.sidebar-title { font-weight: bold; } +div.admonition, div.topic, pre, div[class|="highlight"] { + clear: both; +} + /* -- topics ---------------------------------------------------------------- */ div.topic { border: 1px solid #ccc; padding: 7px 7px 0 7px; margin: 10px 0 10px 0; + overflow-x: auto; } p.topic-title { @@ -346,6 +353,7 @@ div.admonition { margin-top: 10px; margin-bottom: 10px; padding: 7px; + overflow-x: auto; } div.admonition dt { @@ -369,6 +377,8 @@ div.body p.centered { /* -- tables ---------------------------------------------------------------- */ table.docutils { + margin-top: 10px; + margin-bottom: 10px; border: 0; border-collapse: collapse; } @@ -506,6 +516,7 @@ li > p:last-child { dl.footnote > dt, dl.citation > dt { float: left; + margin-right: 0.5em; } dl.footnote > dd, @@ -645,21 +656,52 @@ span.pre { } td.linenos pre { - padding: 5px 0px; border: 0; background-color: transparent; color: #aaa; } table.highlighttable { - margin-left: 0.5em; + display: block; + margin: 1em 0; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; } table.highlighttable td { - padding: 0 0.5em 0 0.5em; + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding: 0 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div > table.highlighttable { + margin-top: 0; } div.code-block-caption { + margin-top: 1em; padding: 2px 5px; font-size: small; } @@ -672,6 +714,7 @@ div.code-block-caption + div > div.highlight > pre { margin-top: 0; } +table.highlighttable td.linenos, div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */ user-select: none; } @@ -685,11 +728,7 @@ div.code-block-caption span.caption-text { } div.literal-block-wrapper { - padding: 1em 1em 0; -} - -div.literal-block-wrapper div.highlight { - margin: 0; + margin: 1em 0; } code.descname { @@ -740,8 +779,7 @@ span.eqno { } span.eqno a.headerlink { - position: relative; - left: 0px; + position: absolute; z-index: 1; } diff --git a/sphinx/themes/basic/theme.conf b/sphinx/themes/basic/theme.conf index df02a5aec..3c289d5dc 100644 --- a/sphinx/themes/basic/theme.conf +++ b/sphinx/themes/basic/theme.conf @@ -10,3 +10,5 @@ sidebarwidth = 230 body_min_width = 450 body_max_width = 800 navigation_with_keys = False +globaltoc_collapse = true +globaltoc_includehidden = false diff --git a/sphinx/themes/bizstyle/layout.html b/sphinx/themes/bizstyle/layout.html index 126bb59e9..c946f8435 100644 --- a/sphinx/themes/bizstyle/layout.html +++ b/sphinx/themes/bizstyle/layout.html @@ -14,10 +14,6 @@ <script src="{{ pathto('_static/bizstyle.js', 1) }}"></script> {%- endblock %} -{# put the sidebar before the body #} -{% block sidebar1 %}{{ sidebar() }}{% endblock %} -{% block sidebar2 %}{% endblock %} - {# doctype override #} {%- block doctype %} <!doctype html> diff --git a/sphinx/themes/bizstyle/static/bizstyle.css_t b/sphinx/themes/bizstyle/static/bizstyle.css_t index b13395b4f..465734646 100644 --- a/sphinx/themes/bizstyle/static/bizstyle.css_t +++ b/sphinx/themes/bizstyle/static/bizstyle.css_t @@ -39,6 +39,11 @@ div.document { -webkit-box-shadow: 2px 2px 5px #000; } +div.documentwrapper { + float: left; + width: 100%; +} + div.bodywrapper { margin: 0 0 0 240px; border-left: 1px solid #ccc; @@ -105,7 +110,6 @@ div.sphinxsidebarwrapper { } div.sphinxsidebar { - margin: 0; padding: 0.5em 12px 12px 12px; width: {{ theme_sidebarwidth|todim }}; {%- if theme_rightsidebar|tobool %} diff --git a/sphinx/themes/sphinxdoc/layout.html b/sphinx/themes/sphinxdoc/layout.html deleted file mode 100644 index bdae9a441..000000000 --- a/sphinx/themes/sphinxdoc/layout.html +++ /dev/null @@ -1,14 +0,0 @@ -{# - sphinxdoc/layout.html - ~~~~~~~~~~~~~~~~~~~~~ - - Sphinx layout template for the sphinxdoc theme. - - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -#} -{%- extends "basic/layout.html" %} - -{# put the sidebar before the body #} -{% block sidebar1 %}{{ sidebar() }}{% endblock %} -{% block sidebar2 %}{% endblock %} diff --git a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t index 4034c617d..626d8c3f2 100644 --- a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +++ b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t @@ -37,6 +37,11 @@ div.document { background-repeat: repeat-x; } +div.documentwrapper { + float: left; + width: 100%; +} + div.bodywrapper { margin: 0 calc({{ theme_sidebarwidth|todim }} + 10px) 0 0; border-right: 1px solid #ccc; @@ -86,7 +91,6 @@ div.sphinxsidebarwrapper { } div.sphinxsidebar { - margin: 0; padding: 0.5em 15px 15px 0; width: calc({{ theme_sidebarwidth|todim }} - 20px); float: right; diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index a00f04fdf..1605c95b9 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -23,6 +23,7 @@ from sphinx import addnodes from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.locale import _, __ +from sphinx.util import docutils from sphinx.util import logging from sphinx.util.docutils import new_document from sphinx.util.i18n import format_date @@ -360,12 +361,18 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform): def get_tokens(self, txtnodes: List[Text]) -> Generator[Tuple[str, str], None, None]: # A generator that yields ``(texttype, nodetext)`` tuples for a list # of "Text" nodes (interface to ``smartquotes.educate_tokens()``). - - texttype = {True: 'literal', # "literal" text is not changed: - False: 'plain'} for txtnode in txtnodes: - notsmartquotable = not is_smartquotable(txtnode) - yield (texttype[notsmartquotable], txtnode.astext()) + if is_smartquotable(txtnode): + if docutils.__version_info__ >= (0, 16): + # SmartQuotes uses backslash escapes instead of null-escapes + text = re.sub(r'(?<=\x00)([-\\\'".`])', r'\\\1', str(txtnode)) + else: + text = txtnode.astext() + + yield ('plain', text) + else: + # skip smart quotes + yield ('literal', txtnode.astext()) class DoctreeReadEvent(SphinxTransform): diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index 48f5dc248..4499e3376 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -92,7 +92,8 @@ class ReferencesResolver(SphinxPostTransform): # no new node found? try the missing-reference event if newnode is None: newnode = self.app.emit_firstresult('missing-reference', self.env, - node, contnode) + node, contnode, + allowed_exceptions=(NoUri,)) # still not found? warn if node wishes to be warned about or # we are in nit-picky mode if newnode is None: @@ -210,7 +211,7 @@ class SigElementFallbackTransform(SphinxPostTransform): else: self.fallback() - def fallback(self): + def fallback(self) -> None: for node in self.document.traverse(addnodes.desc_sig_element): newnode = nodes.inline() newnode.update_all_atts(node) diff --git a/sphinx/transforms/post_transforms/images.py b/sphinx/transforms/post_transforms/images.py index 57b36b4b0..f2cacac3c 100644 --- a/sphinx/transforms/post_transforms/images.py +++ b/sphinx/transforms/post_transforms/images.py @@ -193,7 +193,9 @@ class ImageConverter(BaseImageConverter): super().__init__(*args, **kwargs) def match(self, node: nodes.image) -> bool: - if self.available is None: + if not self.app.builder.supported_image_types: + return False + elif self.available is None: self.available = self.is_available() if not self.available: diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index 2a08821e1..ca9bb028d 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -28,7 +28,7 @@ from time import mktime, strptime from typing import Any, Callable, Dict, IO, Iterable, Iterator, List, Pattern, Set, Tuple from urllib.parse import urlsplit, urlunsplit, quote_plus, parse_qsl, urlencode -from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.errors import ( PycodeError, SphinxParallelError, ExtensionError, FiletypeNotFoundError ) @@ -110,7 +110,7 @@ def get_matching_docs(dirname: str, suffixes: List[str], Exclude files and dirs matching a pattern in *exclude_patterns*. """ warnings.warn('get_matching_docs() is now deprecated. Use get_matching_files() instead.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) suffixpatterns = ['*' + s for s in suffixes] for filename in get_matching_files(dirname, exclude_matchers): for suffixpattern in suffixpatterns: @@ -345,7 +345,7 @@ _coding_re = re.compile(r'coding[:=]\s*([-\w.]+)') def detect_encoding(readline: Callable[[], bytes]) -> str: """Like tokenize.detect_encoding() from Py3k, but a bit simplified.""" warnings.warn('sphinx.util.detect_encoding() is deprecated', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) def read_or_stop() -> bytes: try: @@ -497,6 +497,7 @@ class attrdict(dict): def rpartition(s: str, t: str) -> Tuple[str, str]: """Similar to str.rpartition from 2.5, but doesn't return the separator.""" + warnings.warn('rpartition() is now deprecated.', RemovedInSphinx50Warning, stacklevel=2) i = s.rfind(t) if i != -1: return s[:i], s[i + len(t):] @@ -600,6 +601,31 @@ def import_object(objname: str, source: str = None) -> Any: raise ExtensionError('Could not import %s' % objname, exc) +def split_full_qualified_name(name: str) -> Tuple[str, str]: + """Split full qualified name to a pair of modname and qualname. + + A qualname is an abbreviation for "Qualified name" introduced at PEP-3155 + (https://www.python.org/dev/peps/pep-3155/). It is a dotted path name + from the module top-level. + + A "full" qualified name means a string containing both module name and + qualified name. + + .. note:: This function imports module actually to check the exisitence. + Therefore you need to mock 3rd party modules if needed before + calling this function. + """ + parts = name.split('.') + for i, part in enumerate(parts, 1): + try: + modname = ".".join(parts[:i]) + import_module(modname) + except ImportError: + return ".".join(parts[:i - 1]), ".".join(parts[i - 1:]) + + return name, "" + + def encode_uri(uri: str) -> str: split = list(urlsplit(uri)) split[1] = split[1].encode('idna').decode('ascii') diff --git a/sphinx/util/cfamily.py b/sphinx/util/cfamily.py index cdac9231f..edccf96a7 100644 --- a/sphinx/util/cfamily.py +++ b/sphinx/util/cfamily.py @@ -41,6 +41,16 @@ integer_literal_re = re.compile(r'[1-9][0-9]*') octal_literal_re = re.compile(r'0[0-7]*') hex_literal_re = re.compile(r'0[xX][0-9a-fA-F][0-9a-fA-F]*') binary_literal_re = re.compile(r'0[bB][01][01]*') +integers_literal_suffix_re = re.compile(r'''(?x) + # unsigned and/or (long) long, in any order, but at least one of them + ( + ([uU] ([lL] | (ll) | (LL))?) + | + (([lL] | (ll) | (LL)) [uU]?) + )\b + # the ending word boundary is important for distinguishing + # between suffixes and UDLs in C++ +''') float_literal_re = re.compile(r'''(?x) [+-]?( # decimal @@ -53,6 +63,8 @@ float_literal_re = re.compile(r'''(?x) | (0[xX][0-9a-fA-F]+\.([pP][+-]?[0-9a-fA-F]+)?) ) ''') +float_literal_suffix_re = re.compile(r'[fFlL]\b') +# the ending word boundary is important for distinguishing between suffixes and UDLs in C++ char_literal_re = re.compile(r'''(?x) ((?:u8)|u|U|L)? '( @@ -69,7 +81,7 @@ char_literal_re = re.compile(r'''(?x) def verify_description_mode(mode: str) -> None: - if mode not in ('lastIsName', 'noneIsName', 'markType', 'markName', 'param'): + if mode not in ('lastIsName', 'noneIsName', 'markType', 'markName', 'param', 'udl'): raise Exception("Description mode '%s' is invalid." % mode) @@ -338,10 +350,14 @@ class BaseParser: self.pos = self.end return rv - def assert_end(self) -> None: + def assert_end(self, *, allowSemicolon: bool = False) -> None: self.skip_ws() - if not self.eof: - self.fail('Expected end of definition.') + if allowSemicolon: + if not self.eof and self.definition[self.pos:] != ';': + self.fail('Expected end of definition or ;.') + else: + if not self.eof: + self.fail('Expected end of definition.') ################################################################################ diff --git a/sphinx/util/compat.py b/sphinx/util/compat.py index 0135899eb..4923343ae 100644 --- a/sphinx/util/compat.py +++ b/sphinx/util/compat.py @@ -46,7 +46,7 @@ class IndexEntriesMigrator(SphinxTransform): if len(entries) == 4: source, line = get_source_line(node) warnings.warn('An old styled index node found: %r at (%s:%s)' % - (node, source, line), RemovedInSphinx40Warning) + (node, source, line), RemovedInSphinx40Warning, stacklevel=2) node['entries'][i] = entries + (None,) diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index 699738888..c07bc7f66 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -224,12 +224,12 @@ class DocFieldTransformer: except Exception: # for 3rd party extensions directly calls this transformer. warnings.warn('DocFieldTransformer expects given directive object is a subclass ' - 'of ObjectDescription.', RemovedInSphinx40Warning) + 'of ObjectDescription.', RemovedInSphinx40Warning, stacklevel=2) 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.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) typemap = {} for fieldtype in types: for name in fieldtype.names: diff --git a/sphinx/util/docstrings.py b/sphinx/util/docstrings.py index 7b3f011d1..64fdbf1d7 100644 --- a/sphinx/util/docstrings.py +++ b/sphinx/util/docstrings.py @@ -10,10 +10,13 @@ import re import sys +import warnings from typing import Dict, List from docutils.parsers.rst.states import Body +from sphinx.deprecation import RemovedInSphinx50Warning + field_list_item_re = re.compile(Body.patterns['field_marker']) @@ -42,7 +45,7 @@ def extract_metadata(s: str) -> Dict[str, str]: return metadata -def prepare_docstring(s: str, ignore: int = 1, tabsize: int = 8) -> List[str]: +def prepare_docstring(s: str, ignore: int = None, tabsize: int = 8) -> List[str]: """Convert a docstring into lines of parseable reST. Remove common leading indentation, where the indentation of a given number of lines (usually just one) is ignored. @@ -51,6 +54,12 @@ def prepare_docstring(s: str, ignore: int = 1, tabsize: int = 8) -> List[str]: ViewList (used as argument of nested_parse().) An empty line is added to act as a separator between this docstring and following content. """ + if ignore is None: + ignore = 1 + else: + warnings.warn("The 'ignore' argument to parepare_docstring() is deprecated.", + RemovedInSphinx50Warning, stacklevel=2) + lines = s.expandtabs(tabsize).splitlines() # Find minimum indentation of any non-blank lines after ignored lines. margin = sys.maxsize diff --git a/sphinx/util/images.py b/sphinx/util/images.py index 568682b37..115007d31 100644 --- a/sphinx/util/images.py +++ b/sphinx/util/images.py @@ -12,7 +12,7 @@ import base64 import imghdr from collections import OrderedDict from os import path -from typing import IO, NamedTuple, Tuple +from typing import IO, NamedTuple, Optional, Tuple import imagesize @@ -36,7 +36,7 @@ DataURI = NamedTuple('DataURI', [('mimetype', str), ('data', bytes)]) -def get_image_size(filename: str) -> Tuple[int, int]: +def get_image_size(filename: str) -> Optional[Tuple[int, int]]: try: size = imagesize.get(filename) if size[0] == -1: @@ -53,7 +53,7 @@ def get_image_size(filename: str) -> Tuple[int, int]: return None -def guess_mimetype_for_stream(stream: IO, default: str = None) -> str: +def guess_mimetype_for_stream(stream: IO, default: Optional[str] = None) -> Optional[str]: imgtype = imghdr.what(stream) # type: ignore if imgtype: return 'image/' + imgtype @@ -61,7 +61,7 @@ def guess_mimetype_for_stream(stream: IO, default: str = None) -> str: return default -def guess_mimetype(filename: str = '', default: str = None) -> str: +def guess_mimetype(filename: str = '', default: Optional[str] = None) -> Optional[str]: _, ext = path.splitext(filename.lower()) if ext in mime_suffixes: return mime_suffixes[ext] @@ -72,7 +72,7 @@ def guess_mimetype(filename: str = '', default: str = None) -> str: return default -def get_image_extension(mimetype: str) -> str: +def get_image_extension(mimetype: str) -> Optional[str]: for ext, _mimetype in mime_suffixes.items(): if mimetype == _mimetype: return ext @@ -80,7 +80,7 @@ def get_image_extension(mimetype: str) -> str: return None -def parse_data_uri(uri: str) -> DataURI: +def parse_data_uri(uri: str) -> Optional[DataURI]: if not uri.startswith('data:'): return None @@ -101,7 +101,7 @@ def parse_data_uri(uri: str) -> DataURI: return DataURI(mimetype, charset, image_data) -def test_svg(h: bytes, f: IO) -> str: +def test_svg(h: bytes, f: IO) -> Optional[str]: """An additional imghdr library helper; test the header is SVG's or not.""" try: if '<svg' in h.decode().lower(): diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index a0ea52047..0f3f47562 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -13,6 +13,7 @@ import enum import inspect import re import sys +import types import typing import warnings from functools import partial, partialmethod @@ -20,7 +21,7 @@ from inspect import ( # NOQA Parameter, isclass, ismethod, ismethoddescriptor ) from io import StringIO -from typing import Any, Callable, Mapping, List, Tuple +from typing import Any, Callable, Mapping, List, Optional, Tuple from typing import cast from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning @@ -58,7 +59,7 @@ def getargspec(func: Callable) -> Any: """Like inspect.getfullargspec but supports bound methods, and wrapped methods.""" warnings.warn('sphinx.ext.inspect.getargspec() is deprecated', - RemovedInSphinx50Warning) + RemovedInSphinx50Warning, stacklevel=2) # On 3.5+, signature(int) or similar raises ValueError. On 3.4, it # succeeds with a bogus signature. We want a TypeError uniformly, to # match historical behavior. @@ -125,13 +126,15 @@ def unwrap(obj: Any) -> Any: return obj -def unwrap_all(obj: Any) -> Any: +def unwrap_all(obj: Any, *, stop: Callable = None) -> Any: """ Get an original object from wrapped object (unwrapping partials, wrapped functions, and other decorators). """ while True: - if ispartial(obj): + if stop and stop(obj): + return obj + elif ispartial(obj): obj = obj.func elif inspect.isroutine(obj) and hasattr(obj, '__wrapped__'): obj = obj.__wrapped__ @@ -287,7 +290,8 @@ def isroutine(obj: Any) -> bool: def iscoroutinefunction(obj: Any) -> bool: """Check if the object is coroutine-function.""" - obj = unwrap_all(obj) + # unwrap staticmethod, classmethod and partial (except wrappers) + obj = unwrap_all(obj, stop=lambda o: hasattr(o, '__wrapped__')) 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) @@ -301,6 +305,18 @@ def isproperty(obj: Any) -> bool: return isinstance(obj, property) +def isgenericalias(obj: Any) -> bool: + """Check if the object is GenericAlias.""" + if (hasattr(typing, '_GenericAlias') and # only for py37+ + isinstance(obj, typing._GenericAlias)): # type: ignore + return True + elif (hasattr(types, 'GenericAlias') and # only for py39+ + isinstance(obj, types.GenericAlias)): # type: ignore + return True + else: + return False + + def safe_getattr(obj: Any, name: str, *defargs: Any) -> Any: """A getattr() that turns all exceptions into AttributeErrors.""" try: @@ -326,7 +342,7 @@ def safe_getattr(obj: Any, name: str, *defargs: Any) -> Any: def safe_getmembers(object: Any, predicate: Callable[[str], bool] = None, attr_getter: Callable = safe_getattr) -> List[Tuple[str, Any]]: """A version of inspect.getmembers() that uses safe_getattr().""" - warnings.warn('safe_getmembers() is deprecated', RemovedInSphinx40Warning) + warnings.warn('safe_getmembers() is deprecated', RemovedInSphinx40Warning, stacklevel=2) results = [] # type: List[Tuple[str, Any]] for key in dir(object): @@ -386,27 +402,39 @@ def is_builtin_class_method(obj: Any, attr_name: str) -> bool: Why this function needed? CPython implements int.__init__ by Descriptor but PyPy implements it by pure Python code. """ - classes = [c for c in inspect.getmro(obj) if attr_name in c.__dict__] - cls = classes[0] if classes else object + try: + mro = inspect.getmro(obj) + except AttributeError: + # no __mro__, assume the object has no methods as we know them + return False + + try: + cls = next(c for c in mro if attr_name in safe_getattr(c, '__dict__', {})) + except StopIteration: + return False - if not hasattr(builtins, safe_getattr(cls, '__name__', '')): + try: + name = safe_getattr(cls, '__name__') + except AttributeError: return False - return getattr(builtins, safe_getattr(cls, '__name__', '')) is cls + return getattr(builtins, name, None) is cls -def signature(subject: Callable, bound_method: bool = False) -> inspect.Signature: + +def signature(subject: Callable, bound_method: bool = False, follow_wrapped: bool = False + ) -> inspect.Signature: """Return a Signature object for the given *subject*. :param bound_method: Specify *subject* is a bound method or not + :param follow_wrapped: Same as ``inspect.signature()``. + Defaults to ``False`` (get a signature of *subject*). """ - # check subject is not a built-in class (ex. int, str) - if (isinstance(subject, type) and - is_builtin_class_method(subject, "__new__") and - is_builtin_class_method(subject, "__init__")): - raise TypeError("can't compute signature for built-in type {}".format(subject)) - try: - signature = inspect.signature(subject) + try: + signature = inspect.signature(subject, follow_wrapped=follow_wrapped) + except ValueError: + # follow built-in wrappers up (ex. functools.lru_cache) + signature = inspect.signature(subject) parameters = list(signature.parameters.values()) return_annotation = signature.return_annotation except IndexError: @@ -503,19 +531,34 @@ def signature_from_str(signature: str) -> inspect.Signature: # parameters args = definition.args + defaults = list(args.defaults) params = [] + if hasattr(args, "posonlyargs"): + posonlyargs = len(args.posonlyargs) # type: ignore + positionals = posonlyargs + len(args.args) + else: + posonlyargs = 0 + positionals = len(args.args) + + for _ in range(len(defaults), positionals): + defaults.insert(0, Parameter.empty) if hasattr(args, "posonlyargs"): - for arg in args.posonlyargs: # type: ignore + for i, arg in enumerate(args.posonlyargs): # type: ignore + if defaults[i] is Parameter.empty: + default = Parameter.empty + else: + default = ast_unparse(defaults[i]) + annotation = ast_unparse(arg.annotation) or Parameter.empty params.append(Parameter(arg.arg, Parameter.POSITIONAL_ONLY, - annotation=annotation)) + default=default, annotation=annotation)) for i, arg in enumerate(args.args): - if len(args.args) - i <= len(args.defaults): - default = ast_unparse(args.defaults[-len(args.args) + i]) - else: + if defaults[i + posonlyargs] is Parameter.empty: default = Parameter.empty + else: + default = ast_unparse(defaults[i + posonlyargs]) annotation = ast_unparse(arg.annotation) or Parameter.empty params.append(Parameter(arg.arg, Parameter.POSITIONAL_OR_KEYWORD, @@ -552,7 +595,7 @@ class Signature: def __init__(self, subject: Callable, bound_method: bool = False, has_retval: bool = True) -> None: warnings.warn('sphinx.util.inspect.Signature() is deprecated', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) # check subject is not a built-in class (ex. int, str) if (isinstance(subject, type) and @@ -565,7 +608,7 @@ class Signature: self.partialmethod_with_noargs = False try: - self.signature = inspect.signature(subject) + self.signature = inspect.signature(subject) # type: Optional[inspect.Signature] except IndexError: # Until python 3.6.4, cpython has been crashed on inspection for # partialmethods not having any arguments. @@ -691,13 +734,14 @@ class Signature: def getdoc(obj: Any, attrgetter: Callable = safe_getattr, - allow_inherited: bool = False) -> str: + allow_inherited: bool = False, cls: Any = None, name: str = None) -> str: """Get the docstring for the object. This tries to obtain the docstring for some kind of objects additionally: * partial functions * inherited docstring + * inherited decorated methods """ doc = attrgetter(obj, '__doc__', None) if ispartial(obj) and doc == obj.__class__.__doc__: @@ -705,4 +749,14 @@ def getdoc(obj: Any, attrgetter: Callable = safe_getattr, elif doc is None and allow_inherited: doc = inspect.getdoc(obj) + if doc is None and cls: + # inspect.getdoc() does not support some kind of inherited and decorated methods. + # This tries to obtain the docstring from super classes. + for basecls in getattr(cls, '__mro__', []): + meth = safe_getattr(basecls, name, None) + if meth is not None: + doc = inspect.getdoc(meth) + if doc: + break + return doc diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 53053faaf..5889f3860 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -412,9 +412,13 @@ class WarningIsErrorFilter(logging.Filter): message = record.msg # use record.msg itself if location: - raise SphinxWarning(location + ":" + str(message)) + exc = SphinxWarning(location + ":" + str(message)) else: - raise SphinxWarning(message) + exc = SphinxWarning(message) + if record.exc_info is not None: + raise exc from record.exc_info[1] + else: + raise exc else: return True diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index bca6e0bfc..a18eac580 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -62,8 +62,8 @@ class NodeMatcher: # => [<reference ...>, <reference ...>, ...] """ - def __init__(self, *classes: "Type[Node]", **attrs: Any) -> None: - self.classes = classes + def __init__(self, *node_classes: "Type[Node]", **attrs: Any) -> None: + self.classes = node_classes self.attrs = attrs def match(self, node: Node) -> bool: @@ -280,7 +280,7 @@ def extract_messages(doctree: Element) -> Iterable[Tuple[Element, str]]: def find_source_node(node: Element) -> str: warnings.warn('find_source_node() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) return get_node_source(node) diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py index af41df48b..23f5b0137 100644 --- a/sphinx/util/osutil.py +++ b/sphinx/util/osutil.py @@ -18,7 +18,7 @@ import sys import warnings from io import StringIO from os import path -from typing import Any, Generator, Iterator, List, Tuple +from typing import Any, Generator, Iterator, List, Optional, Tuple from sphinx.deprecation import RemovedInSphinx40Warning @@ -86,7 +86,7 @@ def ensuredir(path: str) -> None: def walk(top: str, topdown: bool = True, followlinks: bool = False) -> Iterator[Tuple[str, List[str], List[str]]]: # NOQA warnings.warn('sphinx.util.osutil.walk() is deprecated for removal. ' 'Please use os.walk() instead.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) return os.walk(top, topdown=topdown, followlinks=followlinks) @@ -178,7 +178,7 @@ def abspath(pathdir: str) -> str: def getcwd() -> str: warnings.warn('sphinx.util.osutil.getcwd() is deprecated. ' 'Please use os.getcwd() instead.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) return os.getcwd() @@ -206,7 +206,7 @@ class FileAvoidWrite: """ def __init__(self, path: str) -> None: self._path = path - self._io = None # type: StringIO + self._io = None # type: Optional[StringIO] def write(self, data: str) -> None: if not self._io: diff --git a/sphinx/util/png.py b/sphinx/util/png.py index c7f73fd50..22c35d991 100644 --- a/sphinx/util/png.py +++ b/sphinx/util/png.py @@ -10,6 +10,7 @@ import binascii import struct +from typing import Optional LEN_IEND = 12 @@ -20,7 +21,7 @@ DEPTH_CHUNK_START = b'tEXtDepth\x00' IEND_CHUNK = b'\x00\x00\x00\x00IEND\xAE\x42\x60\x82' -def read_png_depth(filename: str) -> int: +def read_png_depth(filename: str) -> Optional[int]: """Read the special tEXt chunk indicating the depth from a PNG file.""" with open(filename, 'rb') as f: f.seek(- (LEN_IEND + LEN_DEPTH), 2) diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index 061bbcb6d..6decc1cef 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -31,8 +31,15 @@ logger = logging.getLogger(__name__) # convert_with_2to3(): # support for running 2to3 over config files def convert_with_2to3(filepath: str) -> str: - from lib2to3.refactor import RefactoringTool, get_fixers_from_package - from lib2to3.pgen2.parse import ParseError + try: + from lib2to3.refactor import RefactoringTool, get_fixers_from_package + from lib2to3.pgen2.parse import ParseError + except ImportError: + # python 3.9.0a6+ emits PendingDeprecationWarning for lib2to3. + # Additionally, removal of the module is still discussed at PEP-594. + # To support future python, this catches ImportError for lib2to3. + raise SyntaxError + fixers = get_fixers_from_package('lib2to3.fixes') refactoring_tool = RefactoringTool(fixers) source = refactoring_tool._read_python_source(filepath)[0] diff --git a/sphinx/util/template.py b/sphinx/util/template.py index 1337f407c..2449a60a1 100644 --- a/sphinx/util/template.py +++ b/sphinx/util/template.py @@ -10,8 +10,11 @@ import os from functools import partial -from typing import Dict, List, Union +from os import path +from typing import Callable, Dict, List, Tuple, Union +from jinja2 import TemplateNotFound +from jinja2.environment import Environment from jinja2.loaders import BaseLoader from jinja2.sandbox import SandboxedEnvironment @@ -94,3 +97,36 @@ class ReSTRenderer(SphinxRenderer): self.env.filters['e'] = rst.escape self.env.filters['escape'] = rst.escape self.env.filters['heading'] = rst.heading + + +class SphinxTemplateLoader(BaseLoader): + """A loader supporting template inheritance""" + + def __init__(self, confdir: str, templates_paths: List[str], + system_templates_paths: List[str]) -> None: + self.loaders = [] + self.sysloaders = [] + + for templates_path in templates_paths: + loader = SphinxFileSystemLoader(path.join(confdir, templates_path)) + self.loaders.append(loader) + + for templates_path in system_templates_paths: + loader = SphinxFileSystemLoader(templates_path) + self.loaders.append(loader) + self.sysloaders.append(loader) + + def get_source(self, environment: Environment, template: str) -> Tuple[str, str, Callable]: + if template.startswith('!'): + # search a template from ``system_templates_paths`` + loaders = self.sysloaders + template = template[1:] + else: + loaders = self.loaders + + for loader in loaders: + try: + return loader.get_source(environment, template) + except TemplateNotFound: + pass + raise TemplateNotFound(template) diff --git a/sphinx/util/typing.py b/sphinx/util/typing.py index 08bf7203b..de92e7593 100644 --- a/sphinx/util/typing.py +++ b/sphinx/util/typing.py @@ -91,11 +91,15 @@ def _stringify_py37(annotation: Any) -> str: if getattr(annotation, '__args__', None): if qualname == 'Union': - if len(annotation.__args__) == 2 and annotation.__args__[1] is NoneType: # type: ignore # NOQA - return 'Optional[%s]' % stringify(annotation.__args__[0]) + if len(annotation.__args__) > 1 and annotation.__args__[-1] is NoneType: # type: ignore # NOQA + if len(annotation.__args__) > 2: + args = ', '.join(stringify(a) for a in annotation.__args__[:-1]) + return 'Optional[Union[%s]]' % args + else: + return 'Optional[%s]' % stringify(annotation.__args__[0]) else: args = ', '.join(stringify(a) for a in annotation.__args__) - return '%s[%s]' % (qualname, args) + return 'Union[%s]' % args elif qualname == 'Callable': args = ', '.join(stringify(a) for a in annotation.__args__[:-1]) returns = stringify(annotation.__args__[-1]) @@ -170,8 +174,12 @@ def _stringify_py36(annotation: Any) -> str: annotation.__origin__ is typing.Union): # for Python 3.5.2+ params = annotation.__args__ if params is not None: - if len(params) == 2 and params[1] is NoneType: # type: ignore - return 'Optional[%s]' % stringify(params[0]) + if len(params) > 1 and params[-1] is NoneType: # type: ignore + if len(params) > 2: + param_str = ", ".join(stringify(p) for p in params[:-1]) + return 'Optional[Union[%s]]' % param_str + else: + return 'Optional[%s]' % stringify(params[0]) else: param_str = ', '.join(stringify(p) for p in params) return 'Union[%s]' % param_str diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 9390ba5de..6e7f5021b 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -96,7 +96,7 @@ class LaTeXWriter(writers.Writer): visitor = self.builder.create_translator(self.document, self.builder, self.theme) except TypeError: warnings.warn('LaTeXTranslator now takes 3rd argument; "theme".', - RemovedInSphinx50Warning) + RemovedInSphinx50Warning, stacklevel=2) visitor = self.builder.create_translator(self.document, self.builder) self.document.walkabout(visitor) @@ -292,7 +292,7 @@ class LaTeXTranslator(SphinxTranslator): if theme is None: warnings.warn('LaTeXTranslator now takes 3rd argument; "theme".', - RemovedInSphinx50Warning) + RemovedInSphinx50Warning, stacklevel=2) # flags self.in_title = 0 @@ -1431,6 +1431,8 @@ class LaTeXTranslator(SphinxTranslator): if 'refuri' in node: return + if 'anonymous' in node: + return if node.get('refid'): prev_node = get_prev_node(node) if isinstance(prev_node, nodes.reference) and node['refid'] == prev_node['refid']: @@ -2072,7 +2074,7 @@ class LaTeXTranslator(SphinxTranslator): def babel_defmacro(self, name: str, definition: str) -> str: warnings.warn('babel_defmacro() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) if self.elements['babel']: prefix = '\\addto\\extras%s{' % self.babel.get_language() @@ -2085,7 +2087,7 @@ class LaTeXTranslator(SphinxTranslator): def generate_numfig_format(self, builder: "LaTeXBuilder") -> str: warnings.warn('generate_numfig_format() is deprecated.', - RemovedInSphinx40Warning) + RemovedInSphinx40Warning, stacklevel=2) ret = [] # type: List[str] figure = self.builder.config.numfig_format['figure'].split('%s', 1) if len(figure) == 1: |