cardinal_pythonlib.sphinxtools


Original code copyright (C) 2009-2022 Rudolf Cardinal (rudolf@pobox.com).

This file is part of cardinal_pythonlib.

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


Functions to help with Sphinx, in particular the generation of autodoc files.

Rationale: if you want Sphinx autodoc code to appear as “one module per Sphinx page” (which I normally do), you need one .rst file per module.

class cardinal_pythonlib.sphinxtools.AutodocIndex(index_filename: str, project_root_dir: str, autodoc_rst_root_dir: str, highest_code_dir: str, python_package_root_dir: str | None = None, source_filenames_or_globs: str | Iterable[str] | None = None, index_heading_underline_char: str = '-', source_rst_heading_underline_char: str = '~', title: str = 'Automatic documentation of source code', introductory_rst: str = '', recursive: bool = True, skip_globs: List[str] | None = None, toctree_maxdepth: int = 1, method: AutodocMethod = AutodocMethod.BEST, rst_prefix: str = '', rst_suffix: str = '', source_rst_title_style_python: bool = True, pygments_language_override: Dict[str, str] | None = None)[source]

Class to make an RST file that indexes others.

Example:

import logging
from cardinal_pythonlib.logs import *
from cardinal_pythonlib.sphinxtools import *
main_only_quicksetup_rootlogger(level=logging.INFO)

# Example where one index contains another:

subidx = AutodocIndex(
    index_filename="~/Documents/code/cardinal_pythonlib/docs/source/autodoc/_index2.rst",
    highest_code_dir="~/Documents/code/cardinal_pythonlib",
    project_root_dir="~/Documents/code/cardinal_pythonlib",
    autodoc_rst_root_dir="~/Documents/code/cardinal_pythonlib/docs/source/autodoc",
    source_filenames_or_globs="~/Documents/code/cardinal_pythonlib/docs/*.py",
)
idx = AutodocIndex(
    index_filename="~/Documents/code/cardinal_pythonlib/docs/source/autodoc/_index.rst",
    highest_code_dir="~/Documents/code/cardinal_pythonlib",
    project_root_dir="~/Documents/code/cardinal_pythonlib",
    autodoc_rst_root_dir="~/Documents/code/cardinal_pythonlib/docs/source/autodoc",
    source_filenames_or_globs="~/Documents/code/cardinal_pythonlib/cardinal_pythonlib/*.py",
)
idx.add_index(subidx)
print(idx.index_content())
idx.write_index_and_rst_files(overwrite=True, mock=True)

# Example with a flat index:

