File: conf.py

package info (click to toggle)
sphinx-needs 5.1.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 11,924 kB
  • sloc: python: 21,132; javascript: 187; makefile: 89; sh: 29; xml: 10
file content (437 lines) | stat: -rw-r--r-- 14,292 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
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
39
40
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
97
98
99
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
127
128
129
130
131
132
133
134
135
136
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
165
166
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
218
219
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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
"""sphinx-needs documentation build configuration file"""

import datetime
import os
from pathlib import Path
from typing import Any

from sphinx_needs import __version__

# -- General configuration ------------------------------------------------

# General information about the project.
project = "Sphinx-Needs"
now = datetime.datetime.now()
copyright = f"2017-{now.year}, team useblocks"
author = "team useblocks"

master_doc = "index"
language = "en"

version = release = __version__

# set theme based on environment variable or file
DOCS_THEME = os.getenv("DOCS_THEME", "alabaster")
if (_path := Path(__file__).parent.joinpath("DOCS_THEME")).is_file():
    DOCS_THEME = _path.read_text().strip()

extensions = [
    "sphinx.ext.intersphinx",
    "sphinx.ext.extlinks",
    "sphinxcontrib.plantuml",
    "sphinx_needs",
    "sphinx.ext.autodoc",
    "sphinx_copybutton",
    "sphinxcontrib.programoutput",
    "sphinx_design",
    "sphinx.ext.duration",
    "sphinx.ext.todo",
]
if DOCS_THEME == "sphinx_immaterial":
    extensions.append("sphinx_immaterial")

suppress_warnings = ["needs.link_outgoing"]

nitpicky = True
nitpick_ignore = [
    ("py:class", "docutils.nodes.Node"),
    ("py:class", "docutils.parsers.rst.states.RSTState"),
    ("py:class", "docutils.statemachine.StringList"),
    ("py:class", "sphinx_needs.debug.T"),
    ("py:class", "sphinx_needs.views._LazyIndexes"),
    ("py:class", "sphinx_needs.config.NeedsSphinxConfig"),
]

rst_epilog = """

.. |br| raw:: html

   <br>

"""

extlinks = {
    "pr": ("https://github.com/useblocks/sphinx-needs/pull/%s", "PR #%s"),
    "issue": ("https://github.com/useblocks/sphinx-needs/issues/%s", "issue #%s"),
}

#intersphinx_mapping = {
#    "python": ("https://docs.python.org/3.8", None),
#    "sphinx": ("https://www.sphinx-doc.org/en/master", None),
#}

def check_object_path(key, url, path):
    if os.path.isfile(path):
        return {key: (url, path)}
    return {}

intersphinx_mapping = {}
intersphinx_mapping.update(check_object_path('python',
                                            'https://docs.python.org/3.8',
                                             '/usr/share/doc/python3.13/html/objects.inv'))
intersphinx_mapping.update(check_object_path('sphinx',
                                             'https://www.sphinx-doc.org/en/master',
                                             '/usr/share/doc/sphinx-doc/html/objects.inv'))

# smartquotes = False

add_module_names = False  # Used to shorten function name output
autodoc_docstring_signature = (
    True  # Used to read spec. func-defs from docstring (e.g. get rid of self)
)

exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
exclude_patterns += os.getenv("SPHINX_EXCLUDE", "").split(",")

sd_custom_directives = {
    "dropdown": {
        "inherit": "dropdown",
        "options": {
            "icon": "pencil",
            "class-container": "sn-dropdown-default",
        },
    }
}

graphviz_output_format = "svg"

# -- Options for html builder ----------------------------------------------

html_static_path = ["_static"]
html_css_files = ["_css/shared.css"]
html_favicon = "./_static/sphinx-needs-logo-square-dark.svg"

html_theme = DOCS_THEME

if DOCS_THEME == "alabaster":
    # https://alabaster.readthedocs.io
    html_theme_options = {
        "logo": "sphinx-needs-logo-long-light.svg",
        "description": "",
        "github_type": "star",
        "github_user": "useblocks",
        "github_repo": "sphinx-needs",
    }
elif DOCS_THEME == "furo":
    # https://pradyunsg.me/furo
    html_css_files += ["_css/furo.css"]
    html_theme_options = {
        "sidebar_hide_name": True,
        "top_of_page_buttons": ["view", "edit"],
        "source_repository": "https://github.com/useblocks/sphinx-needs",
        "source_branch": "master",
        "source_directory": "docs/",
        "light_logo": "sphinx-needs-logo-long-light.svg",
        "dark_logo": "sphinx-needs-logo-long-dark.svg",
    }
    templates_path = ["_static/_templates/furo"]
    html_sidebars = {
        "**": [
            "sidebar/brand.html",
            "sidebar/search.html",
            "sidebar/scroll-start.html",
            "sidebar/navigation.html",
            "sidebar/ethical-ads.html",
            "sidebar/scroll-end.html",
            "side-github.html",
            "sidebar/variant-selector.html",
        ]
    }
    html_context = {"repository": "useblocks/sphinx-needs"}
