From e294b8e036ffbc5cc0147173fe555780e68cfbbc Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 1 Dec 2018 18:46:22 +0900 Subject: [PATCH 1/2] Add role manipulator functions to sphinx.util.docutils --- sphinx/application.py | 8 ++++---- sphinx/directives/__init__.py | 8 ++++---- sphinx/util/docutils.py | 22 ++++++++++++++++++++++ sphinx/util/rst.py | 5 +++-- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index 58c4de6fb..ec793b19e 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -674,10 +674,10 @@ class Sphinx: Add *override* keyword. """ logger.debug('[app] adding role: %r', (name, role)) - if name in roles._roles and not override: + if not override and docutils.is_role_registered(name): logger.warning(__('role %r is already registered, it will be overridden'), name, type='app', subtype='add_role') - roles.register_local_role(name, role) + docutils.register_role(name, role) def add_generic_role(self, name, nodeclass, override=False): # type: (unicode, Any, bool) -> None @@ -693,11 +693,11 @@ class Sphinx: # Don't use ``roles.register_generic_role`` because it uses # ``register_canonical_role``. logger.debug('[app] adding generic role: %r', (name, nodeclass)) - if name in roles._roles and not override: + if not override and docutils.is_role_registered(name): logger.warning(__('role %r is already registered, it will be overridden'), name, type='app', subtype='add_generic_role') role = roles.GenericRole(name, nodeclass) - roles.register_local_role(name, role) + docutils.register_role(name, role) def add_domain(self, domain, override=False): # type: (Type[Domain], bool) -> None diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py index 7e47bb5fe..30456ef7e 100644 --- a/sphinx/directives/__init__.py +++ b/sphinx/directives/__init__.py @@ -15,6 +15,7 @@ from docutils import nodes from docutils.parsers.rst import directives, roles from sphinx import addnodes +from sphinx.util import docutils from sphinx.util.docfields import DocFieldTransformer from sphinx.util.docutils import SphinxDirective @@ -201,9 +202,7 @@ class DefaultRole(SphinxDirective): def run(self): # type: () -> List[N_co] if not self.arguments: - if '' in roles._roles: - # restore the "default" default role - del roles._roles[''] + docutils.unregister_role('') return [] role_name = self.arguments[0] role, messages = roles.role(role_name, self.state_machine.language, @@ -214,7 +213,8 @@ class DefaultRole(SphinxDirective): nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return messages + [error] - roles._roles[''] = role + + docutils.register_role('', role) self.env.temp_data['default_role'] = role_name return messages diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 820c9c620..07be9f092 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -67,6 +67,28 @@ def docutils_namespace(): additional_nodes.discard(node) +def is_role_registered(name): + # type: (unicode) -> bool + """Check the *name* role is already registered.""" + return name in roles._roles + + +def register_role(name, role): + # type: (unicode, RoleFunction) -> None + """Register a role to docutils. + + This modifies global state of docutils. So it is better to use this + inside ``docutils_namespace()`` to prevent side-effects. + """ + roles.register_local_role(name, role) + + +def unregister_role(name): + # type: (unicode) -> None + """Unregister a role from docutils.""" + roles._roles.pop(name, None) + + def is_node_registered(node): # type: (Type[nodes.Element]) -> bool """Check the *node* is already registered.""" diff --git a/sphinx/util/rst.py b/sphinx/util/rst.py index a59b2b07e..8b8aca9ea 100644 --- a/sphinx/util/rst.py +++ b/sphinx/util/rst.py @@ -18,6 +18,7 @@ from docutils.parsers.rst.languages import en as english from docutils.utils import Reporter from sphinx.locale import __ +from sphinx.util import docutils from sphinx.util import logging if False: @@ -43,10 +44,10 @@ def default_role(docname, name): dummy_reporter = Reporter('', 4, 4) role_fn, _ = roles.role(name, english, 0, dummy_reporter) if role_fn: - roles._roles[''] = role_fn + docutils.register_role('', role_fn) else: logger.warning(__('default role %s not found'), name, location=docname) yield - roles._roles.pop('', None) # if a document has set a local default role + docutils.unregister_role('') From bfd35c6ce179d121b0795ddb90f594e3c9543e34 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 1 Dec 2018 18:57:18 +0900 Subject: [PATCH 2/2] Add role manipulator directives to sphinx.util.docutils --- sphinx/application.py | 8 ++++---- sphinx/util/docutils.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/sphinx/application.py b/sphinx/application.py index ec793b19e..1cabca6ad 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -21,7 +21,7 @@ from inspect import isclass from io import StringIO from os import path -from docutils.parsers.rst import Directive, directives, roles +from docutils.parsers.rst import Directive, roles import sphinx from sphinx import package_dir, locale @@ -651,15 +651,15 @@ class Sphinx: """ logger.debug('[app] adding directive: %r', (name, obj, content, arguments, options)) - if name in directives._directives and not override: + if not override and docutils.is_directive_registered(name): logger.warning(__('directive %r is already registered, it will be overridden'), name, type='app', subtype='add_directive') if not isclass(obj) or not issubclass(obj, Directive): directive = directive_helper(obj, content, arguments, **options) - directives.register_directive(name, directive) + docutils.register_directive(name, directive) else: - directives.register_directive(name, obj) + docutils.register_directive(name, obj) def add_role(self, name, role, override=False): # type: (unicode, Any, bool) -> None diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 07be9f092..7b1edfc34 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -67,6 +67,22 @@ def docutils_namespace(): additional_nodes.discard(node) +def is_directive_registered(name): + # type: (unicode) -> bool + """Check the *name* directive is already registered.""" + return name in directives._directives + + +def register_directive(name, directive): + # type: (unicode, Type[Directive]) -> None + """Register a directive to docutils. + + This modifies global state of docutils. So it is better to use this + inside ``docutils_namespace()`` to prevent side-effects. + """ + directives.register_directive(name, directive) + + def is_role_registered(name): # type: (unicode) -> bool """Check the *name* role is already registered."""