flatidx = AutodocIndex(
    index_filename="~/Documents/code/cardinal_pythonlib/docs/source/autodoc/_index.rst",
    highest_code_dir="~/Documents/code/cardinal_pythonlib/cardinal_pythonlib",
    project_root_dir="~/Documents/code/cardinal_pythonlib",
    autodoc_rst_root_dir="~/Documents/code/cardinal_pythonlib/docs/source/autodoc",
    source_filenames_or_globs="~/Documents/code/cardinal_pythonlib/cardinal_pythonlib/*.py",
)
print(flatidx.index_content())
flatidx.write_index_and_rst_files(overwrite=True, mock=True)
Parameters:
  • index_filename – filename of the index .RST (ReStructured Text) file to create

  • project_root_dir – top-level directory for the whole project

  • autodoc_rst_root_dir – directory within which all automatically generated .RST files (each to document a specific source file) will be placed. A directory hierarchy within this directory will be created, reflecting the structure of the code relative to highest_code_dir (q.v.).

  • highest_code_dir – the “lowest” directory such that all code is found within it; the directory structure within autodoc_rst_root_dir is to .RST files what the directory structure is of the source files, relative to highest_code_dir.

  • python_package_root_dir – if your Python modules live in a directory other than project_root_dir, specify it here

  • source_filenames_or_globs – optional string, or list of strings, each describing a file or glob-style file specification; these are the source filenames to create automatic RST` for. If you don’t specify them here, you can use add_source_files(). To add sub-indexes, use add_index() and add_indexes().

  • index_heading_underline_char – the character used to underline the title in the index file

  • source_rst_heading_underline_char – the character used to underline the heading in each of the source files

  • title – title for the index

  • introductory_rst – extra RST for the index, which goes between the title and the table of contents

  • recursive – use glob.glob() in recursive mode?

  • skip_globs – list of file names or file specifications to skip; e.g. ['__init__.py']

  • toctree_maxdepthmaxdepth parameter for the toctree command generated in the index file

  • method – see FileToAutodocument

  • rst_prefix – optional RST content (e.g. copyright comment) to put early on in each of the RST files

  • rst_suffix – optional RST content to put late on in each of the RST files

  • source_rst_title_style_python – make the individual RST files use titles in the style of Python modules, x.y.z, rather than path style (x/y/z); path style will be used for non-Python files in any case.

  • pygments_language_override – if specified, a dictionary mapping file specifications to Pygments languages (for example: a .pro file will be autodetected as Prolog, but you might want to map that to none for Qt project files).

add_index(index: AutodocIndex) None[source]

Add a sub-index file to this index.

Parameters:

index – index file to add, as an instance of AutodocIndex

add_indexes(indexes: List[AutodocIndex]) None[source]

Adds multiple sub-indexes to this index.

Parameters:

indexes – list of sub-indexes

add_source_files(source_filenames_or_globs: str | List[str], method: AutodocMethod | None = None, recursive: bool | None = None, source_rst_title_style_python: bool | None = None, pygments_language_override: Dict[str, str] | None = None) None[source]

Adds source files to the index.

Parameters:
  • source_filenames_or_globs – string containing a filename or a glob, describing the file(s) to be added, or a list of such strings

  • method – optional method to override self.method

  • recursive – use glob.glob() in recursive mode? (If None, the default, uses the version from the constructor.)

  • source_rst_title_style_python – optional to override self.source_rst_title_style_python

  • pygments_language_override – optional to override self.pygments_language_override

get_sorted_source_files(source_filenames_or_globs: str | List[str], recursive: bool = True) List[str][source]

Returns a sorted list of filenames to process, from a filename, a glob string, or a list of filenames/globs.

Parameters:
  • source_filenames_or_globs – filename/glob, or list of them

  • recursive – use glob.glob() in recursive mode?

Returns:

sorted list of files to process

index_content() str[source]

Returns the contents of the index RST file.

index_filename_rel_other_index(other: str) str[source]

Returns the filename of this index, relative to the director of another index. (For inserting a reference to this index into other.)

Parameters:

other – the other index

Returns:

relative filename of our index

property index_filename_rel_project_root: str

Returns the name of the index filename, relative to the project root. Used for labelling the index file.

should_exclude(filename) bool[source]

Should we exclude this file from consideration?

specific_file_rst_filename(source_filename: str) str[source]

Gets the RST filename corresponding to a source filename. See the help for the constructor for more details.

Parameters:

source_filename – source filename within current project

Returns:

RST filename

Note in particular: the way we structure the directories means that we won’t get clashes between files with idential names in two different directories. However, we must also incorporate the original source filename, in particular for C++ where thing.h and thing.cpp must not generate the same RST filename. So we just add .rst.

write_index(overwrite: bool = False, mock: bool = False) None[source]

Writes the index file, if permitted.

Parameters:
  • overwrite – allow existing files to be overwritten?

  • mock – pretend to write, but don’t

write_index_and_rst_files(overwrite: bool = False, mock: bool = False) None[source]

Writes both the individual RST files and the index.

Parameters:
  • overwrite – allow existing files to be overwritten?

  • mock – pretend to write, but don’t

class cardinal_pythonlib.sphinxtools.AutodocMethod(value)[source]

Enum to specify the method of autodocumenting a file.

class cardinal_pythonlib.sphinxtools.FileToAutodocument(source_filename: str, project_root_dir: str, target_rst_filename: str, method: AutodocMethod = AutodocMethod.BEST, python_package_root_dir: str | None = None, source_rst_title_style_python: bool = True, pygments_language_override: Dict[str, str] | None = None)[source]

Class representing a file to document automatically via Sphinx autodoc.

Example:

import logging
from cardinal_pythonlib.logs import *
from cardinal_pythonlib.sphinxtools import *
main_only_quicksetup_rootlogger(level=logging.DEBUG)

f = FileToAutodocument(
    source_filename="~/Documents/code/cardinal_pythonlib/cardinal_pythonlib/sphinxtools.py",
    project_root_dir="~/Documents/code/cardinal_pythonlib",
    target_rst_filename="~/Documents/code/cardinal_pythonlib/docs/source/autodoc/sphinxtools.rst",
)
print(f)
f.source_extension
f.is_python
f.source_filename_rel_project_root
f.rst_dir
f.source_filename_rel_rst_file
f.rst_filename_rel_project_root
f.rst_filename_rel_autodoc_index(
    "~/Documents/code/cardinal_pythonlib/docs/source/autodoc/_index.rst")
f.python_module_name
f.pygments_code_type
print(f.rst_content(prefix=".. Hello!"))
print(f.rst_content(prefix=".. Hello!", method=AutodocMethod.CONTENTS))
f.write_rst(prefix=".. Hello!")
Parameters:
  • source_filename – source file (e.g. Python, C++, XML file) to document

  • project_root_dir – root directory of the whole project

  • target_rst_filename – filenamd of an RST file to write that will document the source file

  • method – instance of AutodocMethod; for example, should we ask Sphinx’s autodoc to read docstrings and build us a pretty page, or just include the contents with syntax highlighting?

  • python_package_root_dir – if your Python modules live in a directory other than project_root_dir, specify it here

  • source_rst_title_style_python – if True and the file is a Python file and method == AutodocMethod.AUTOMODULE, the heading used will be in the style of a Python module, x.y.z. Otherwise, it will be a path (x/y/z).

  • pygments_language_override – if specified, a dictionary mapping file specifications to Pygments languages (for example: a .pro file will be autodetected as Prolog, but you might want to map that to none for Qt project files).

property is_python: bool

Is the source file a Python file?

property pygments_language: str

Returns the code type annotation for Pygments; e.g. python for Python, cpp for C++, etc.

property python_module_name: str

Returns the name of the Python module that this instance refers to, in dotted Python module notation, or a blank string if it doesn’t.

rst_content(prefix: str = '', suffix: str = '', heading_underline_char: str = '=', method: AutodocMethod | None = None) str[source]

Returns the text contents of an RST file that will automatically document our source file.

Parameters:
  • prefix – prefix, e.g. RST copyright comment

  • suffix – suffix, after the part we’re creating

  • heading_underline_char – RST character to use to underline the heading

  • method – optional method to override self.method; see constructor

Returns:

the RST contents

property rst_dir: str

Returns the directory of the target RST file.

rst_filename_rel_autodoc_index(index_filename: str) str[source]

Returns the filename of the target RST file, relative to a specified index file. Used to make the index refer to the RST.

property rst_filename_rel_project_root: str

Returns the filename of the target RST file, relative to the project root directory. Used for labelling the RST file itself.

property source_extension: str

Returns the extension of the source filename.

property source_filename_rel_project_root: str

Returns the name of the source filename, relative to the project root. Used to calculate file titles.

property source_filename_rel_python_root: str

Returns the name of the source filename, relative to the Python package root. Used to calculate the name of Python modules.

property source_filename_rel_rst_file: str

Returns the source filename as seen from the RST filename that we will generate. Used for .. include:: commands.

write_rst(prefix: str = '', suffix: str = '', heading_underline_char: str = '=', method: AutodocMethod | None = None, overwrite: bool = False, mock: bool = False) None[source]

Writes the RST file to our destination RST filename, making any necessary directories.

Parameters:
cardinal_pythonlib.sphinxtools.filename_matches_glob(filename: str, globtext: str) bool[source]

The glob.glob function doesn’t do exclusion very well. We don’t want to have to specify root directories for exclusion patterns. We don’t want to have to trawl a massive set of files to find exclusion files. So let’s implement a glob match.

Parameters:
  • filename – filename

  • globtext – glob

Returns:

does the filename match the glob?

See also:

cardinal_pythonlib.sphinxtools.rst_underline(heading: str, underline_char: str) str[source]

Underlines a heading for RST files.

Parameters:
  • heading – text to underline

  • underline_char – character to use

Returns:

underlined heading, over two lines (without a final terminating newline)

cardinal_pythonlib.sphinxtools.write_if_allowed(filename: str, content: str, overwrite: bool = False, mock: bool = False) None[source]

Writes the contents to a file, if permitted.

Parameters:
  • filename – filename to write

  • content – contents to write

  • overwrite – permit overwrites?

  • mock – pretend to write, but don’t

Raises:

RuntimeError – if file exists but overwriting not permitted