Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional description argument to app.add_config_value #12549

Merged
merged 3 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Deprecated
Features added
--------------

* Add optional ``description`` argument to
:meth:`~sphinx.application.Sphinx.add_config_value`.
Patch by Chris Sewell.
* #11165: Support the `officially recommended`_ ``.jinja`` suffix for template
files.
Patch by James Addison and Adam Turner
Expand Down
14 changes: 10 additions & 4 deletions sphinx/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,9 +527,11 @@ def add_builder(self, builder: type[Builder], override: bool = False) -> None:
"""
self.registry.add_builder(builder, override=override)

# TODO(stephenfin): Describe 'types' parameter
def add_config_value(self, name: str, default: Any, rebuild: _ConfigRebuild,
types: type | Collection[type] | ENUM = ()) -> None:
def add_config_value(
self, name: str, default: Any, rebuild: _ConfigRebuild,
types: type | Collection[type] | ENUM = (),
description: str | None = None,
) -> None:
"""Register a configuration value.

This is necessary for Sphinx to recognize new values and set default
Expand All @@ -550,6 +552,7 @@ def add_config_value(self, name: str, default: Any, rebuild: _ConfigRebuild,
:param types: The type of configuration value. A list of types can be specified. For
example, ``[str]`` is used to describe a configuration that takes string
value.
:param description: A short description of the configuration value.

.. versionchanged:: 0.4
If the *default* value is a callable, it will be called with the
Expand All @@ -561,9 +564,12 @@ def add_config_value(self, name: str, default: Any, rebuild: _ConfigRebuild,
Changed *rebuild* from a simple boolean (equivalent to ``''`` or
``'env'``) to a string. However, booleans are still accepted and
converted internally.

.. versionadded:: 7.4
The *description* parameter.
"""
logger.debug('[app] adding config value: %r', (name, default, rebuild, types))
self.config.add(name, default, rebuild, types)
self.config.add(name, default, rebuild, types, description)

def add_event(self, name: str) -> None:
"""Register an event called *name*.
Expand Down
38 changes: 23 additions & 15 deletions sphinx/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,20 +94,23 @@ def match(self, value: str | list | tuple) -> bool:


_OptValidTypes = Union[tuple[()], tuple[type, ...], frozenset[type], ENUM]
_DescriptionType = Union[str, None]


class _Opt:
__slots__ = 'default', 'rebuild', 'valid_types'
__slots__ = 'default', 'rebuild', 'valid_types', 'description'

default: Any
rebuild: _ConfigRebuild
valid_types: _OptValidTypes
description: _DescriptionType

def __init__(
self,
default: Any,
rebuild: _ConfigRebuild,
valid_types: _OptValidTypes,
description: _DescriptionType = None,
) -> None:
"""Configuration option type for Sphinx.

Expand All @@ -120,52 +123,56 @@ def __init__(
super().__setattr__('default', default)
super().__setattr__('rebuild', rebuild)
super().__setattr__('valid_types', valid_types)
super().__setattr__('description', description)

def __repr__(self) -> str:
return (
f'{self.__class__.__qualname__}('
f'default={self.default!r}, '
f'rebuild={self.rebuild!r}, '
f'valid_types={self.valid_types!r})'
f'valid_types={self.rebuild!r}, '
f'description={self.description!r})'
)

def __eq__(self, other: object) -> bool:
if isinstance(other, _Opt):
self_tpl = (self.default, self.rebuild, self.valid_types)
other_tpl = (other.default, other.rebuild, other.valid_types)
self_tpl = (self.default, self.rebuild, self.valid_types, self.description)
other_tpl = (other.default, other.rebuild, other.valid_types, self.description)
return self_tpl == other_tpl
return NotImplemented

def __lt__(self, other: _Opt) -> bool:
if self.__class__ is other.__class__:
self_tpl = (self.default, self.rebuild, self.valid_types)
other_tpl = (other.default, other.rebuild, other.valid_types)
self_tpl = (self.default, self.rebuild, self.valid_types, self.description)
other_tpl = (other.default, other.rebuild, other.valid_types, self.description)
return self_tpl > other_tpl
return NotImplemented

def __hash__(self) -> int:
return hash((self.default, self.rebuild, self.valid_types))
return hash((self.default, self.rebuild, self.valid_types, self.description))

def __setattr__(self, key: str, value: Any) -> None:
if key in {'default', 'rebuild', 'valid_types'}:
if key in {'default', 'rebuild', 'valid_types', 'description'}:
msg = f'{self.__class__.__name__!r} object does not support assignment to {key!r}'
raise TypeError(msg)
super().__setattr__(key, value)

def __delattr__(self, key: str) -> None:
if key in {'default', 'rebuild', 'valid_types'}:
if key in {'default', 'rebuild', 'valid_types', 'description'}:
msg = f'{self.__class__.__name__!r} object does not support deletion of {key!r}'
raise TypeError(msg)
super().__delattr__(key)

def __getstate__(self) -> tuple[Any, _ConfigRebuild, _OptValidTypes]:
return self.default, self.rebuild, self.valid_types
def __getstate__(self) -> tuple[Any, _ConfigRebuild, _OptValidTypes, _DescriptionType]:
return self.default, self.rebuild, self.valid_types, self.description

def __setstate__(self, state: tuple[Any, _ConfigRebuild, _OptValidTypes]) -> None:
default, rebuild, valid_types = state
def __setstate__(
self, state: tuple[Any, _ConfigRebuild, _OptValidTypes, _DescriptionType]) -> None:
default, rebuild, valid_types, description = state
super().__setattr__('default', default)
super().__setattr__('rebuild', rebuild)
super().__setattr__('valid_types', valid_types)
super().__setattr__('description', description)

def __getitem__(self, item: int | slice) -> Any:
warnings.warn(
Expand Down Expand Up @@ -445,7 +452,8 @@ def __iter__(self) -> Iterator[ConfigValue]:
yield ConfigValue(name, getattr(self, name), opt.rebuild)

def add(self, name: str, default: Any, rebuild: _ConfigRebuild,
types: type | Collection[type] | ENUM) -> None:
types: type | Collection[type] | ENUM,
description: str | None = None) -> None:
if name in self._options:
raise ExtensionError(__('Config value %r already present') % name)

Expand All @@ -455,7 +463,7 @@ def add(self, name: str, default: Any, rebuild: _ConfigRebuild,

# standardise valid_types
valid_types = _validate_valid_types(types)
self._options[name] = _Opt(default, rebuild, valid_types)
self._options[name] = _Opt(default, rebuild, valid_types, description)

def filter(self, rebuild: Set[_ConfigRebuild]) -> Iterator[ConfigValue]:
if isinstance(rebuild, str):
Expand Down