Migrate to py3 style type annotation: sphinx.config

This commit is contained in:
Takeshi KOMIYA 2019-12-25 01:48:10 +09:00
parent 6e88d66543
commit 7f5acbdf1f

View File

@ -14,7 +14,9 @@ import types
import warnings import warnings
from collections import OrderedDict from collections import OrderedDict
from os import path, getenv from os import path, getenv
from typing import Any, NamedTuple, Union from typing import (
Any, Callable, Dict, Generator, Iterator, List, NamedTuple, Set, Tuple, Union
)
from sphinx.deprecation import RemovedInSphinx30Warning, RemovedInSphinx40Warning from sphinx.deprecation import RemovedInSphinx30Warning, RemovedInSphinx40Warning
from sphinx.errors import ConfigError, ExtensionError from sphinx.errors import ConfigError, ExtensionError
@ -23,14 +25,13 @@ from sphinx.util import logging
from sphinx.util.i18n import format_date from sphinx.util.i18n import format_date
from sphinx.util.osutil import cd from sphinx.util.osutil import cd
from sphinx.util.pycompat import execfile_ from sphinx.util.pycompat import execfile_
from sphinx.util.tags import Tags
from sphinx.util.typing import NoneType from sphinx.util.typing import NoneType
if False: if False:
# For type annotation # For type annotation
from typing import Callable, Dict, Generator, Iterator, List, Set, Tuple # NOQA from sphinx.application import Sphinx
from sphinx.application import Sphinx # NOQA from sphinx.environment import BuildEnvironment
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.util.tags import Tags # NOQA
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -43,8 +44,7 @@ ConfigValue = NamedTuple('ConfigValue', [('name', str),
('rebuild', Union[bool, str])]) ('rebuild', Union[bool, str])])
def is_serializable(obj): def is_serializable(obj: Any) -> bool:
# type: (Any) -> bool
"""Check if object is serializable or not.""" """Check if object is serializable or not."""
if isinstance(obj, UNSERIALIZABLE_TYPES): if isinstance(obj, UNSERIALIZABLE_TYPES):
return False return False
@ -64,12 +64,10 @@ class ENUM:
Example: Example:
app.add_config_value('latex_show_urls', 'no', None, ENUM('no', 'footnote', 'inline')) app.add_config_value('latex_show_urls', 'no', None, ENUM('no', 'footnote', 'inline'))
""" """
def __init__(self, *candidates): def __init__(self, *candidates: str) -> None:
# type: (str) -> None
self.candidates = candidates self.candidates = candidates
def match(self, value): def match(self, value: Union[str, List, Tuple]) -> bool:
# type: (Union[str, List, Tuple]) -> bool
if isinstance(value, (list, tuple)): if isinstance(value, (list, tuple)):
return all(item in self.candidates for item in value) return all(item in self.candidates for item in value)
else: else:
@ -156,8 +154,7 @@ class Config:
'env', []), 'env', []),
} # type: Dict[str, Tuple] } # type: Dict[str, Tuple]
def __init__(self, *args): def __init__(self, *args) -> None:
# type: (Any) -> None
if len(args) == 4: if len(args) == 4:
# old style arguments: (dirname, filename, overrides, tags) # old style arguments: (dirname, filename, overrides, tags)
warnings.warn('The argument of Config() class has been changed. ' warnings.warn('The argument of Config() class has been changed. '
@ -190,27 +187,23 @@ class Config:
self.extensions = config.get('extensions', []) # type: List[str] self.extensions = config.get('extensions', []) # type: List[str]
@classmethod @classmethod
def read(cls, confdir, overrides=None, tags=None): def read(cls, confdir: str, overrides: Dict = None, tags: Tags = None) -> "Config":
# type: (str, Dict, Tags) -> Config
"""Create a Config object from configuration file.""" """Create a Config object from configuration file."""
filename = path.join(confdir, CONFIG_FILENAME) filename = path.join(confdir, CONFIG_FILENAME)
namespace = eval_config_file(filename, tags) namespace = eval_config_file(filename, tags)
return cls(namespace, overrides or {}) return cls(namespace, overrides or {})
def check_types(self): def check_types(self) -> None:
# type: () -> None
warnings.warn('Config.check_types() is deprecated. Use check_confval_types() instead.', warnings.warn('Config.check_types() is deprecated. Use check_confval_types() instead.',
RemovedInSphinx30Warning, stacklevel=2) RemovedInSphinx30Warning, stacklevel=2)
check_confval_types(None, self) check_confval_types(None, self)
def check_unicode(self): def check_unicode(self) -> None:
# type: () -> None
warnings.warn('Config.check_unicode() is deprecated. Use check_unicode() instead.', warnings.warn('Config.check_unicode() is deprecated. Use check_unicode() instead.',
RemovedInSphinx30Warning, stacklevel=2) RemovedInSphinx30Warning, stacklevel=2)
check_unicode(self) check_unicode(self)
def convert_overrides(self, name, value): def convert_overrides(self, name: str, value: Any) -> Any:
# type: (str, Any) -> Any
if not isinstance(value, str): if not isinstance(value, str):
return value return value
else: else:
@ -243,8 +236,7 @@ class Config:
else: else:
return value return value
def pre_init_values(self): def pre_init_values(self) -> None:
# type: () -> None
""" """
Initialize some limited config variables before initialize i18n and loading extensions Initialize some limited config variables before initialize i18n and loading extensions
""" """
@ -258,8 +250,7 @@ class Config:
except ValueError as exc: except ValueError as exc:
logger.warning("%s", exc) logger.warning("%s", exc)
def init_values(self): def init_values(self) -> None:
# type: () -> None
config = self._raw_config config = self._raw_config
for valname, value in self.overrides.items(): for valname, value in self.overrides.items():
try: try:
@ -281,8 +272,7 @@ class Config:
if name in self.values: if name in self.values:
self.__dict__[name] = config[name] self.__dict__[name] = config[name]
def __getattr__(self, name): def __getattr__(self, name: str) -> Any:
# type: (str) -> Any
if name.startswith('_'): if name.startswith('_'):
raise AttributeError(name) raise AttributeError(name)
if name not in self.values: if name not in self.values:
@ -292,42 +282,34 @@ class Config:
return default(self) return default(self)
return default return default
def __getitem__(self, name): def __getitem__(self, name: str) -> str:
# type: (str) -> str
return getattr(self, name) return getattr(self, name)
def __setitem__(self, name, value): def __setitem__(self, name: str, value: Any) -> None:
# type: (str, Any) -> None
setattr(self, name, value) setattr(self, name, value)
def __delitem__(self, name): def __delitem__(self, name: str) -> None:
# type: (str) -> None
delattr(self, name) delattr(self, name)
def __contains__(self, name): def __contains__(self, name: str) -> bool:
# type: (str) -> bool
return name in self.values return name in self.values
def __iter__(self): def __iter__(self) -> Generator[ConfigValue, None, None]:
# type: () -> Generator[ConfigValue, None, None]
for name, value in self.values.items(): for name, value in self.values.items():
yield ConfigValue(name, getattr(self, name), value[1]) yield ConfigValue(name, getattr(self, name), value[1])
def add(self, name, default, rebuild, types): def add(self, name: str, default: Any, rebuild: Union[bool, str], types: Any) -> None:
# type: (str, Any, Union[bool, str], Any) -> None
if name in self.values: if name in self.values:
raise ExtensionError(__('Config value %r already present') % name) raise ExtensionError(__('Config value %r already present') % name)
else: else:
self.values[name] = (default, rebuild, types) self.values[name] = (default, rebuild, types)
def filter(self, rebuild): def filter(self, rebuild: Union[str, List[str]]) -> Iterator[ConfigValue]:
# type: (Union[str, List[str]]) -> Iterator[ConfigValue]
if isinstance(rebuild, str): if isinstance(rebuild, str):
rebuild = [rebuild] rebuild = [rebuild]
return (value for value in self if value.rebuild in rebuild) return (value for value in self if value.rebuild in rebuild)
def __getstate__(self): def __getstate__(self) -> Dict:
# type: () -> Dict
"""Obtains serializable data for pickling.""" """Obtains serializable data for pickling."""
# remove potentially pickling-problematic values from config # remove potentially pickling-problematic values from config
__dict__ = {} __dict__ = {}
@ -350,13 +332,11 @@ class Config:
return __dict__ return __dict__
def __setstate__(self, state): def __setstate__(self, state: Dict) -> None:
# type: (Dict) -> None
self.__dict__.update(state) self.__dict__.update(state)
def eval_config_file(filename, tags): def eval_config_file(filename: str, tags: Tags) -> Dict[str, Any]:
# type: (str, Tags) -> Dict[str, Any]
"""Evaluate a config file.""" """Evaluate a config file."""
namespace = {} # type: Dict[str, Any] namespace = {} # type: Dict[str, Any]
namespace['__file__'] = filename namespace['__file__'] = filename
@ -380,8 +360,7 @@ def eval_config_file(filename, tags):
return namespace return namespace
def convert_source_suffix(app, config): def convert_source_suffix(app: "Sphinx", config: Config) -> None:
# type: (Sphinx, Config) -> None
"""This converts old styled source_suffix to new styled one. """This converts old styled source_suffix to new styled one.
* old style: str or list * old style: str or list
@ -406,8 +385,7 @@ def convert_source_suffix(app, config):
"But `%r' is given." % source_suffix)) "But `%r' is given." % source_suffix))
def init_numfig_format(app, config): def init_numfig_format(app: "Sphinx", config: Config) -> None:
# type: (Sphinx, Config) -> None
"""Initialize :confval:`numfig_format`.""" """Initialize :confval:`numfig_format`."""
numfig_format = {'section': _('Section %s'), numfig_format = {'section': _('Section %s'),
'figure': _('Fig. %s'), 'figure': _('Fig. %s'),
@ -419,8 +397,7 @@ def init_numfig_format(app, config):
config.numfig_format = numfig_format # type: ignore config.numfig_format = numfig_format # type: ignore
def correct_copyright_year(app, config): def correct_copyright_year(app: "Sphinx", config: Config) -> None:
# type: (Sphinx, Config) -> None
"""correct values of copyright year that are not coherent with """correct values of copyright year that are not coherent with
the SOURCE_DATE_EPOCH environment variable (if set) the SOURCE_DATE_EPOCH environment variable (if set)
@ -433,8 +410,7 @@ def correct_copyright_year(app, config):
config[k] = copyright_year_re.sub(replace, config[k]) config[k] = copyright_year_re.sub(replace, config[k])
def check_confval_types(app, config): def check_confval_types(app: "Sphinx", config: Config) -> None:
# type: (Sphinx, Config) -> None
"""check all values for deviation from the default value's type, since """check all values for deviation from the default value's type, since
that can result in TypeErrors all over the place NB. that can result in TypeErrors all over the place NB.
""" """
@ -489,8 +465,7 @@ def check_confval_types(app, config):
default=type(default))) default=type(default)))
def check_unicode(config): def check_unicode(config: Config) -> None:
# type: (Config) -> None
"""check all string values for non-ASCII characters in bytestrings, """check all string values for non-ASCII characters in bytestrings,
since that can result in UnicodeErrors all over the place since that can result in UnicodeErrors all over the place
""" """
@ -506,16 +481,15 @@ def check_unicode(config):
'Please use Unicode strings, e.g. %r.'), name, 'Content') 'Please use Unicode strings, e.g. %r.'), name, 'Content')
def check_primary_domain(app, config): def check_primary_domain(app: "Sphinx", config: Config) -> None:
# type: (Sphinx, Config) -> None
primary_domain = config.primary_domain primary_domain = config.primary_domain
if primary_domain and not app.registry.has_domain(primary_domain): if primary_domain and not app.registry.has_domain(primary_domain):
logger.warning(__('primary_domain %r not found, ignored.'), primary_domain) logger.warning(__('primary_domain %r not found, ignored.'), primary_domain)
config.primary_domain = None # type: ignore config.primary_domain = None # type: ignore
def check_master_doc(app, env, added, changed, removed): def check_master_doc(app: "Sphinx", env: "BuildEnvironment", added: Set[str],
# type: (Sphinx, BuildEnvironment, Set[str], Set[str], Set[str]) -> Set[str] changed: Set[str], removed: Set[str]) -> Set[str]:
"""Adjust master_doc to 'contents' to support an old project which does not have """Adjust master_doc to 'contents' to support an old project which does not have
no master_doc setting. no master_doc setting.
""" """
@ -529,8 +503,7 @@ def check_master_doc(app, env, added, changed, removed):
return changed return changed
def setup(app): def setup(app: "Sphinx") -> Dict[str, Any]:
# type: (Sphinx) -> Dict[str, Any]
app.connect('config-inited', convert_source_suffix) app.connect('config-inited', convert_source_suffix)
app.connect('config-inited', init_numfig_format) app.connect('config-inited', init_numfig_format)
app.connect('config-inited', correct_copyright_year) app.connect('config-inited', correct_copyright_year)