elif DOCS_THEME == "pydata_sphinx_theme":
    # https://pydata-sphinx-theme.readthedocs.io
    html_css_files += ["_css/pydata_sphinx_theme.css"]
    html_theme_options = {
        "logo": {
            "image_light": "_static/sphinx-needs-logo-long-light.svg",
            "image_dark": "_static/sphinx-needs-logo-long-dark.svg",
        },
        "use_edit_page_button": True,
        "github_url": "https://github.com/useblocks/sphinx-needs",
    }
    html_context = {
        "github_user": "useblocks",
        "github_repo": "sphinx-needs",
        "github_version": "master",
        "doc_path": "docs",
    }
elif DOCS_THEME == "sphinx_rtd_theme":
    # https://sphinx-rtd-theme.readthedocs.io
    html_css_files += ["_css/sphinx_rtd_theme.css"]
    html_logo = "./_static/sphinx-needs-logo-long-dark.svg"
    html_theme_options = {
        "logo_only": True,
    }
elif DOCS_THEME == "sphinx_immaterial":
    # https://jbms.github.io/sphinx-immaterial
    html_logo = "./_static/sphinx-needs-logo-long-dark.svg"
    templates_path = ["_templates/sphinx_immaterial"]
    html_css_files += ["_css/sphinx_immaterial.css"]
    html_sidebars = {
        "**": ["about.html", "navigation.html", "searchbox.html"],
    }
    html_theme_options = {
        "font": False,
        "icon": {
            "repo": "fontawesome/brands/github",
        },
        "site_url": "https://sphinx-needs.readthedocs.io/",
        "repo_url": "https://github.com/useblocks/sphinx-needs",
        "repo_name": "Sphinx-Needs",
        "edit_uri": "blob/master/docs",
        "globaltoc_collapse": True,
        "features": [
            "navigation.sections",
            "navigation.top",
            "search.share",
        ],
        "palette": [
            {
                "media": "(prefers-color-scheme: light)",
                "scheme": "default",
                "primary": "blue",
                "accent": "light-blue",
                "toggle": {
                    "icon": "material/weather-night",
                    "name": "Switch to dark mode",
                },
            },
            {
                "media": "(prefers-color-scheme: dark)",
                "scheme": "slate",
                "primary": "blue",
                "accent": "yellow",
                "toggle": {
                    "icon": "material/weather-sunny",
                    "name": "Switch to light mode",
                },
            },
        ],
        "toc_title_is_page_title": True,
    }

# -- Options for htmlhelp builder ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = "needstestdocsdoc"

# -- Options for latex builder -------------------------------------------
# Grouping the document tree into LaTeX files. List of tuples (source start file, target name, title, author, documentclass [howto, manual, or own class]).
latex_documents = [
    (
        master_doc,
        "needstestdocs.tex",
        "needs test docs Documentation",
        "team useblocks",
        "manual",
    ),
]
latex_elements: dict[str, Any] = {
    # The paper size ('letterpaper' or 'a4paper').
    #
    # 'papersize': 'letterpaper',
    # The font size ('10pt', '11pt' or '12pt').
    #
    # 'pointsize': '10pt',
    # Additional stuff for the LaTeX preamble.
    #
    # 'preamble': '',
    # Latex figure (float) alignment
    #
    # 'figure_align': 'htbp',
}

# -- Options for man builder ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    (master_doc, "needstestdocs", "needs test docs Documentation", [author], 1)
]

# -- Options for texinfo builder -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples (source start file, target name, title, author, dir menu entry, description, category)
texinfo_documents = [
    (
        master_doc,
        "needstestdocs",
        "needs test docs Documentation",
        author,
        "needstestdocs",
        "One line description of project.",
        "Miscellaneous",
    ),
]

# -- Options for lincheck builder ---------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html?highlight=linkcheck#options-for-the-linkcheck-builder

linkcheck_ignore = [
    r"http://localhost:\d+",
    r"http://127.0.0.1:\d+",
    r"../.*",
    r"http://sourceforge.net/projects/plantuml.*",
    r"https?://useblocks.com/sphinx-needs/bench/index.html",
]

linkcheck_request_headers = {
    "*": {
        "User-Agent": "Mozilla/5.0",
    }
}

linkcheck_workers = 5

# -- Options for PlantUML extension ---------------------------------------

local_plantuml_path = os.path.join(
    os.path.dirname(__file__), "utils", "plantuml-1.2022.14.jar"
)
plantuml = f"java -Djava.awt.headless=true -jar {local_plantuml_path}"

# plantuml_output_format = 'png'
plantuml_output_format = "svg"

