Skip to content

Doctools

Provides tools to assist with generating documentation for SSVC decision points.

Writes the following files for each decision point: - a markdown table that can be used in the decision point documentation - a json example that can be used in the decision point documentation - a markdown file that builds an insert using mkdocs tabs to switch between the markdown description and the json example

Examples

To generate the documentation for the decision points, use the following command:

python -m ssvc.doctools --overwrite --outdir ./tmp/md_out --jsondir ./tmp/json_out`

To regenerate the existing docs, use the following command:

python -m ssvc.doctools --overwrite --outdir docs/_generated/decision_points --jsondir data/json/decision_points

EnsureDirExists

A runtime context that ensures that a directory exists or creates it otherwise.

Example:

with EnsureDirExists(dir):
    assert os.path.exists(dir)
Source code in src/ssvc/doctools.py
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
class EnsureDirExists:
    """
    A runtime context that ensures that a directory exists or creates it otherwise.

    Example:

        with EnsureDirExists(dir):
            assert os.path.exists(dir)
    """

    def __init__(self, dir: str):
        """
        Create a new EnsureDirExists context.

        Args:
            dir (str): The directory to ensure exists.

        Returns:
            EnsureDirExists: The new EnsureDirExists context.
        """
        self.dir = dir

    def __enter__(self):
        os.makedirs(self.dir, exist_ok=True)

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass

__init__(dir)

Create a new EnsureDirExists context.

Parameters:

Name Type Description Default
dir str

The directory to ensure exists.

required

Returns:

Name Type Description
EnsureDirExists

The new EnsureDirExists context.

Source code in src/ssvc/doctools.py
110
111
112
113
114
115
116
117
118
119
120
def __init__(self, dir: str):
    """
    Create a new EnsureDirExists context.

    Args:
        dir (str): The directory to ensure exists.

    Returns:
        EnsureDirExists: The new EnsureDirExists context.
    """
    self.dir = dir

dump_decision_point(jsondir, outdir, dp, overwrite)

Generate the markdown table, json example, and markdown table file for a decision point.

Parameters:

Name Type Description Default
jsondir str

The directory to write the json example to.

required
outdir str

The directory to write the markdown table file to.

required
dp SsvcDecisionPoint

The decision point to generate documentation for.

required
overwrite bool

Whether to overwrite existing files.

required

Returns:

Name Type Description
dict dict

A dictionary with the following keys: - include_file: The path to the markdown table file. - symlink: The path to the symlink that points to the markdown table file. - json_file: The path to the json example file.

Source code in src/ssvc/doctools.py
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
def dump_decision_point(
    jsondir: str, outdir: str, dp: SsvcDecisionPoint, overwrite: bool
) -> dict:
    """
    Generate the markdown table, json example, and markdown table file for a decision point.

    Args:
        jsondir (str): The directory to write the json example to.
        outdir (str): The directory to write the markdown table file to.
        dp (SsvcDecisionPoint): The decision point to generate documentation for.
        overwrite (bool): Whether to overwrite existing files.

    Returns:
        dict: A dictionary with the following keys:
            - include_file: The path to the markdown table file.
            - symlink: The path to the symlink that points to the markdown table file.
            - json_file: The path to the json example file.
    """
    # - generate markdown table
    # make dp.name safe for use in a filename
    basename = _filename_friendly(dp.name) + f"_{_filename_friendly(dp.version)}"
    # - generate json example
    json_file = dump_json(basename, dp, jsondir, overwrite)

    # - generate markdown table file
    r = dump_markdown(basename, dp, json_file, outdir, overwrite)
    r["json_file"] = json_file
    return r

dump_json(basename, dp, jsondir, overwrite)

Generate the json example for a decision point.

Parameters:

Name Type Description Default
basename str

The basename of the json example file.

required
dp SsvcDecisionPoint

The decision point to generate documentation for.

required
jsondir str

The directory to write the json example to.

required
overwrite bool

Whether to overwrite existing files.

required

Returns:

Name Type Description
str str

The path to the json example file.

Source code in src/ssvc/doctools.py
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
def dump_json(
    basename: str, dp: SsvcDecisionPoint, jsondir: str, overwrite: bool
) -> str:
    """
    Generate the json example for a decision point.

    Args:
        basename (str): The basename of the json example file.
        dp (SsvcDecisionPoint): The decision point to generate documentation for.
        jsondir (str): The directory to write the json example to.
        overwrite (bool): Whether to overwrite existing files.

    Returns:
        str: The path to the json example file.
    """
    json_file = f"{jsondir}/{basename}.json"
    if overwrite:
        remove_if_exists(json_file)
    with EnsureDirExists(jsondir):
        try:
            with open(json_file, "x") as f:
                f.write(dp.to_json(indent=2))
        except FileExistsError:
            logger.warning(
                f"File {json_file} already exists, use --overwrite to replace"
            )
    return json_file

dump_markdown(basename, dp, json_file, outdir, overwrite)

Generate the markdown table file for a decision point.

Parameters:

Name Type Description Default
basename str

The basename of the markdown table file.

required
dp SsvcDecisionPoint

The decision point to generate documentation for.

required
json_file str

The path to the json example file.

required
outdir str

The directory to write the markdown table file to.

required
overwrite bool

Whether to overwrite existing files.

required

Returns:

Name Type Description
dict dict

A dictionary with the following keys: - include_file: The path to the markdown table file. - symlink: The path to the symlink that points to the markdown table file.

Source code in src/ssvc/doctools.py
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
def dump_markdown(
    basename: str, dp: SsvcDecisionPoint, json_file: str, outdir: str, overwrite: bool
) -> dict:
    """
    Generate the markdown table file for a decision point.

    Args:
        basename (str): The basename of the markdown table file.
        dp (SsvcDecisionPoint): The decision point to generate documentation for.
        json_file (str): The path to the json example file.
        outdir (str): The directory to write the markdown table file to.
        overwrite (bool): Whether to overwrite existing files.

    Returns:
        dict: A dictionary with the following keys:
            - include_file: The path to the markdown table file.
            - symlink: The path to the symlink that points to the markdown table file.
    """
    include_file = f"{outdir}/{basename}.md"

    relative_json_file = os.path.relpath(json_file, outdir)

    if overwrite:
        remove_if_exists(include_file)
    with EnsureDirExists(outdir):
        try:
            with open(include_file, "x") as f:
                formatted_template = MD_INCLUDE_TEMPLATE.format(
                    dp=dp,
                    json_file=relative_json_file,
                    table=(to_markdown_table(dp)),
                )
                f.write(formatted_template)
        except FileExistsError:
            logger.warning(
                f"File {include_file} already exists, use --overwrite to replace"
            )

    # update the symlink
    # because we don't want to have to edit each markdown file every time something changes
    symlink = f"{outdir}/{_filename_friendly(dp.name)}.md"
    remove_if_exists(symlink)
    relative_md_file = os.path.relpath(include_file, outdir)
    os.symlink(relative_md_file, symlink)

    result = {
        "include_file": include_file,
        "symlink": symlink,
    }

    return result

to_markdown_table(dp)

Generate a markdown table for a decision point.

Parameters:

Name Type Description Default
dp SsvcDecisionPoint

The decision point to generate a markdown table for.

required

Returns:

Name Type Description
str str

The markdown table.

Source code in src/ssvc/doctools.py
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def to_markdown_table(dp: SsvcDecisionPoint) -> str:
    """
    Generate a markdown table for a decision point.

    Args:
        dp (SsvcDecisionPoint): The decision point to generate a markdown table for.

    Returns:
        str: The markdown table.
    """
    rows = []
    # prepend the header
    rows.append(f"    {dp.description}")
    rows.append("")
    indent = " " * 4
    rows.append(f"{indent}| Value | Definition |")
    rows.append(f"{indent}|:-----|:-----------|")

    # add a row for each value
    for value in dp.values:
        rows.append(indent + MD_TABLE_ROW_TEMPLATE.format(value=value))

    return "\n".join(rows)