Skip to content

Commit

Permalink
Merge branch '5.0.x' into 5.x
Browse files Browse the repository at this point in the history
  • Loading branch information
tk0miya committed May 22, 2022
2 parents 419d594 + dea4873 commit b4eca32
Show file tree
Hide file tree
Showing 146 changed files with 485 additions and 360 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/coverage.yml
@@ -0,0 +1,32 @@
name: Coverage

on: [push]

jobs:
coverage:
runs-on: ubuntu-latest
if: github.repository_owner == 'sphinx-doc'

steps:
- uses: actions/checkout@v3
- name: Set up Python 3
uses: actions/setup-python@v3
with:
python-version: 3

- name: Check Python version
run: python --version

- name: Install graphviz
run: sudo apt-get install graphviz

- name: Install dependencies
run: python -m pip install -U pip tox pytest-cov

- name: Run Tox
run: tox --sitepackages -e py -- -vv
env:
PYTEST_ADDOPTS: "--cov ./ --cov-append --cov-config setup.cfg"

- name: codecov
uses: codecov/codecov-action@v3
29 changes: 0 additions & 29 deletions .github/workflows/main.yml
Expand Up @@ -56,32 +56,3 @@ jobs:
run: python -m pip install -U pip tox
- name: Run Tox
run: tox -e py -- -vv

coverage:
# only run on pushes to branches in the sphinx-doc/sphinx repo
if: github.repository_owner == 'sphinx-doc' && github.event_name == 'push'
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Python 3
uses: actions/setup-python@v3
with:
python-version: 3

- name: Check Python version
run: python --version

- name: Install graphviz
run: sudo apt-get install graphviz

- name: Install dependencies
run: python -m pip install -U pip tox pytest-cov

- name: Run Tox
run: tox --sitepackages -e py -- -vv
env:
PYTEST_ADDOPTS: "--cov ./ --cov-append --cov-config setup.cfg"

- name: codecov
uses: codecov/codecov-action@v3
32 changes: 11 additions & 21 deletions CHANGES
@@ -1,24 +1,3 @@
Release 5.1.0 (in development)
==============================

Dependencies
------------

Incompatible changes
--------------------

Deprecated
----------

Features added
--------------

Bugs fixed
----------

Testing
--------

Release 5.0.0 beta2 (in development)
====================================

Expand All @@ -37,6 +16,17 @@ Features added
Bugs fixed
----------

* #9575: autodoc: The annotation of return value should not be shown when
``autodoc_typehints="description"``
* #9648: autodoc: ``*args`` and ``**kwargs`` entries are duplicated when
``autodoc_typehints="description"``
* #10443: epub: EPUB builder can't detect the mimetype of .webp file
* #10456: py domain: ``:meta:`` fields are displayed if docstring contains two
or more meta-field
* #9096: sphinx-build: the value of progress bar for paralle build is wrong
* #10110: sphinx-build: exit code is not changed when error is raised on
builder-finished event

Testing
--------

Expand Down
6 changes: 3 additions & 3 deletions sphinx/__init__.py
Expand Up @@ -21,8 +21,8 @@
warnings.filterwarnings('ignore', 'The frontend.Option class .*',
DeprecationWarning, module='docutils.frontend')

__version__ = '5.1.0+'
__released__ = '5.1.0' # used when Sphinx builds its own docs
__version__ = '5.0.0b1'
__released__ = '5.0.0b1' # used when Sphinx builds its own docs

#: Version info for better programmatic use.
#:
Expand All @@ -32,7 +32,7 @@
#:
#: .. versionadded:: 1.2
#: Before version 1.2, check the string ``sphinx.__version__``.
version_info = (5, 1, 0, 'beta', 0)
version_info = (5, 0, 0, 'beta', 1)

package_dir = path.abspath(path.dirname(__file__))

Expand Down
57 changes: 29 additions & 28 deletions sphinx/application.py
Expand Up @@ -328,42 +328,43 @@ def build(self, force_all: bool = False, filenames: List[str] = None) -> None:
self.builder.compile_update_catalogs()
self.builder.build_update()

if self._warncount and self.keep_going:
self.statuscode = 1

