sphinx-section-include 2026.11.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,40 @@
1
+ """Include parsed reStructuredText sections in Sphinx documentation."""
2
+
3
+ from importlib.metadata import version
4
+
5
+ from sphinx.application import Sphinx
6
+
7
+ from sphinx_section_include.directive import (
8
+ IncludeSection,
9
+ resolve_included_references,
10
+ )
11
+ from sphinx_section_include.reader import read_document, resolve_source
12
+ from sphinx_section_include.sections import (
13
+ copy_section,
14
+ find_sections,
15
+ select_section,
16
+ )
17
+
18
+ __all__ = [
19
+ "copy_section",
20
+ "find_sections",
21
+ "read_document",
22
+ "resolve_source",
23
+ "select_section",
24
+ ]
25
+ __version__ = version(distribution_name="sphinx-section-include")
26
+
27
+
28
+ def setup(app: Sphinx) -> dict[str, object]:
29
+ """Register the directive and builder-independent reference
30
+ handling.
31
+ """
32
+ app.add_directive(name="include-section", cls=IncludeSection)
33
+ _ = app.connect(
34
+ event="doctree-resolved", callback=resolve_included_references
35
+ )
36
+ return {
37
+ "version": __version__,
38
+ "parallel_read_safe": True,
39
+ "parallel_write_safe": True,
40
+ }
@@ -0,0 +1,232 @@
1
+ """Expose parsed section inclusion as a Sphinx directive."""
2
+
3
+ import posixpath
4
+ from collections.abc import Callable
5
+ from pathlib import Path
6
+ from typing import Any, ClassVar, override
7
+ from urllib.parse import urlsplit
8
+
9
+ from docutils import nodes
10
+ from docutils.parsers.rst import directives
11
+ from sphinx import addnodes
12
+ from sphinx.application import Sphinx
13
+ from sphinx.errors import NoUri
14
+ from sphinx.util import docname_join
15
+ from sphinx.util.docutils import SphinxDirective
16
+
17
+ from sphinx_section_include.reader import read_document, resolve_source
18
+ from sphinx_section_include.sections import copy_section, select_section
19
+
20
+
21
+ def _prepare_nodes(
22
+ *,
23
+ directive: SphinxDirective,
24
+ content: list[nodes.Node],
25
+ source_docname: str,
26
+ ) -> list[nodes.Node]:
27
+ """Prefix copied targets and retain external reference origins."""
28
+ container = nodes.container()
29
+ container.extend(item=content)
30
+ serial = directive.env.new_serialno(category="section-include")
31
+ prefix = f"section-include-{serial}-"
32
+ elements = list(container.findall(condition=nodes.Element))
33
+ identities = {
34
+ identity: prefix + identity
35
+ for element in elements
36
+ for identity in element["ids"]
37
+ }
38
+ names = {
39
+ name: prefix + name
40
+ for element in elements
41
+ for name in element["names"]
42
+ }
43
+ for element in elements:
44
+ element["ids"] = [identities[identity] for identity in element["ids"]]
45
+ element["names"] = [names[name] for name in element["names"]]
46
+ if bool(element["ids"]) or bool(element["names"]):
47
+ directive.state.document.note_explicit_target(target=element)
48
+ element.document = directive.state.document
49
+ if isinstance(element, addnodes.pending_xref):
50
+ _prepare_cross_reference(
51
+ reference=element,
52
+ names=names,
53
+ source_docname=source_docname,
54
+ docname=directive.env.docname,
55
+ )
56
+ if isinstance(element, nodes.reference):
57
+ _prepare_reference(
58
+ reference=element,
59
+ identities=identities,
60
+ source_docname=source_docname,
61
+ )
62
+ if isinstance(element, nodes.image):
63
+ _prepare_image(
64
+ image=element,
65
+ directive=directive,
66
+ source_docname=source_docname,
67
+ )
68
+ return container.children
69
+
70
+
71
+ def _prepare_cross_reference(
72
+ *,
73
+ reference: addnodes.pending_xref,
74
+ names: dict[str, str],
75
+ source_docname: str,
76
+ docname: str,
77
+ ) -> None:
78
+ """Keep Sphinx roles tied to their selected target or original
79
+ document.
80
+ """
81
+ if reference.get(key="refdomain") == "std":
82
+ if (
83
+ reference.get(key="reftype") == "ref"
84
+ and reference["reftarget"] in names
85
+ ):
86
+ reference["reftarget"] = names[reference["reftarget"]]
87
+ elif reference.get(key="reftype") == "doc":
88
+ reference["reftarget"] = "/" + docname_join(
89
+ basedocname=source_docname, docname=reference["reftarget"]
90
+ )
91
+ reference["refdoc"] = docname
92
+
93
+
94
+ def _is_relative_uri(*, uri: str) -> bool:
95
+ """Recognize local links without schemes, hosts, or rooted paths."""
96
+ parsed = urlsplit(url=uri)
97
+ return (
98
+ not bool(parsed.scheme)
99
+ and not bool(parsed.netloc)
100
+ and not parsed.path.startswith("/")
101
+ )
102
+
103
+
104
+ def _prepare_reference(
105
+ *,
106
+ reference: nodes.reference,
107
+ identities: dict[str, str],
108
+ source_docname: str,
109
+ ) -> None:
110
+ """Distinguish anchors inside the excerpt from links to its source."""
111
+ if "refid" in reference:
112
+ target = reference["refid"]
113
+ if target in identities:
114
+ reference["refid"] = identities[target]
115
+ else:
116
+ del reference["refid"]
117
+ _ = reference.setdefault(
118
+ key="section_include_origin", failobj=source_docname
119
+ )
120
+ reference["section_include_anchor"] = target
121
+ elif "refuri" in reference and _is_relative_uri(uri=reference["refuri"]):
122
+ _ = reference.setdefault(
123
+ key="section_include_origin", failobj=source_docname
124
+ )
125
+
126
+
127
+ def _prepare_image(
128
+ *,
129
+ image: nodes.image,
130
+ directive: SphinxDirective,
131
+ source_docname: str,
132
+ ) -> None:
133
+ """Resolve local image paths before the caller collects image
134
+ assets.
135
+ """
136
+ if not _is_relative_uri(uri=image["uri"]):
137
+ return
138
+ origin = Path(
139
+ image.source
140
+ if image.source is not None
141
+ else directive.env.doc2path(docname=source_docname)
142
+ )
143
+ relative = (
144
+ origin.parent.resolve()
145
+ .relative_to(Path(directive.env.srcdir).resolve())
146
+ .as_posix()
147
+ )
148
+ image["uri"] = "/" + posixpath.normpath(
149
+ path=posixpath.join(relative, str(object=image["uri"]))
150
+ )
151
+
152
+
153
+ def resolve_included_references(
154
+ app: Sphinx, doctree: nodes.document, docname: str
155
+ ) -> None:
156
+ """Resolve source links using the active builder's URI conventions."""
157
+ for reference in doctree.findall(condition=nodes.reference):
158
+ origin = reference.get(key="section_include_origin")
159
+ if origin is None:
160
+ continue
161
+ try:
162
+ base = app.builder.get_relative_uri(from_=docname, to=origin)
163
+ except NoUri:
164
+ reference.replace_self(new=reference.children)
165
+ continue
166
+ anchor = reference.get(key="section_include_anchor")
167
+ if anchor is not None:
168
+ reference["refuri"] = base + "#" + anchor
169
+ else:
170
+ # Keep paths relative to the original rendered document.
171
+
172
+ parsed = urlsplit(url=str(object=reference["refuri"]))
173
+ path = (
174
+ posixpath.normpath(
175
+ path=posixpath.join(posixpath.dirname(base), parsed.path)
176
+ )
177
+ if bool(parsed.path)
178
+ else base
179
+ )
180
+ if parsed.path.endswith("/") and not path.endswith("/"):
181
+ path += "/"
182
+ reference["refuri"] = parsed._replace(path=path).geturl()
183
+
184
+
185
+ class IncludeSection(SphinxDirective):
186
+ """Include one exact section while preserving its document
187
+ structure.
188
+ """
189
+
190
+ required_arguments = 1
191
+ option_spec: ClassVar[dict[str, Callable[[str], Any]] | None] = { # pyrefly: ignore[explicit-any]
192
+ "section": directives.unchanged_required,
193
+ "include-heading": directives.flag,
194
+ "exclude-sections": directives.unchanged_required,
195
+ }
196
+
197
+ @override
198
+ def run(self) -> list[nodes.Node]:
199
+ """Read, select, and copy a section without rendering it to
200
+ HTML.
201
+ """
202
+ if "section" not in self.options:
203
+ raise self.error(message="include-section requires :section:")
204
+ try:
205
+ path = resolve_source(directive=self, source=self.arguments[0])
206
+ document = read_document(directive=self, source=self.arguments[0])
207
+ selected = select_section(
208
+ document=document, selector=self.options["section"]
209
+ )
210
+ excluded = tuple(
211
+ select_section(document=selected, selector=selector.strip())
212
+ for selector in self.options.get(
213
+ "exclude-sections", ""
214
+ ).splitlines()
215
+ if bool(selector.strip())
216
+ )
217
+ content = copy_section(
218
+ section=selected,
219
+ include_heading="include-heading" in self.options,
220
+ exclude_sections=excluded,
221
+ )
222
+ return _prepare_nodes(
223
+ directive=self,
224
+ content=content,
225
+ source_docname=path.relative_to(
226
+ Path(self.env.srcdir).resolve()
227
+ )
228
+ .with_suffix(suffix="")
229
+ .as_posix(),
230
+ )
231
+ except ValueError as error:
232
+ raise self.error(message=str(object=error)) from error
File without changes
@@ -0,0 +1,110 @@
1
+ """Read source documents through the active Sphinx directive context."""
2
+
3
+ from copy import copy
4
+ from pathlib import Path
5
+
6
+ from docutils import nodes
7
+ from docutils.parsers.rst import Parser
8
+ from docutils.transforms.references import (
9
+ AnonymousHyperlinks,
10
+ DanglingReferences,
11
+ ExternalTargets,
12
+ IndirectHyperlinks,
13
+ InternalTargets,
14
+ PropagateTargets,
15
+ Substitutions,
16
+ )
17
+ from docutils.utils import new_document
18
+ from sphinx.transforms import DefaultSubstitutions
19
+ from sphinx.util.docutils import LoggingReporter, SphinxDirective
20
+
21
+
22
+ def resolve_source(*, directive: SphinxDirective, source: str) -> Path:
23
+ """Resolve an RST source inside the Sphinx source directory."""
24
+ root = Path(directive.env.srcdir).resolve()
25
+ _relative, filename = directive.env.relfn2path(filename=source)
26
+ path = Path(filename).resolve()
27
+ if not path.is_relative_to(root) or path.suffix != ".rst":
28
+ message = (
29
+ "Section source must be an RST file within the source directory"
30
+ )
31
+ raise ValueError(message)
32
+ current = Path(
33
+ directive.env.doc2path(docname=directive.env.docname)
34
+ ).resolve()
35
+ if path == current:
36
+ message = "A section include cannot include itself"
37
+ raise ValueError(message)
38
+ if not path.is_file():
39
+ message = f"Section source does not exist: {source!r}"
40
+ raise ValueError(message)
41
+ return path
42
+
43
+
44
+ def read_document(
45
+ *, directive: SphinxDirective, source: str, docname: str | None = None
46
+ ) -> nodes.document:
47
+ """Parse source content and record its transitive include dependencies.
48
+
49
+ Registered directives, substitutions, and the caller's Sphinx configuration
50
+ remain available. Source-relative includes use the source document's path.
51
+ Temporary parsing context is restored even if parsing fails.
52
+ """
53
+ path = resolve_source(directive=directive, source=source)
54
+ root = Path(directive.env.srcdir).resolve()
55
+ parent = directive.state.document
56
+ ancestors = tuple[str, ...](
57
+ parent.get(key="_section_include_sources", failobj=())
58
+ )
59
+ if str(object=path) in ancestors:
60
+ message = f"Circular section include involving {path.name!r}"
61
+ raise ValueError(message)
62
+ settings = copy(x=parent.settings)
63
+ document = new_document(
64
+ source_path=str(
65
+ object=directive.env.doc2path(
66
+ docname=directive.env.docname if docname is None else docname
67
+ )
68
+ ),
69
+ settings=settings,
70
+ )
71
+ document.reporter = LoggingReporter.from_reporter(
72
+ reporter=document.reporter
73
+ )
74
+ document["_section_include_sources"] = (*ancestors, str(object=path))
75
+ relative = path.relative_to(root).as_posix()
76
+ env = directive.env
77
+ current = env.current_document
78
+ source_docname = path.relative_to(root).with_suffix(suffix="").as_posix()
79
+ context = copy(x=current)
80
+ context.docname = source_docname if docname is None else docname
81
+ env.note_dependency(filename=path)
82
+ env.current_document = context
83
+ try:
84
+ text = "\n\n".join(
85
+ part
86
+ for part in (
87
+ directive.config.rst_prolog or "",
88
+ f".. include:: /{relative}",
89
+ directive.config.rst_epilog or "",
90
+ )
91
+ if bool(part)
92
+ )
93
+ Parser().parse(inputstring=text, document=document)
94
+ for transform in (
95
+ DefaultSubstitutions,
96
+ Substitutions,
97
+ PropagateTargets,
98
+ AnonymousHyperlinks,
99
+ IndirectHyperlinks,
100
+ ExternalTargets,
101
+ InternalTargets,
102
+ DanglingReferences,
103
+ ):
104
+ transform(document=document).apply()
105
+ finally:
106
+ env.current_document = current
107
+ env.dependencies[current.docname].update(
108
+ env.dependencies[context.docname]
109
+ )
110
+ return document
@@ -0,0 +1,78 @@
1
+ """Select and copy parsed sections without imposing presentation
2
+ policy.
3
+ """
4
+
5
+ from docutils import nodes
6
+
7
+
8
+ def find_sections(
9
+ *, document: nodes.document | nodes.section, selector: str
10
+ ) -> list[nodes.section]:
11
+ """Find literal headings, heading paths, or standard RST labels.
12
+
13
+ Literal headings take precedence over path or label syntax.
14
+ """
15
+ sections = list(document.findall(condition=nodes.section))
16
+ literal = [
17
+ section for section in sections if section[0].astext() == selector
18
+ ]
19
+ if bool(literal):
20
+ return literal
21
+ if selector.startswith("#"):
22
+ label = nodes.fully_normalize_name(name=selector[1:])
23
+ return [
24
+ section
25
+ for section in sections
26
+ if label in section["names"] or label in section["ids"]
27
+ ]
28
+ parts = [part.strip() for part in selector.split(sep="/")]
29
+ matches: list[nodes.section] = [
30
+ section for section in sections if section[0].astext() == parts[0]
31
+ ]
32
+ for part in parts[1:]:
33
+ matches = [
34
+ child
35
+ for section in matches
36
+ for child in section.children
37
+ if isinstance(child, nodes.section) and child[0].astext() == part
38
+ ]
39
+ return matches
40
+
41
+
42
+ def select_section(
43
+ *, document: nodes.document | nodes.section, selector: str
44
+ ) -> nodes.section:
45
+ """Require exactly one matching section."""
46
+ matches = find_sections(document=document, selector=selector)
47
+ if len(matches) != 1:
48
+ message = (
49
+ f"Expected one section for {selector!r}, found {len(matches)}"
50
+ )
51
+ raise ValueError(message)
52
+ return matches[0]
53
+
54
+
55
+ def copy_section(
56
+ *,
57
+ section: nodes.section,
58
+ include_heading: bool = True,
59
+ exclude_sections: tuple[nodes.section, ...] = (),
60
+ ) -> list[nodes.Node]:
61
+ """Copy a subtree, preserving headings, anchors, and source metadata.
62
+
63
+ Exclusions must be resolved descendants of the selected section.
64
+ The source tree is never modified.
65
+ """
66
+ originals = list(section.findall(condition=nodes.section))
67
+ identities = {id(node) for node in originals if node is not section}
68
+ if any(id(node) not in identities for node in exclude_sections):
69
+ message = "Excluded sections must be descendants of the selection"
70
+ raise ValueError(message)
71
+ copied = section.deepcopy()
72
+ copies = list(copied.findall(condition=nodes.section))
73
+ excluded = {id(node) for node in exclude_sections}
74
+ for original, target in zip(originals, copies, strict=True):
75
+ if id(original) in excluded:
76
+ assert target.parent is not None
77
+ _ = target.parent.remove(item=target)
78
+ return [copied] if include_heading else copied.children[1:]
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.4
2
+ Name: sphinx-section-include
3
+ Version: 2026.11.1
4
+ Summary: Include selected sections of reStructuredText documents in Sphinx projects.
5
+ Author-email: Adam Dangoor <adamdangoor@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Issues, https://github.com/adamtheturtle/sphinx-section-include/issues
8
+ Project-URL: Source, https://github.com/adamtheturtle/sphinx-section-include
9
+ Keywords: documentation,rst,sphinx
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Web Environment
12
+ Classifier: Framework :: Sphinx :: Extension
13
+ Classifier: Operating System :: Microsoft :: Windows
14
+ Classifier: Operating System :: POSIX
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Programming Language :: Python :: 3.15
20
+ Requires-Python: >=3.12
21
+ Description-Content-Type: text/x-rst
22
+ License-File: LICENSE
23
+ Requires-Dist: docutils>=0.21.2
24
+ Requires-Dist: sphinx<10,>=9.1.1
25
+ Dynamic: license-file
26
+
27
+ |Build Status| |PyPI|
28
+
29
+ sphinx-section-include
30
+ ======================
31
+
32
+ Include selected sections of reStructuredText documents in Sphinx projects.
33
+ The extension copies parsed nodes, retaining nested headings, code blocks, source locations, and references.
34
+ It also provides a typed Python API for extensions that select and transform sections themselves.
35
+
36
+ Installation
37
+ ------------
38
+
39
+ .. code-block:: console
40
+
41
+ $ pip install sphinx-section-include
42
+
43
+ Enable the extension in ``conf.py``:
44
+
45
+ .. code-block:: python
46
+
47
+ """Enable section inclusion in this Sphinx project."""
48
+
49
+ extensions = ["sphinx_section_include"]
50
+
51
+ Including a section
52
+ -------------------
53
+
54
+ .. code-block:: rst
55
+
56
+ .. include-section:: manual.rst
57
+ :section: Getting started / Configuration
58
+ :include-heading:
59
+ :exclude-sections: Advanced configuration
60
+
61
+ ``:section:`` is required.
62
+ It accepts an exact heading, a slash-separated heading path, or an RST label prefixed by ``#``.
63
+ Literal heading matches take precedence, so headings containing slashes remain selectable.
64
+ Missing or ambiguous selections fail with a build diagnostic.
65
+
66
+ ``:include-heading:`` includes the selected section's heading.
67
+ Without it, only the section's contents and nested sections are included.
68
+ ``:exclude-sections:`` accepts one descendant selector per line.
69
+
70
+ Paths are relative to the including document.
71
+ A leading ``/`` selects a path relative to the Sphinx source directory.
72
+ Sources must be existing ``.rst`` files within that directory.
73
+ Self-inclusion and circular section includes are rejected.
74
+
75
+ Source documents are parsed with registered directives, substitutions, ``rst_prolog``, and ``rst_epilog``.
76
+ Dependencies from nested includes are tracked for incremental builds.
77
+ Internal anchors are namespaced so the same section can appear more than once.
78
+ Links outside the excerpt retain their source document, and local image paths retain their source directory.
79
+ Standard Sphinx reference resolution and builder URI conventions apply.
80
+
81
+ Python API
82
+ ----------
83
+
84
+ ``find_sections(document=..., selector=...)`` returns all matching sections.
85
+ ``select_section(document=..., selector=...)`` requires exactly one match and raises ``ValueError`` otherwise.
86
+
87
+ ``copy_section(section=..., include_heading=True, exclude_sections=())`` returns independent copied nodes without modifying the source tree.
88
+ Exclusions are resolved section nodes and must be descendants of the selection.
89
+ This function preserves document structure and does not apply rendering policy.
90
+
91
+ For Sphinx directive authors, ``read_document(directive=..., source=..., docname=None)`` parses an RST source and records its dependencies.
92
+ The default parsing context is the source document.
93
+ A ``docname`` override supports extensions whose embedded content uses the caller's context.
94
+ Temporary context is restored after parsing.
95
+ ``resolve_source(directive=..., source=...)`` validates and resolves the path.
96
+ Both helpers require an active Sphinx build, which supplies the source directory and directive context.
97
+
98
+ This library was extracted from `sphinx-hackerrank <https://github.com/adamtheturtle/sphinx-hackerrank>`_.
99
+ HackerRank layouts, language filtering, and HTML export remain in that extension.
100
+
101
+ Development
102
+ -----------
103
+
104
+ See `CONTRIBUTING.rst <CONTRIBUTING.rst>`_ for local checks and release steps.
105
+ The sample project exercises section inclusion without HackerRank dependencies.
106
+
107
+ License
108
+ -------
109
+
110
+ MIT.
111
+ See ``LICENSE``.
112
+
113
+ .. |Build Status| image:: https://github.com/adamtheturtle/sphinx-section-include/actions/workflows/ci.yml/badge.svg?branch=main
114
+ :target: https://github.com/adamtheturtle/sphinx-section-include/actions
115
+ .. |PyPI| image:: https://badge.fury.io/py/sphinx-section-include.svg
116
+ :target: https://badge.fury.io/py/sphinx-section-include
@@ -0,0 +1,10 @@
1
+ sphinx_section_include/__init__.py,sha256=0eEbZPjCobVcfti28Th061whDkLmKJsqUkMgzttl9sQ,1039
2
+ sphinx_section_include/directive.py,sha256=gYKXYioqo6ZrXr_kyFCBXP7r3FErucjk0qipquKnbXY,7917
3
+ sphinx_section_include/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ sphinx_section_include/reader.py,sha256=Td25MC7Svl0fz7ZDREcdeolV6us_TuKcDAKRL1o5D0o,3870
5
+ sphinx_section_include/sections.py,sha256=XfBIao0a_oLPgE8uoC6lkhDErwev1M3fHaSJb6w3JWU,2722
6
+ sphinx_section_include-2026.11.1.dist-info/licenses/LICENSE,sha256=hvkADUCIndXpdC1L7yhnIKS99N0Wdtaf9YF06bRgZCo,1065
7
+ sphinx_section_include-2026.11.1.dist-info/METADATA,sha256=A5JdBWkjwmSBJifir5wO4euvW42K_Uew5_0Lz6l6Ieo,4847
8
+ sphinx_section_include-2026.11.1.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
9
+ sphinx_section_include-2026.11.1.dist-info/top_level.txt,sha256=MoKTLpvbIddgffcyurFCklHI2C5p-2HCYu314x92xdM,23
10
+ sphinx_section_include-2026.11.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rippling
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ sphinx_section_include