# -- Options for Needs extension ---------------------------------------

needs_from_toml = "ubproject.toml"

needs_debug_measurement = "READTHEDOCS" in os.environ  # run on CI
needs_debug_filters = True


def custom_defined_func():
    return "List of contributors:"


needs_render_context = {
    "custom_data_1": "Project_X",
    "custom_data_2": custom_defined_func(),
    "custom_data_3": True,
    "custom_data_4": [("Daniel", 811982), ("Marco", 234232)],
}

# needs_external_needs = [
#     {
#         "base_url": "https://sphinxcontrib-needs.readthedocs.io/en/latest",
#         "json_path": "examples/needs.json",
#         "id_prefix": "EXT_",
#         "css_class": "external_link",
#     },
# ]

# You can uncomment some of the following lines to override the default configuration for Sphinx-Needs.
# DEFAULT_DIAGRAM_TEMPLATE = "<size:12>{{type_name}}</size>\\n**{{title|wordwrap(15, wrapstring='**\\\\n**')}}**\\n<size:10>{{id}}</size>"
# needs_diagram_template = DEFAULT_DIAGRAM_TEMPLATE

# Absolute path to the needs_report_template_file based on the conf.py directory
# needs_report_template = "/needs_templates/report_template.need"   # Use custom report template

# -- custom extensions ---------------------------------------
from typing import get_args  # noqa: E402

from docutils import nodes  # noqa: E402
from docutils.statemachine import StringList  # noqa: E402
from sphinx.application import Sphinx  # noqa: E402
from sphinx.directives import SphinxDirective  # noqa: E402
from sphinx.roles import SphinxRole  # noqa: E402

from sphinx_needs.api import generate_need  # noqa: E402
from sphinx_needs.config import NeedsSphinxConfig  # noqa: E402
from sphinx_needs.logging import (  # noqa: E402
    WarningSubTypeDescription,
    WarningSubTypes,
)
from sphinx_needs.needsfile import NeedsList  # noqa: E402


class NeedsWarningsDirective(SphinxDirective):
    """Directive to list all extension warning subtypes."""

    def run(self):
        parsed = nodes.container(classes=["needs-warnings"])
        content = [
            f"- ``needs.{name}`` {WarningSubTypeDescription.get(name, '')}"
            for name in get_args(WarningSubTypes)
        ]
        self.state.nested_parse(StringList(content), self.content_offset, parsed)
        return [parsed]


class NeedExampleDirective(SphinxDirective):
    """Directive to add example content to the documentation.

    It adds a container with a title, a code block, and a parsed content block.
    """

    optional_arguments = 1
    final_argument_whitespace = True
    has_content = True

    def run(self):
        count = self.env.temp_data.setdefault("needs-example-count", 0)
        count += 1
        self.env.temp_data["needs-example-count"] = count
        root = nodes.container(classes=["needs-example"])
        self.set_source_info(root)
        title = f"Example {count}"
        title_nodes, _ = (
            self.state.inline_text(f"{title}: {self.arguments[0]}", self.lineno)
            if self.arguments
            else ([nodes.Text(title)], [])
        )
        root += nodes.rubric("", "", *title_nodes)
        code = nodes.literal_block(
            "", "\n".join(self.content), language="rst", classes=["needs-example-raw"]
        )
        root += code
        parsed = nodes.container(classes=["needs-example-raw"])
        root += parsed
        self.state.nested_parse(self.content, self.content_offset, parsed)
        return [root]


class NeedConfigDefaultRole(SphinxRole):
    """Role to add a default configuration value to the documentation."""

    def run(self):
        default = NeedsSphinxConfig.get_default(self.text)
        return [[nodes.literal("", repr(default), language="python")], []]


def create_tutorial_needs(app: Sphinx, _env, _docnames):
    """Create a JSON to import in the tutorial.

    We do this dynamically, to avoid having to maintain the JSON file manually.
    """
    needs_config = NeedsSphinxConfig(app.config)
    writer = NeedsList(app.config, outdir=app.confdir, confdir=app.confdir)
    for i in range(1, 5):
        need_item = generate_need(
            needs_config,
            need_type="tutorial-test",
            id=f"T_00{i}",
            title=f"Unit test {i}",
            content=f"Test case {i}",
        )
        writer.add_need(version, need_item)
    json_str = writer.dump_json()
    outpath = Path(app.confdir, "_static", "tutorial_needs.json")
    if outpath.is_file() and outpath.read_text() == json_str:
        return  # only write this file if it has changed
    outpath.write_text(json_str)


def setup(app: Sphinx):
    app.add_directive("need-example", NeedExampleDirective)
    app.add_directive("need-warnings", NeedsWarningsDirective)
    app.add_role("need_config_default", NeedConfigDefaultRole())
    app.connect("env-before-read-docs", create_tutorial_needs, priority=600)