status = (__('succeeded') if self.statuscode == 0
else __('finished with problems'))
if self._warncount:
if self.warningiserror:
if self._warncount == 1:
msg = __('build %s, %s warning (with warnings treated as errors).')
else:
msg = __('build %s, %s warnings (with warnings treated as errors).')
else:
if self._warncount == 1:
msg = __('build %s, %s warning.')
else:
msg = __('build %s, %s warnings.')

logger.info(bold(msg % (status, self._warncount)))
else:
logger.info(bold(__('build %s.') % status))

if self.statuscode == 0 and self.builder.epilog:
logger.info('')
logger.info(self.builder.epilog % {
'outdir': relpath(self.outdir),
'project': self.config.project
})
self.events.emit('build-finished', None)
except Exception as err:
# delete the saved env to force a fresh build next time
envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
if path.isfile(envfile):
os.unlink(envfile)
self.events.emit('build-finished', err)
raise

if self._warncount and self.keep_going:
self.statuscode = 1

status = (__('succeeded') if self.statuscode == 0
else __('finished with problems'))
if self._warncount:
if self.warningiserror:
if self._warncount == 1:
msg = __('build %s, %s warning (with warnings treated as errors).')
else:
msg = __('build %s, %s warnings (with warnings treated as errors).')
else:
if self._warncount == 1:
msg = __('build %s, %s warning.')
else:
msg = __('build %s, %s warnings.')

logger.info(bold(msg % (status, self._warncount)))
else:
self.events.emit('build-finished', None)
logger.info(bold(__('build %s.') % status))

if self.statuscode == 0 and self.builder.epilog:
logger.info('')
logger.info(self.builder.epilog % {
'outdir': relpath(self.outdir),
'project': self.config.project
})

self.builder.cleanup()

# ---- general extensibility interface -------------------------------------
Expand Down
32 changes: 23 additions & 9 deletions sphinx/builders/__init__.py
Expand Up @@ -25,6 +25,7 @@
from sphinx.util.osutil import SEP, ensuredir, relative_uri, relpath
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, parallel_available
from sphinx.util.tags import Tags
from sphinx.util.typing import NoneType

# side effect: registers roles and directives
from sphinx import directives # NOQA isort:skip
Expand Down Expand Up @@ -429,6 +430,13 @@ def _read_serial(self, docnames: List[str]) -> None:
self.read_doc(docname)

def _read_parallel(self, docnames: List[str], nproc: int) -> None:
chunks = make_chunks(docnames, nproc)

# create a status_iterator to step progressbar after reading a document
# (see: ``merge()`` function)
progress = status_iterator(chunks, __('reading sources... '), "purple",
len(chunks), self.app.verbosity)

# clear all outdated docs at once
for docname in docnames:
self.events.emit('env-purge-doc', self.env, docname)
Expand All @@ -445,16 +453,15 @@ def merge(docs: List[str], otherenv: bytes) -> None:
env = pickle.loads(otherenv)
self.env.merge_info_from(docs, env, self.app)

tasks = ParallelTasks(nproc)
chunks = make_chunks(docnames, nproc)
next(progress)

for chunk in status_iterator(chunks, __('reading sources... '), "purple",
len(chunks), self.app.verbosity):
tasks = ParallelTasks(nproc)
for chunk in chunks:
tasks.add_task(read_process, chunk, merge)

# make sure all threads have finished
logger.info(bold(__('waiting for workers...')))
tasks.join()
logger.info('')

def read_doc(self, docname: str) -> None:
"""Parse a file and add/update inventory entries for the doctree."""
Expand Down Expand Up @@ -563,19 +570,26 @@ def write_process(docs: List[Tuple[str, nodes.document]]) -> None:
tasks = ParallelTasks(nproc)
chunks = make_chunks(docnames, nproc)

# create a status_iterator to step progressbar after writing a document
# (see: ``on_chunk_done()`` function)
progress = status_iterator(chunks, __('writing output... '), "darkgreen",
len(chunks), self.app.verbosity)

def on_chunk_done(args: List[Tuple[str, NoneType]], result: NoneType) -> None:
next(progress)

