PKbW((sphinx_pyproject/__init__.py#!/usr/bin/env python3 # # __init__.py """ Move some of your Sphinx configuration into ``pyproject.toml``. """ # # Copyright © 2021 Dominic Davis-Foster # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. # # stdlib import re from typing import Any, Dict, Iterator, List, Mapping, MutableMapping, Optional # 3rd party import dom_toml from dom_toml.decoder import TomlPureDecoder from dom_toml.parser import TOML_TYPES, AbstractConfigParser, BadConfigError from domdf_python_tools.paths import PathPlus from domdf_python_tools.typing import PathLike from domdf_python_tools.words import word_join __author__: str = "Dominic Davis-Foster" __copyright__: str = "2021 Dominic Davis-Foster" __license__: str = "MIT License" __version__: str = "0.3.0" __email__: str = "dominic@davis-foster.co.uk" __all__ = ["SphinxConfig", "ProjectParser", "PoetryProjectParser"] class SphinxConfig(Mapping[str, Any]): """ Read the Sphinx configuration from ``pyproject.toml``. :param pyproject_file: The path to the ``pyproject.toml`` file. :param globalns: The global namespace of the ``conf.py`` file. The variables parsed from the ``[tool.sphinx-pyproject]`` table will be added to this namespace. By default, or if explicitly :py:obj:`None`, this does not happen. :no-default globalns: :param style: Either ``pep621`` (default), or ``poetry`` to read configuration from the ``[tool.poetry]`` table. :no-default style: :param config_overrides: Custom configuration overrides. This parameter can be used to dynamically update values from ``pyproject.toml``. This can be used to patch dynamic values like ``version``. By default, or if explicitly :py:obj:`None`, no config updates are performed. :no-default config_overrides: .. versionchanged:: 0.2.0 Added the ``style`` keyword argument. .. versionchanged:: 0.3.0 Added the ``config_overrides`` keyword argument. .. autosummary-widths:: 1/4 """ name: str """ The value of the :pep621:`project.name ` key in the :pep:`621` metadata. Underscores are replaced by dashes but :pep:`508` normalization is *not* applied. The recommendation is to assign this to the `project `_ variable in ``conf.py``: .. code-block:: python from sphinx_pyproject import SphinxConfig config = SphinxConfig() project = config.name """ version: str """ The value of the :pep621:`project.version ` key in the :pep:`621` metadata. Converted to a string if the value was a number in the ``pyproject.toml`` file. """ description: str """ The value of the :pep621:`project.description ` key in the :pep:`621` metadata. """ author: str """ A string giving the names of the authors. This is parsed from the :pep621:`project.authors ` key in the :pep:`621` metadata, or the :pep621:`project.maintainers ` key as a fallback. The names are joined together, e.g.: .. code-block:: TOML # pyproject.toml [[project.authors]] name = "Dominic Davis-Foster" [[project.authors]] name = "Joe Bloggs" [[project.authors]] name = "Jane Doe" .. code-block:: python >>> SphinxConfig("pyproject.toml").author 'Dominic Davis-Foster, Joe Bloggs and Jane Doe' """ def __init__( self, pyproject_file: PathLike = "../pyproject.toml", *, globalns: Optional[MutableMapping] = None, style: str = "pep621", config_overrides: Optional[MutableMapping] = None, ): pyproject_file = PathPlus(pyproject_file).abspath() config = dom_toml.load(pyproject_file, decoder=TomlPureDecoder) parser_cls = project_parser_styles.get(style) if parser_cls is None: styles = ", ".join(project_parser_styles) raise ValueError(f"'style' argument must be one of: {styles}") namespace = parser_cls.get_namespace(pyproject_file, config) pep621_config = parser_cls().parse(namespace) for key, value in (config_overrides or {}).items(): pep621_config[key] = value for key in ("name", "version", "description"): if key not in pep621_config: raise BadConfigError( f"Either {key!r} was not declared in the 'project' table " f"or it was marked as 'dynamic', which is unsupported by 'sphinx-pyproject'." ) if "author" not in pep621_config: raise BadConfigError( f"Either 'authors/maintainers' was not declared in the 'project' table " f"or it was marked as 'dynamic', which is unsupported by 'sphinx-pyproject'." ) self.name = pep621_config["name"] self.version = pep621_config["version"] self.description = pep621_config["description"] self.author = pep621_config["author"] self._freeform = config.get("tool", {}).get("sphinx-pyproject", {}) if globalns is not None: globalns.update(pep621_config) globalns.update(self._freeform) def __getitem__(self, item: str) -> Any: """ Returns the value of the given key in the ``tool.sphinx-pyproject`` table. :param item: """ return self._freeform[item] def __len__(self) -> int: """ Returns the number of keys in the ``tool.sphinx-pyproject`` table. """ return len(self._freeform) def __iter__(self) -> Iterator[str]: """ Returns an iterator over the keys in the ``tool.sphinx-pyproject`` table. """ yield from self._freeform class ProjectParser(AbstractConfigParser): """ Parser for :pep:`621` metadata from ``pyproject.toml``. .. autosummary-widths:: 7/16 """ @staticmethod def get_namespace(filename: PathPlus, config: Dict[str, TOML_TYPES]) -> Dict[str, TOML_TYPES]: """ Returns the ``[project]`` table in a ``project.toml`` file. :param filename: The filename the TOML data was read from. Used in error messages. :param config: The data from the TOML file. .. versionadded:: 0.2.0 """ if "project" not in config: raise BadConfigError(f"No 'project' table found in {filename.as_posix()}") return config["project"] def parse_name(self, config: Dict[str, TOML_TYPES]) -> str: """ Parse the :pep621:`name` key. :param config: The unparsed TOML config for the ``[project]`` table. """ name = config["name"] self.assert_type(name, str, ["project", "name"]) return str(name).replace('_', '-') def parse_version(self, config: Dict[str, TOML_TYPES]) -> str: """ Parse the :pep621:`version` key. :param config: The unparsed TOML config for the ``[project]`` table. """ version = config["version"] self.assert_type(version, (str, int), ["project", "version"]) return str(version) def parse_description(self, config: Dict[str, TOML_TYPES]) -> str: """ Parse the :pep621:`description` key. :param config: The unparsed TOML config for the ``[project]`` table. """ description = config["description"] self.assert_type(description, str, ["project", "description"]) return description @staticmethod def parse_author(config: Dict[str, TOML_TYPES]) -> str: """ Parse the :pep621:`authors/maintainers` key. :param config: The unparsed TOML config for the ``[project]`` table. """ all_authors: List[Optional[str]] = [] for idx, author in enumerate(config["author"]): name = author.get("name", None) if name is not None and ',' in name: raise BadConfigError(f"The 'project.authors[{idx}].name' key cannot contain commas.") all_authors.append(name) all_authors = list(filter(bool, all_authors)) if not all_authors: raise BadConfigError(f"The 'project.authors' key cannot be empty.") return word_join(all_authors) # type: ignore @property def keys(self) -> List[str]: """ The keys to parse from the TOML file. """ return [ "name", "version", "description", "author", ] def parse( self, config: Dict[str, TOML_TYPES], set_defaults: bool = False, ) -> Dict[str, TOML_TYPES]: """ Parse the TOML configuration. :param config: :param set_defaults: Has no effect in this class. """ if "authors" in config: config["author"] = config.pop("authors") elif "maintainers" in config: config["author"] = config.pop("maintainers") return super().parse(config) class PoetryProjectParser(ProjectParser): """ Parser for poetry metadata from ``pyproject.toml``. .. versionadded:: 0.2.0 """ @staticmethod def get_namespace(filename: PathPlus, config: Dict[str, TOML_TYPES]) -> Dict[str, TOML_TYPES]: """ Returns the ``[tool.poetry]`` table in a ``project.toml`` file. :param filename: The filename the TOML data was read from. Used in error messages. :param config: The data from the TOML file. """ result = config.get("tool", {}).get("poetry") if result is None: raise BadConfigError(f"No 'tool.poetry' table found in {filename.as_posix()}") return result @staticmethod def parse_author(config: Dict[str, TOML_TYPES]) -> str: """ Parse poetry's authors key. :param config: The unparsed TOML config for the ``[tool.poetry]`` table. """ pep621_style_authors: List[Dict[str, str]] = [] for author in config["author"]: match = re.match(r"(?P.*)<(?P.*)>", author) if match: name = match.group("name").strip() email = match.group("email").strip() pep621_style_authors.append({"name": name, "email": email}) return ProjectParser.parse_author({"author": pep621_style_authors}) project_parser_styles = { "pep621": ProjectParser, "poetry": PoetryProjectParser, } PKbWsphinx_pyproject/py.typedPKsWl}(((sphinx_pyproject-0.3.0.dist-info/LICENSECopyright (c) 2021 Dominic Davis-Foster Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PKsW _[&[&)sphinx_pyproject-0.3.0.dist-info/METADATAMetadata-Version: 2.1 Name: sphinx-pyproject Version: 0.3.0 Summary: Move some of your Sphinx configuration into pyproject.toml Author-email: Dominic Davis-Foster License: MIT Keywords: documentation,pep621,sphinx,toml Home-page: https://github.com/sphinx-toolbox/sphinx-pyproject Project-URL: Issue Tracker, https://github.com/sphinx-toolbox/sphinx-pyproject/issues Project-URL: Source Code, https://github.com/sphinx-toolbox/sphinx-pyproject Project-URL: Documentation, https://sphinx-pyproject.readthedocs.io/en/latest Platform: Windows Platform: macOS Platform: Linux Classifier: Development Status :: 4 - Beta Classifier: Framework :: Sphinx Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Documentation Classifier: Topic :: Documentation :: Sphinx Classifier: Topic :: Software Development :: Documentation Classifier: Topic :: Utilities Classifier: Typing :: Typed Requires-Python: >=3.6 Requires-Dist: dom-toml>=0.3.0 Requires-Dist: domdf-python-tools>=2.7.0 Description-Content-Type: text/x-rst ################# sphinx-pyproject ################# .. start short_desc **Move some of your Sphinx configuration into pyproject.toml** .. end short_desc .. start shields .. list-table:: :stub-columns: 1 :widths: 10 90 * - Docs - |docs| |docs_check| * - Tests - |actions_linux| |actions_windows| |actions_macos| |coveralls| * - PyPI - |pypi-version| |supported-versions| |supported-implementations| |wheel| * - Anaconda - |conda-version| |conda-platform| * - Activity - |commits-latest| |commits-since| |maintained| |pypi-downloads| * - QA - |codefactor| |actions_flake8| |actions_mypy| * - Other - |license| |language| |requires| .. |docs| image:: https://img.shields.io/readthedocs/sphinx-pyproject/latest?logo=read-the-docs :target: https://sphinx-pyproject.readthedocs.io/en/latest :alt: Documentation Build Status .. |docs_check| image:: https://github.com/sphinx-toolbox/sphinx-pyproject/workflows/Docs%20Check/badge.svg :target: https://github.com/sphinx-toolbox/sphinx-pyproject/actions?query=workflow%3A%22Docs+Check%22 :alt: Docs Check Status .. |actions_linux| image:: https://github.com/sphinx-toolbox/sphinx-pyproject/workflows/Linux/badge.svg :target: https://github.com/sphinx-toolbox/sphinx-pyproject/actions?query=workflow%3A%22Linux%22 :alt: Linux Test Status .. |actions_windows| image:: https://github.com/sphinx-toolbox/sphinx-pyproject/workflows/Windows/badge.svg :target: https://github.com/sphinx-toolbox/sphinx-pyproject/actions?query=workflow%3A%22Windows%22 :alt: Windows Test Status .. |actions_macos| image:: https://github.com/sphinx-toolbox/sphinx-pyproject/workflows/macOS/badge.svg :target: https://github.com/sphinx-toolbox/sphinx-pyproject/actions?query=workflow%3A%22macOS%22 :alt: macOS Test Status .. |actions_flake8| image:: https://github.com/sphinx-toolbox/sphinx-pyproject/workflows/Flake8/badge.svg :target: https://github.com/sphinx-toolbox/sphinx-pyproject/actions?query=workflow%3A%22Flake8%22 :alt: Flake8 Status .. |actions_mypy| image:: https://github.com/sphinx-toolbox/sphinx-pyproject/workflows/mypy/badge.svg :target: https://github.com/sphinx-toolbox/sphinx-pyproject/actions?query=workflow%3A%22mypy%22 :alt: mypy status .. |requires| image:: https://dependency-dash.repo-helper.uk/github/sphinx-toolbox/sphinx-pyproject/badge.svg :target: https://dependency-dash.repo-helper.uk/github/sphinx-toolbox/sphinx-pyproject/ :alt: Requirements Status .. |coveralls| image:: https://img.shields.io/coveralls/github/sphinx-toolbox/sphinx-pyproject/master?logo=coveralls :target: https://coveralls.io/github/sphinx-toolbox/sphinx-pyproject?branch=master :alt: Coverage .. |codefactor| image:: https://img.shields.io/codefactor/grade/github/sphinx-toolbox/sphinx-pyproject?logo=codefactor :target: https://www.codefactor.io/repository/github/sphinx-toolbox/sphinx-pyproject :alt: CodeFactor Grade .. |pypi-version| image:: https://img.shields.io/pypi/v/sphinx-pyproject :target: https://pypi.org/project/sphinx-pyproject/ :alt: PyPI - Package Version .. |supported-versions| image:: https://img.shields.io/pypi/pyversions/sphinx-pyproject?logo=python&logoColor=white :target: https://pypi.org/project/sphinx-pyproject/ :alt: PyPI - Supported Python Versions .. |supported-implementations| image:: https://img.shields.io/pypi/implementation/sphinx-pyproject :target: https://pypi.org/project/sphinx-pyproject/ :alt: PyPI - Supported Implementations .. |wheel| image:: https://img.shields.io/pypi/wheel/sphinx-pyproject :target: https://pypi.org/project/sphinx-pyproject/ :alt: PyPI - Wheel .. |conda-version| image:: https://img.shields.io/conda/v/domdfcoding/sphinx-pyproject?logo=anaconda :target: https://anaconda.org/domdfcoding/sphinx-pyproject :alt: Conda - Package Version .. |conda-platform| image:: https://img.shields.io/conda/pn/domdfcoding/sphinx-pyproject?label=conda%7Cplatform :target: https://anaconda.org/domdfcoding/sphinx-pyproject :alt: Conda - Platform .. |license| image:: https://img.shields.io/github/license/sphinx-toolbox/sphinx-pyproject :target: https://github.com/sphinx-toolbox/sphinx-pyproject/blob/master/LICENSE :alt: License .. |language| image:: https://img.shields.io/github/languages/top/sphinx-toolbox/sphinx-pyproject :alt: GitHub top language .. |commits-since| image:: https://img.shields.io/github/commits-since/sphinx-toolbox/sphinx-pyproject/v0.3.0 :target: https://github.com/sphinx-toolbox/sphinx-pyproject/pulse :alt: GitHub commits since tagged version .. |commits-latest| image:: https://img.shields.io/github/last-commit/sphinx-toolbox/sphinx-pyproject :target: https://github.com/sphinx-toolbox/sphinx-pyproject/commit/master :alt: GitHub last commit .. |maintained| image:: https://img.shields.io/maintenance/yes/2023 :alt: Maintenance .. |pypi-downloads| image:: https://img.shields.io/pypi/dm/sphinx-pyproject :target: https://pypi.org/project/sphinx-pyproject/ :alt: PyPI - Downloads .. end shields Installation -------------- .. start installation ``sphinx-pyproject`` can be installed from PyPI or Anaconda. To install with ``pip``: .. code-block:: bash $ python -m pip install sphinx-pyproject To install with ``conda``: * First add the required channels .. code-block:: bash $ conda config --add channels https://conda.anaconda.org/conda-forge $ conda config --add channels https://conda.anaconda.org/domdfcoding * Then install .. code-block:: bash $ conda install sphinx-pyproject .. end installation Usage ------- The ``SphinxConfig`` class will load the configuration from ``pyproject.toml``. By passing ``globalns=globals()`` to the class constructor, the keys parsed from the ``pyproject.toml`` file will be added to the global namespace of the ``conf.py`` file. For example: .. code-block:: python3 # conf.py from sphinx_pyproject import SphinxConfig config = SphinxConfig("../pyproject.toml", globalns=globals()) author # This name *looks* to be undefined, but it isn't. The ``SphinxConfig`` class also provides a ``collections.abc.Mapping`` interface. If you are going to override or modify one of the configuration values after parsing it, the recommended approach is to explicitly assign the name: .. code-block:: python extensions = config["extensions"] extensions.append("sphinx.ext.autodoc") This will prevent warnings from linters etc., but is not necessary for Sphinx to see the configuration. Additionally the ``SphinxConfig`` class takes an optional parameter ``config_overrides`` that can be used to dynamically update values from ``pyproject.toml``. This can be helpful for setting dynamic values like ``version``. .. code-block:: python3 # conf.py from sphinx_pyproject import SphinxConfig from myproject import __version__ as myproject_version config = SphinxConfig("../pyproject.toml", globalns=globals(), config_overrides = {"version": myproject_version}) Configuration ^^^^^^^^^^^^^^^ ``sphinx-pyproject`` parses the configuration from the ``[project]`` and ``[tool.sphinx-pyproject]`` tables in ``pyproject.toml``. The ``[project]`` table is defined in `PEP 621`_. ``sphinx-pyproject`` only uses the following keys: * name_ – The name of the project. * version_ – The version of the project. * description_ – The summary description of the project. * One of `authors/maintainers`_. The remaining `Sphinx configuration values`_ can be provided in the ``[tool.sphinx-pyproject]`` table. See `this project's pyproject.toml file`_ for an example of this configuration. .. _PEP 621: https://www.python.org/dev/peps/pep-0621/#authors-maintainers .. _name: https://www.python.org/dev/peps/pep-0621/#name .. _version: https://www.python.org/dev/peps/pep-0621/#version .. _description: https://www.python.org/dev/peps/pep-0621/#description .. _authors/maintainers: https://www.python.org/dev/peps/pep-0621/#authors-maintainers .. _Sphinx configuration values: https://www.sphinx-doc.org/en/master/usage/configuration.html .. _this project's pyproject.toml file: https://github.com/sphinx-toolbox/sphinx-pyproject/blob/master/pyproject.toml PKsW7qTT&sphinx_pyproject-0.3.0.dist-info/WHEELWheel-Version: 1.0 Generator: whey (0.0.24) Root-Is-Purelib: true Tag: py3-none-any PKsW1sphinx_pyproject-0.3.0.dist-info/entry_points.txtPKsW VV'sphinx_pyproject-0.3.0.dist-info/RECORDsphinx_pyproject/__init__.py,sha256=ik-WHbl49-SheNlQgw5_pvTBDPoTGKF4uBEPWBbiHnU,10437 sphinx_pyproject/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 sphinx_pyproject-0.3.0.dist-info/LICENSE,sha256=TXanB-tJYmHhByFsynyh-UGwh2VdTVVjbZeFz1utSWc,1064 sphinx_pyproject-0.3.0.dist-info/METADATA,sha256=SirFzuvymnnIruT0NyQUgztfdfEEpMrtVzDRPhfmDlM,9819 sphinx_pyproject-0.3.0.dist-info/WHEEL,sha256=3vSnEhs48RUlSXcCXKCl4DOHs_qqaP2dU3IGkMqN2oI,84 sphinx_pyproject-0.3.0.dist-info/entry_points.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 sphinx_pyproject-0.3.0.dist-info/RECORD,, PKbW((sphinx_pyproject/__init__.pyPKbW(sphinx_pyproject/py.typedPKsWl}(((6)sphinx_pyproject-0.3.0.dist-info/LICENSEPKsW _[&[&)-sphinx_pyproject-0.3.0.dist-info/METADATAPKsW7qTT&FTsphinx_pyproject-0.3.0.dist-info/WHEELPKsW1Tsphinx_pyproject-0.3.0.dist-info/entry_points.txtPKsW VV'-Usphinx_pyproject-0.3.0.dist-info/RECORDPKFW