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.app 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 ClassVar[str]

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

Source code in doc2dash/parsers/types.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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 doc2dash/parsers/types.py
63
64
65
66
67
68
69
70
71
72
73
@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 doc2dash/parsers/types.py
52
53
54
55
56
57
58
59
60
61
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 doc2dash/parsers/types.py
75
76
77
78
79
80
81
82
83
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
Iterator[Patcher]

A patch function.

Source code in doc2dash/parsers/types.py
85
86
87
88
89
90
91
92
93
94
95
96
@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 doc2dash/parsers/types.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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 doc2dash/parsers/types.py
105
106
107
108
109
110
111
112
113
114
115
116
117
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 doc2dash/parsers/types.py
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
@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 class-attribute

The full display name of the index entry.

type: EntryType class-attribute

The type of the entry.

path: str class-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 doc2dash/parsers/types.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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.