self.app.phase = BuildPhase.RESOLVING
for chunk in status_iterator(chunks, __('writing output... '), "darkgreen",
len(chunks), self.app.verbosity):
for chunk in chunks:
arg = []
for docname in chunk:
doctree = self.env.get_and_resolve_doctree(docname, self)
self.write_doc_serialized(docname, doctree)
arg.append((docname, doctree))
tasks.add_task(write_process, arg)
tasks.add_task(write_process, arg, on_chunk_done)

# make sure all threads have finished
logger.info(bold(__('waiting for workers...')))
tasks.join()
logger.info('')

def prepare_writing(self, docnames: Set[str]) -> None:
"""A place where you can add logic before :meth:`write_doc` is run"""
Expand Down
1 change: 1 addition & 0 deletions sphinx/builders/_epub_base.py
Expand Up @@ -56,6 +56,7 @@
'.xhtml': 'application/xhtml+xml',
'.css': 'text/css',
'.png': 'image/png',
'.webp': 'image/webp',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.jpg': 'image/jpeg',
Expand Down
4 changes: 2 additions & 2 deletions sphinx/domains/python.py
Expand Up @@ -1068,11 +1068,11 @@ def filter_meta_fields(app: Sphinx, domain: str, objtype: str, content: Element)
for node in content:
if isinstance(node, nodes.field_list):
fields = cast(List[nodes.field], node)
for field in fields:
# removing list items while iterating the list needs reversed()
for field in reversed(fields):
field_name = cast(nodes.field_body, field[0]).astext().strip()
if field_name == 'meta' or field_name.startswith('meta '):
node.remove(field)
break


class PythonModuleIndex(Index):
Expand Down
32 changes: 27 additions & 5 deletions sphinx/ext/autodoc/typehints.py
Expand Up @@ -59,7 +59,10 @@ def merge_typehints(app: Sphinx, domain: str, objtype: str, contentnode: Element

for field_list in field_lists:
if app.config.autodoc_typehints_description_target == "all":
modify_field_list(field_list, annotations[fullname])
if objtype == 'class':
modify_field_list(field_list, annotations[fullname], suppress_rtype=True)
else:
modify_field_list(field_list, annotations[fullname])
elif app.config.autodoc_typehints_description_target == "documented_params":
augment_descriptions_with_types(
field_list, annotations[fullname], force_rtype=True
Expand All @@ -83,7 +86,8 @@ def insert_field_list(node: Element) -> nodes.field_list:
return field_list


def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> None:
def modify_field_list(node: nodes.field_list, annotations: Dict[str, str],
suppress_rtype: bool = False) -> None:
arguments: Dict[str, Dict[str, bool]] = {}
fields = cast(Iterable[nodes.field], node)
for field in fields:
Expand Down Expand Up @@ -111,7 +115,15 @@ def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> No
if name == 'return':
continue

arg = arguments.get(name, {})
if '*' + name in arguments:
name = '*' + name
arguments.get(name)
elif '**' + name in arguments:
name = '**' + name
arguments.get(name)
else:
arg = arguments.get(name, {})

if not arg.get('type'):
field = nodes.field()
field += nodes.field_name('', 'type ' + name)
Expand All @@ -124,6 +136,10 @@ def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> No
node += field

if 'return' in annotations and 'return' not in arguments:
annotation = annotations['return']
if annotation == 'None' and suppress_rtype:
return

field = nodes.field()
field += nodes.field_name('', 'rtype')
field += nodes.field_body('', nodes.paragraph('', annotation))
Expand Down Expand Up @@ -159,13 +175,19 @@ def augment_descriptions_with_types(
has_type.add('return')

# Add 'type' for parameters with a description but no declared type.
for name in annotations:
for name, annotation in annotations.items():
if name in ('return', 'returns'):
continue

if '*' + name in has_description:
name = '*' + name
elif '**' + name in has_description:
name = '**' + name

if name in has_description and name not in has_type:
field = nodes.field()
field += nodes.field_name('', 'type ' + name)
field += nodes.field_body('', nodes.paragraph('', annotations[name]))
field += nodes.field_body('', nodes.paragraph('', annotation))
node += field

# Add 'rtype' if 'return' is present and 'rtype' isn't.
Expand Down
Binary file modified sphinx/locale/ar/LC_MESSAGES/sphinx.mo
Binary file not shown.

0 comments on commit b4eca32

Please sign in to comment.