mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '3.x'
This commit is contained in:
commit
5460ea103b
29
CHANGES
29
CHANGES
@ -81,6 +81,12 @@ Features added
|
||||
* #8619: html: kbd role generates customizable HTML tags for compound keys
|
||||
* #8634: html: Allow to change the order of JS/CSS via ``priority`` parameter
|
||||
for :meth:`Sphinx.add_js_file()` and :meth:`Sphinx.add_css_file()`
|
||||
* #6241: html: Allow to add JS/CSS files to the specific page when an extension
|
||||
calls ``app.add_js_file()`` or ``app.add_css_file()`` on
|
||||
:event:`html-page-context` event
|
||||
* #8649: imgconverter: Skip availability check if builder supports the image
|
||||
type
|
||||
* #6241: mathjax: Include mathjax.js only on the document using equations
|
||||
* #8132: Add :confval:`project_copyright` as an alias of :confval:`copyright`
|
||||
|
||||
Bugs fixed
|
||||
@ -102,7 +108,7 @@ Bugs fixed
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 3.4.2 (in development)
|
||||
Release 3.4.4 (in development)
|
||||
==============================
|
||||
|
||||
Dependencies
|
||||
@ -120,15 +126,30 @@ Features added
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 3.4.3 (released Jan 08, 2021)
|
||||
=====================================
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #8655: autodoc: Failed to generate document if target module contains an
|
||||
object that raises an exception on ``hasattr()``
|
||||
|
||||
Release 3.4.2 (released Jan 04, 2021)
|
||||
=====================================
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #8164: autodoc: Classes that inherit mocked class are not documented
|
||||
* #8602: autodoc: The ``autodoc-process-docstring`` event is emitted to the
|
||||
non-datadescriptors unexpectedly
|
||||
* #8616: autodoc: AttributeError is raised on non-class object is passed to
|
||||
autoclass directive
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 3.4.1 (released Dec 25, 2020)
|
||||
=====================================
|
||||
|
||||
|
@ -376,6 +376,9 @@ Here is a more detailed list of these events.
|
||||
You can return a string from the handler, it will then replace
|
||||
``'page.html'`` as the HTML template for this page.
|
||||
|
||||
.. note:: You can install JS/CSS files for the specific page via
|
||||
:meth:`Sphinx.add_js_file` and :meth:`Sphinx.add_css_file` since v3.5.0.
|
||||
|
||||
.. versionadded:: 0.4
|
||||
|
||||
.. versionchanged:: 1.3
|
||||
|
@ -1003,7 +1003,14 @@ that use Sphinx's HTMLWriter class.
|
||||
'https://example.com/css/custom.css',
|
||||
('print.css', {'media': 'print'})]
|
||||
|
||||
As a special attribute, *priority* can be set as an integer to load the CSS
|
||||
file earlier or lazier step. For more information, refer
|
||||
:meth:`Sphinx.add_css_files()`.
|
||||
|
||||
.. versionadded:: 1.8
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
Support priority attribute
|
||||
|
||||
.. confval:: html_js_files
|
||||
|
||||
@ -1019,7 +1026,14 @@ that use Sphinx's HTMLWriter class.
|
||||
'https://example.com/scripts/custom.js',
|
||||
('custom.js', {'async': 'async'})]
|
||||
|
||||
As a special attribute, *priority* can be set as an integer to load the CSS
|
||||
file earlier or lazier step. For more information, refer
|
||||
:meth:`Sphinx.add_css_files()`.
|
||||
|
||||
.. versionadded:: 1.8
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
Support priority attribute
|
||||
|
||||
.. confval:: html_static_path
|
||||
|
||||
|
@ -917,9 +917,11 @@ class Sphinx:
|
||||
Add *filename* to the list of JavaScript files that the default HTML
|
||||
template will include in order of *priority* (ascending). The filename
|
||||
must be relative to the HTML static path , or a full URI with scheme.
|
||||
If the keyword argument ``body`` is given, its value will be added
|
||||
between the ``<script>`` tags. Extra keyword arguments are included as
|
||||
attributes of the ``<script>`` tag.
|
||||
If the priority of JavaScript file is the same as others, the JavaScript
|
||||
files will be included in order of the registration. If the keyword
|
||||
argument ``body`` is given, its value will be added between the
|
||||
``<script>`` tags. Extra keyword arguments are included as attributes of
|
||||
the ``<script>`` tag.
|
||||
|
||||
Example::
|
||||
|
||||
@ -944,6 +946,9 @@ class Sphinx:
|
||||
* - 800
|
||||
- default priority for :confval:`html_js_files`
|
||||
|
||||
A JavaScript file can be added to the specific HTML page when on extension
|
||||
calls this method on :event:`html-page-context` event.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. versionchanged:: 1.8
|
||||
@ -951,7 +956,7 @@ class Sphinx:
|
||||
And it allows keyword arguments as attributes of script tag.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
Take priority argument.
|
||||
Take priority argument. Allow to add a JavaScript file to the specific page.
|
||||
"""
|
||||
self.registry.add_js_file(filename, priority=priority, **kwargs)
|
||||
if hasattr(self.builder, 'add_js_file'):
|
||||
@ -962,8 +967,10 @@ class Sphinx:
|
||||
|
||||
Add *filename* to the list of CSS files that the default HTML template
|
||||
will include in order of *priority* (ascending). The filename must be
|
||||
relative to the HTML static path, or a full URI with scheme. The
|
||||
eyword arguments are also accepted for attributes of ``<link>`` tag.
|
||||
relative to the HTML static path, or a full URI with scheme. If the
|
||||
priority of CSS file is the same as others, the CSS files will be
|
||||
included in order of the registration. The keyword arguments are also
|
||||
accepted for attributes of ``<link>`` tag.
|
||||
|
||||
Example::
|
||||
|
||||
@ -990,6 +997,9 @@ class Sphinx:
|
||||
* - 800
|
||||
- default priority for :confval:`html_css_files`
|
||||
|
||||
A CSS file can be added to the specific HTML page when on extension calls
|
||||
this method on :event:`html-page-context` event.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
|
||||
.. versionchanged:: 1.6
|
||||
@ -1004,7 +1014,7 @@ class Sphinx:
|
||||
And it allows keyword arguments as attributes of link tag.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
Take priority argument.
|
||||
Take priority argument. Allow to add a CSS file to the specific page.
|
||||
"""
|
||||
logger.debug('[app] adding stylesheet: %r', filename)
|
||||
self.registry.add_css_files(filename, priority=priority, **kwargs)
|
||||
|
@ -481,6 +481,10 @@ class StandaloneHTMLBuilder(Builder):
|
||||
rellinks.append((indexname, indexcls.localname,
|
||||
'', indexcls.shortname))
|
||||
|
||||
# back up script_files and css_files to allow adding JS/CSS files to a specific page.
|
||||
self._script_files = list(self.script_files)
|
||||
self._css_files = list(self.css_files)
|
||||
|
||||
self.globalcontext = {
|
||||
'embedded': self.embedded,
|
||||
'project': self.config.project,
|
||||
@ -1014,6 +1018,10 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.add_sidebars(pagename, ctx)
|
||||
ctx.update(addctx)
|
||||
|
||||
# revert script_files and css_files
|
||||
self.script_files[:] = self._script_files
|
||||
self.css_files[:] = self.css_files
|
||||
|
||||
self.update_page_context(pagename, templatename, ctx, event_arg)
|
||||
newtmpl = self.app.emit_firstresult('html-page-context', pagename,
|
||||
templatename, ctx, event_arg)
|
||||
|
@ -9,7 +9,7 @@
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Tuple, cast
|
||||
from typing import TYPE_CHECKING, Any, Dict, Generic, List, Tuple, TypeVar, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node
|
||||
@ -31,6 +31,8 @@ if TYPE_CHECKING:
|
||||
nl_escape_re = re.compile(r'\\\n')
|
||||
strip_backslash_re = re.compile(r'\\(.)')
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
def optional_int(argument: str) -> int:
|
||||
"""
|
||||
@ -45,7 +47,7 @@ def optional_int(argument: str) -> int:
|
||||
return value
|
||||
|
||||
|
||||
class ObjectDescription(SphinxDirective):
|
||||
class ObjectDescription(SphinxDirective, Generic[T]):
|
||||
"""
|
||||
Directive to describe a class, function or similar object. Not used
|
||||
directly, but subclassed (in domain-specific directives) to add custom
|
||||
@ -95,7 +97,7 @@ class ObjectDescription(SphinxDirective):
|
||||
else:
|
||||
return [line.strip() for line in lines]
|
||||
|
||||
def handle_signature(self, sig: str, signode: desc_signature) -> Any:
|
||||
def handle_signature(self, sig: str, signode: desc_signature) -> T:
|
||||
"""
|
||||
Parse the signature *sig* into individual nodes and append them to
|
||||
*signode*. If ValueError is raised, parsing is aborted and the whole
|
||||
@ -107,7 +109,7 @@ class ObjectDescription(SphinxDirective):
|
||||
"""
|
||||
raise ValueError
|
||||
|
||||
def add_target_and_index(self, name: Any, sig: str, signode: desc_signature) -> None:
|
||||
def add_target_and_index(self, name: T, sig: str, signode: desc_signature) -> None:
|
||||
"""
|
||||
Add cross-reference IDs and entries to self.indexnode, if applicable.
|
||||
|
||||
@ -171,7 +173,7 @@ class ObjectDescription(SphinxDirective):
|
||||
if self.domain:
|
||||
node['classes'].append(self.domain)
|
||||
|
||||
self.names = [] # type: List[Any]
|
||||
self.names = [] # type: List[T]
|
||||
signatures = self.get_signatures()
|
||||
for i, sig in enumerate(signatures):
|
||||
# add a signature node for each signature in the current unit
|
||||
|
@ -3099,7 +3099,7 @@ def _make_phony_error_name() -> ASTNestedName:
|
||||
return ASTNestedName([ASTIdentifier("PhonyNameDueToError")], rooted=False)
|
||||
|
||||
|
||||
class CObject(ObjectDescription):
|
||||
class CObject(ObjectDescription[ASTDeclaration]):
|
||||
"""
|
||||
Description of a C language object.
|
||||
"""
|
||||
|
@ -6670,7 +6670,7 @@ def _make_phony_error_name() -> ASTNestedName:
|
||||
return ASTNestedName([nne], [False], rooted=False)
|
||||
|
||||
|
||||
class CPPObject(ObjectDescription):
|
||||
class CPPObject(ObjectDescription[ASTDeclaration]):
|
||||
"""Description of a C++ language object."""
|
||||
|
||||
doc_field_types = [
|
||||
|
@ -32,7 +32,7 @@ from sphinx.util.nodes import make_id, make_refnode
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class JSObject(ObjectDescription):
|
||||
class JSObject(ObjectDescription[Tuple[str, str]]):
|
||||
"""
|
||||
Description of a JavaScript object.
|
||||
"""
|
||||
|
@ -136,8 +136,11 @@ class MathDomain(Domain):
|
||||
def get_objects(self) -> List:
|
||||
return []
|
||||
|
||||
def has_equations(self) -> bool:
|
||||
return any(self.data['has_equations'].values())
|
||||
def has_equations(self, docname: str = None) -> bool:
|
||||
if docname:
|
||||
return self.data['has_equations'].get(docname, False)
|
||||
else:
|
||||
return any(self.data['has_equations'].values())
|
||||
|
||||
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
|
@ -333,7 +333,7 @@ class PyTypedField(PyXrefMixin, TypedField):
|
||||
return super().make_xref(rolename, domain, target, innernode, contnode, env)
|
||||
|
||||
|
||||
class PyObject(ObjectDescription):
|
||||
class PyObject(ObjectDescription[Tuple[str, str]]):
|
||||
"""
|
||||
Description of a general Python object.
|
||||
|
||||
|
@ -31,7 +31,7 @@ logger = logging.getLogger(__name__)
|
||||
dir_sig_re = re.compile(r'\.\. (.+?)::(.*)$')
|
||||
|
||||
|
||||
class ReSTMarkup(ObjectDescription):
|
||||
class ReSTMarkup(ObjectDescription[str]):
|
||||
"""
|
||||
Description of generic reST markup.
|
||||
"""
|
||||
|
@ -46,7 +46,7 @@ option_desc_re = re.compile(r'((?:/|--|-|\+)?[^\s=]+)(=?\s*.*)')
|
||||
token_re = re.compile(r'`(\w+)`', re.U)
|
||||
|
||||
|
||||
class GenericObject(ObjectDescription):
|
||||
class GenericObject(ObjectDescription[str]):
|
||||
"""
|
||||
A generic x-ref directive registered with Sphinx.add_object_type().
|
||||
"""
|
||||
@ -176,7 +176,7 @@ class Target(SphinxDirective):
|
||||
return self.name + '-' + name
|
||||
|
||||
|
||||
class Cmdoption(ObjectDescription):
|
||||
class Cmdoption(ObjectDescription[str]):
|
||||
"""
|
||||
Description of a command-line option (.. option).
|
||||
"""
|
||||
|
@ -153,7 +153,10 @@ def mock(modnames: List[str]) -> Generator[None, None, None]:
|
||||
def ismock(subject: Any) -> bool:
|
||||
"""Check if the object is mocked."""
|
||||
# check the object has '__sphinx_mock__' attribute
|
||||
if not hasattr(subject, '__sphinx_mock__'):
|
||||
try:
|
||||
if safe_getattr(subject, '__sphinx_mock__', None) is None:
|
||||
return False
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
# check the object is mocked module
|
||||
|
@ -17,14 +17,16 @@ from docutils import nodes
|
||||
|
||||
import sphinx
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
from sphinx.domains.math import MathDomain
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.errors import ExtensionError
|
||||
from sphinx.locale import _
|
||||
from sphinx.util.math import get_node_equation_number
|
||||
from sphinx.writers.html import HTMLTranslator
|
||||
|
||||
# more information for mathjax secure url is here:
|
||||
# https://docs.mathjax.org/en/latest/start.html#secure-access-to-the-cdn
|
||||
MATHJAX_URL = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js'
|
||||
|
||||
|
||||
def html_visit_math(self: HTMLTranslator, node: nodes.math) -> None:
|
||||
self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate nohighlight'))
|
||||
@ -66,25 +68,25 @@ def html_visit_displaymath(self: HTMLTranslator, node: nodes.math_block) -> None
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
def install_mathjax(app: Sphinx, env: BuildEnvironment) -> None:
|
||||
def install_mathjax(app: Sphinx, pagename: str, templatename: str, context: Dict,
|
||||
event_arg: Any) -> None:
|
||||
if app.builder.format != 'html' or app.builder.math_renderer_name != 'mathjax': # type: ignore # NOQA
|
||||
return
|
||||
if not app.config.mathjax_path:
|
||||
raise ExtensionError('mathjax_path config value must be set for the '
|
||||
'mathjax extension to work')
|
||||
|
||||
builder = cast(StandaloneHTMLBuilder, app.builder)
|
||||
domain = cast(MathDomain, env.get_domain('math'))
|
||||
if domain.has_equations():
|
||||
domain = cast(MathDomain, app.env.get_domain('math'))
|
||||
if domain.has_equations(pagename):
|
||||
# Enable mathjax only if equations exists
|
||||
options = {'async': 'async'}
|
||||
if app.config.mathjax_options:
|
||||
options.update(app.config.mathjax_options)
|
||||
builder.add_js_file(app.config.mathjax_path, **options)
|
||||
app.add_js_file(app.config.mathjax_path, **options) # type: ignore
|
||||
|
||||
if app.config.mathjax_config:
|
||||
body = "MathJax.Hub.Config(%s)" % json.dumps(app.config.mathjax_config)
|
||||
builder.add_js_file(None, type="text/x-mathjax-config", body=body)
|
||||
app.add_js_file(None, type="text/x-mathjax-config", body=body)
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
@ -92,15 +94,11 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
(html_visit_math, None),
|
||||
(html_visit_displaymath, None))
|
||||
|
||||
# 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://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js',
|
||||
'html')
|
||||
app.add_config_value('mathjax_path', MATHJAX_URL, 'html')
|
||||
app.add_config_value('mathjax_options', {}, 'html')
|
||||
app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html')
|
||||
app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html')
|
||||
app.add_config_value('mathjax_config', None, 'html')
|
||||
app.connect('env-updated', install_mathjax)
|
||||
app.connect('html-page-context', install_mathjax)
|
||||
|
||||
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
|
||||
|
@ -197,15 +197,15 @@ class ImageConverter(BaseImageConverter):
|
||||
def match(self, node: nodes.image) -> bool:
|
||||
if not self.app.builder.supported_image_types:
|
||||
return False
|
||||
elif set(node['candidates']) & set(self.app.builder.supported_image_types):
|
||||
# builder supports the image; no need to convert
|
||||
return False
|
||||
elif self.available is None:
|
||||
# store the value to the class variable to share it during the build
|
||||
self.__class__.available = self.is_available()
|
||||
|
||||
if not self.available:
|
||||
return False
|
||||
elif set(node['candidates']) & set(self.app.builder.supported_image_types):
|
||||
# builder supports the image; no need to convert
|
||||
return False
|
||||
else:
|
||||
rule = self.get_conversion_rule(node)
|
||||
if rule:
|
||||
|
@ -6,6 +6,7 @@ Test Math
|
||||
|
||||
math
|
||||
page
|
||||
nomath
|
||||
|
||||
.. math:: a^2+b^2=c^2
|
||||
|
||||
|
0
tests/roots/test-ext-math/nomath.rst
Normal file
0
tests/roots/test-ext-math/nomath.rst
Normal file
@ -4,7 +4,9 @@ version = '1.4.4'
|
||||
html_static_path = ['static', 'subdir']
|
||||
html_extra_path = ['extra', 'subdir']
|
||||
html_css_files = ['css/style.css',
|
||||
('https://example.com/custom.css', {'title': 'title', 'media': 'print'})]
|
||||
('https://example.com/custom.css',
|
||||
{'title': 'title', 'media': 'print', 'priority': 400})]
|
||||
html_js_files = ['js/custom.js',
|
||||
('https://example.com/script.js', {'async': 'async'})]
|
||||
('https://example.com/script.js',
|
||||
{'async': 'async', 'priority': 400})]
|
||||
exclude_patterns = ['**/_build', '**/.htpasswd']
|
||||
|
@ -1220,15 +1220,15 @@ def test_assets_order(app):
|
||||
|
||||
# css_files
|
||||
expected = ['_static/early.css', '_static/pygments.css', '_static/alabaster.css',
|
||||
'_static/normal.css', '_static/late.css', '_static/css/style.css',
|
||||
'https://example.com/custom.css', '_static/lazy.css']
|
||||
'https://example.com/custom.css', '_static/normal.css', '_static/late.css',
|
||||
'_static/css/style.css', '_static/lazy.css']
|
||||
pattern = '.*'.join('href="%s"' % f for f in expected)
|
||||
assert re.search(pattern, content, re.S)
|
||||
|
||||
# js_files
|
||||
expected = ['_static/early.js', '_static/jquery.js', '_static/underscore.js',
|
||||
'_static/doctools.js', '_static/normal.js', '_static/late.js',
|
||||
'_static/js/custom.js', 'https://example.com/script.js', '_static/lazy.js']
|
||||
'_static/doctools.js', 'https://example.com/script.js', '_static/normal.js',
|
||||
'_static/late.js', '_static/js/custom.js', '_static/lazy.js']
|
||||
pattern = '.*'.join('src="%s"' % f for f in expected)
|
||||
assert re.search(pattern, content, re.S)
|
||||
|
||||
|
@ -15,6 +15,7 @@ import warnings
|
||||
import pytest
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx.ext.mathjax import MATHJAX_URL
|
||||
from sphinx.testing.util import assert_node
|
||||
|
||||
|
||||
@ -224,6 +225,18 @@ def test_mathjax_config(app, status, warning):
|
||||
'</script>' in content)
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-math',
|
||||
confoverrides={'extensions': ['sphinx.ext.mathjax']})
|
||||
def test_mathjax_is_installed_only_if_document_having_math(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
||||
content = (app.outdir / 'index.html').read_text()
|
||||
assert MATHJAX_URL in content
|
||||
|
||||
content = (app.outdir / 'nomath.html').read_text()
|
||||
assert MATHJAX_URL not in content
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='basic',
|
||||
confoverrides={'extensions': ['sphinx.ext.mathjax']})
|
||||
def test_mathjax_is_not_installed_if_no_equations(app, status, warning):
|
||||
|
@ -4,7 +4,7 @@ Release checklist
|
||||
for stable releases
|
||||
-------------------
|
||||
|
||||
* open https://github.com/sphinx-doc/sphinx/actions?query=branch:X.Y.x and all tests has passed
|
||||
* open "https://github.com/sphinx-doc/sphinx/actions?query=branch:X.Y.x" and all tests has passed
|
||||
* Run ``git fetch; git status`` and check nothing changed
|
||||
* ``python utils/bump_version.py X.Y.Z``
|
||||
* Check diff by ``git diff``
|
||||
@ -28,7 +28,7 @@ for stable releases
|
||||
for first beta releases
|
||||
-----------------------
|
||||
|
||||
* open https://github.com/sphinx-doc/sphinx/actions?query=branch:master and all tests has passed
|
||||
* open "https://github.com/sphinx-doc/sphinx/actions?query=branch:master" and all tests has passed
|
||||
* Run ``git fetch; git status`` and check nothing changed
|
||||
* Run ``python setup.py extract_messages``
|
||||
* Run ``(cd sphinx/locale; tx push -s)``
|
||||
@ -58,7 +58,7 @@ for first beta releases
|
||||
for other beta releases
|
||||
-----------------------
|
||||
|
||||
* open https://github.com/sphinx-doc/sphinx/actions?query=branch:X.x and all tests has passed
|
||||
* open "https://github.com/sphinx-doc/sphinx/actions?query=branch:X.x" and all tests has passed
|
||||
* Run ``git fetch; git status`` and check nothing changed
|
||||
* ``python utils/bump_version.py X.Y.0bN``
|
||||
* Check diff by ``git diff``
|
||||
@ -81,7 +81,7 @@ for other beta releases
|
||||
for major releases
|
||||
------------------
|
||||
|
||||
* open https://github.com/sphinx-doc/sphinx/actions?query=branch:X.x and all tests has passed
|
||||
* open "https://github.com/sphinx-doc/sphinx/actions?query=branch:X.x" and all tests has passed
|
||||
* Run ``git fetch; git status`` and check nothing changed
|
||||
* Run ``(cd sphinx/locale; tx pull -a -f)``
|
||||
* Run ``python setup.py compile_catalog``
|
||||
|
Loading…
Reference in New Issue
Block a user