Skip to content

Writing Custom Parser Plugins

A doc2dash parser plugin has three jobs:

  1. Detect whether it can parse a directory and extract an appropriate name for the docset.
  2. Parse a directory and tell doc2dash about all entries that should be indexed.
  3. Patch files such that Dash can generate per-file tables of contents.

For that, it must implement the Parser protocol:

Parser

Bases: Protocol

A doc2dash documentation parser.

Attributes:

Name Type Description
name str

The name of this parser. Used in user-facing output.

Source code in src/doc2dash/parsers/types.py
class Parser(Protocol):
    """
    A *doc2dash* documentation parser.

    Attributes:
        name: The name of this parser. Used in user-facing output.

    """

    name: ClassVar[str] = NotImplemented

    def __init__(self, source: Path):
        """
        Initialize parser.

        If this parser's `detect()` static method indicates that *source*
        belongs to it, *doc2dash* instantiates it as `parser_type(path)`.

        Args:
           source: The path to the documentation that will be parsed.
        """

    @staticmethod
    def detect(path: Path) -> str | None:
        """
        Check whether *path* can be parsed by this parser.

        Args:
            path: The path to the documentation.

        Returns:
            The name of the documentation or `None` if it's not ours.
        """

    def parse(self) -> Generator[ParserEntry, None, None]:
        """
        Parse the path that this parser was initialized with and `yield` a
        [`ParserEntry`][doc2dash.parsers.types.ParserEntry] for each
        entry it finds.

        Returns:
            A generator that yields `ParserEntry`s.
        """

    @contextmanager
    def make_patcher_for_file(self, path: Path) -> Iterator[Patcher]:
        """
        A context manager that prepares for patching *path* and returns a
        `Patcher` callable.

        Args:
            path: path to file to patch

        Yields:
            A patch function.
        """

detect(path) staticmethod

Check whether path can be parsed by this parser.

Parameters:

Name Type Description Default
path Path

The path to the documentation.

required

Returns:

Type Description
str | None

The name of the documentation or None if it’s not ours.

Source code in src/doc2dash/parsers/types.py
@staticmethod
def detect(path: Path) -> str | None:
    """
    Check whether *path* can be parsed by this parser.

    Args:
        path: The path to the documentation.

    Returns:
        The name of the documentation or `None` if it's not ours.
    """

__init__(source)

Initialize parser.

If this parser’s detect() static method indicates that source belongs to it, doc2dash instantiates it as parser_type(path).

Parameters:

Name Type Description Default
source Path

The path to the documentation that will be parsed.

required
Source code in src/doc2dash/parsers/types.py
def __init__(self, source: Path):
    """
    Initialize parser.

    If this parser's `detect()` static method indicates that *source*
    belongs to it, *doc2dash* instantiates it as `parser_type(path)`.

    Args:
       source: The path to the documentation that will be parsed.
    """

parse()

Parse the path that this parser was initialized with and yield a ParserEntry for each entry it finds.

Returns:

Type Description
Generator[ParserEntry, None, None]

A generator that yields ParserEntrys.

Source code in src/doc2dash/parsers/types.py
def parse(self) -> Generator[ParserEntry, None, None]:
    """
    Parse the path that this parser was initialized with and `yield` a
    [`ParserEntry`][doc2dash.parsers.types.ParserEntry] for each
    entry it finds.

    Returns:
        A generator that yields `ParserEntry`s.
    """

make_patcher_for_file(path)

A context manager that prepares for patching path and returns a Patcher callable.

Parameters:

Name Type Description Default
path Path

path to file to patch

required

Yields:

Type Description
Patcher

A patch function.

Source code in src/doc2dash/parsers/types.py
@contextmanager
def make_patcher_for_file(self, path: Path) -> Iterator[Patcher]:
    """
    A context manager that prepares for patching *path* and returns a
    `Patcher` callable.

    Args:
        path: path to file to patch

    Yields:
        A patch function.
    """

Patcher

Bases: Protocol

A callable that patches the file that it belongs to and returns whether it did.

Source code in src/doc2dash/parsers/types.py
class Patcher(Protocol):
    """
    A callable that patches the file that it belongs to and returns whether it
    did.
    """

    def __call__(
        self, name: str, type: EntryType, anchor: str, ref: str
    ) -> bool:
        """
        Args:
            name: name of the entry
            type: the type of the entry
            anchor: the place to add *ref*
            ref: the reference to add before *anchor*

        Returns:
            Whether it found the anchor and did anything.
        """

__call__(name, type, anchor, ref)

Parameters:

Name Type Description Default
name str

name of the entry

required
type EntryType

the type of the entry

required
anchor str

the place to add ref

required
ref str

the reference to add before anchor

required

Returns:

Type Description
bool

Whether it found the anchor and did anything.

Source code in src/doc2dash/parsers/types.py
def __call__(
    self, name: str, type: EntryType, anchor: str, ref: str
) -> bool:
    """
    Args:
        name: name of the entry
        type: the type of the entry
        anchor: the place to add *ref*
        ref: the reference to add before *anchor*

    Returns:
        Whether it found the anchor and did anything.
    """

ParserEntry

A symbol to be indexed, as found by Parser’s parse() method.

Source code in src/doc2dash/parsers/types.py
@attrs.frozen
class ParserEntry:
    """
    A symbol to be indexed, as found by `Parser`'s `parse()` method.
    """

    name: str
    """
    The full display name of the index entry.
    """
    type: EntryType
    """
    The type of the entry.
    """
    path: str
    """
    Full path including anchor (`#`). E.g. `api.rst#print`
    """

    def as_tuple(self) -> tuple[str, str, str]:
        """
        Return a tuple of the data for SQL generation.
        """
        return self.name, self.type.value, self.path

name: str instance-attribute

The full display name of the index entry.

type: EntryType instance-attribute

The type of the entry.

path: str instance-attribute

Full path including anchor (#). E.g. api.rst#print

EntryType

Bases: Enum

Possible types for entries.

Pick from https://kapeli.com/docsets#supportedentrytypes.

Source code in src/doc2dash/parsers/types.py
class EntryType(Enum):
    """
    Possible types for entries.

    Pick from <https://kapeli.com/docsets#supportedentrytypes>.
    """

    ATTRIBUTE = "Attribute"
    CLASS = "Class"
    CONSTANT = "Constant"
    ENV = "Environment"
    EXCEPTION = "Exception"
    FUNCTION = "Function"
    GUIDE = "Guide"
    INTERFACE = "Interface"
    MACRO = "Macro"
    METHOD = "Method"
    OPCODE = "Operator"
    OPTION = "Option"
    PACKAGE = "Module"
    PROPERTY = "Property"
    PROTOCOL = "Protocol"
    SECTION = "Section"
    SETTING = "Setting"
    TYPE = "Type"
    VALUE = "Value"
    VARIABLE = "Variable"
    WORD = "Word"

To use your custom parser, you have to invoke doc2dash with the --parser option and specify the importable path to it.

Example

Often, it’s the easiest to get started by looking at existing parsers. Conveniently, doc2dash ships one:

The intersphinx parser uses a machine-readable format to extract the necessary metadata.