sphinx-tabular 0.1.0__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.
- sphinx_tabular/__init__.py +42 -0
- sphinx_tabular/directive.py +148 -0
- sphinx_tabular/formulas.py +1572 -0
- sphinx_tabular/html.py +36 -0
- sphinx_tabular/markup.py +107 -0
- sphinx_tabular/model.py +40 -0
- sphinx_tabular/normalize.py +76 -0
- sphinx_tabular/parser.py +104 -0
- sphinx_tabular/render_nodes.py +159 -0
- sphinx_tabular/static/sphinx-tabular.css +454 -0
- sphinx_tabular/static/sphinx-tabular.js +79 -0
- sphinx_tabular-0.1.0.dist-info/METADATA +127 -0
- sphinx_tabular-0.1.0.dist-info/RECORD +15 -0
- sphinx_tabular-0.1.0.dist-info/WHEEL +5 -0
- sphinx_tabular-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from .directive import McsvTableDirective, RcsvTableDirective
|
|
6
|
+
|
|
7
|
+
from docutils import nodes
|
|
8
|
+
|
|
9
|
+
from .html import depart_entry_html, visit_entry_html
|
|
10
|
+
|
|
11
|
+
def setup(app):
|
|
12
|
+
# Needed for .mcsv cell parsing.
|
|
13
|
+
app.setup_extension("myst_parser")
|
|
14
|
+
|
|
15
|
+
app.add_directive("rcsv-table", RcsvTableDirective)
|
|
16
|
+
app.add_directive("mcsv-table", McsvTableDirective)
|
|
17
|
+
|
|
18
|
+
app.add_node(
|
|
19
|
+
nodes.entry,
|
|
20
|
+
override=True,
|
|
21
|
+
html=(visit_entry_html, depart_entry_html),
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
app.add_config_value("sphinx_tabular_strict", False, "env")
|
|
25
|
+
|
|
26
|
+
app.connect("builder-inited", _copy_static_assets)
|
|
27
|
+
app.add_css_file("sphinx-tabular.css")
|
|
28
|
+
app.add_js_file("sphinx-tabular.js")
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
"version": "0.1.0",
|
|
32
|
+
"parallel_read_safe": True,
|
|
33
|
+
"parallel_write_safe": True,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _copy_static_assets(app):
|
|
40
|
+
static_src = Path(__file__).parent / "static"
|
|
41
|
+
if str(static_src) not in app.config.html_static_path:
|
|
42
|
+
app.config.html_static_path.append(str(static_src))
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from docutils.parsers.rst import directives
|
|
6
|
+
from sphinx.errors import ExtensionError
|
|
7
|
+
from sphinx.util.docutils import SphinxDirective
|
|
8
|
+
|
|
9
|
+
from .normalize import normalize_rows
|
|
10
|
+
from .parser import RcsvParseError, parse_csv_with_quote_tracking
|
|
11
|
+
from .render_nodes import build_table_node
|
|
12
|
+
from docutils import nodes
|
|
13
|
+
from sphinx.util import logging
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
class BaseTabularDirective(SphinxDirective):
|
|
18
|
+
has_content = True
|
|
19
|
+
required_arguments = 0
|
|
20
|
+
optional_arguments = 1
|
|
21
|
+
final_argument_whitespace = True
|
|
22
|
+
|
|
23
|
+
markup = "rst"
|
|
24
|
+
directive_name = "tabular-table"
|
|
25
|
+
dialect_class = "sphinx-tabular"
|
|
26
|
+
|
|
27
|
+
option_spec = {
|
|
28
|
+
"file": directives.unchanged_required,
|
|
29
|
+
"header-rows": directives.nonnegative_int,
|
|
30
|
+
"width": directives.unchanged,
|
|
31
|
+
"widths": directives.unchanged,
|
|
32
|
+
"class": directives.class_option,
|
|
33
|
+
"text-align": directives.unchanged,
|
|
34
|
+
"vertical-align": directives.unchanged,
|
|
35
|
+
"sticky-header": directives.flag,
|
|
36
|
+
"sticky-offset": directives.unchanged,
|
|
37
|
+
"strict": directives.flag,
|
|
38
|
+
}
|
|
39
|
+
def _is_strict(self) -> bool:
|
|
40
|
+
return bool(
|
|
41
|
+
"strict" in self.options
|
|
42
|
+
or getattr(self.config, "sphinx_tabular_strict", False)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _warn_or_raise(self, message: str) -> list[nodes.Node]:
|
|
47
|
+
if self._is_strict():
|
|
48
|
+
raise ExtensionError(message)
|
|
49
|
+
|
|
50
|
+
source, line = self.get_source_info()
|
|
51
|
+
|
|
52
|
+
logger.warning(
|
|
53
|
+
"sphinx-tabular: %s",
|
|
54
|
+
message,
|
|
55
|
+
location=(source, line),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return []
|
|
59
|
+
|
|
60
|
+
def run(self):
|
|
61
|
+
caption = self.arguments[0] if self.arguments else None
|
|
62
|
+
|
|
63
|
+
has_file = "file" in self.options
|
|
64
|
+
has_inline_content = any(line.strip() for line in self.content)
|
|
65
|
+
|
|
66
|
+
strict = bool(
|
|
67
|
+
"strict" in self.options
|
|
68
|
+
or getattr(self.config, "sphinx_tabular_strict", False)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
if has_file and has_inline_content:
|
|
72
|
+
return self._warn_or_raise(
|
|
73
|
+
f"{self.directive_name}: specify either :file: or inline content, not both"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
if not has_file and not has_inline_content:
|
|
77
|
+
return self._warn_or_raise(
|
|
78
|
+
f"{self.directive_name}: specify either :file: or inline content"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if has_file:
|
|
82
|
+
rel_file = self.options["file"]
|
|
83
|
+
|
|
84
|
+
doc_dir = Path(self.env.doc2path(self.env.docname)).parent
|
|
85
|
+
source_path = (doc_dir / rel_file).resolve()
|
|
86
|
+
|
|
87
|
+
if not source_path.exists():
|
|
88
|
+
return self._warn_or_raise(
|
|
89
|
+
f"{self.directive_name}: file not found: {rel_file}"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
self.env.note_dependency(str(source_path))
|
|
93
|
+
text = source_path.read_text(encoding="utf-8")
|
|
94
|
+
source = str(source_path)
|
|
95
|
+
else:
|
|
96
|
+
text = "\n".join(self.content)
|
|
97
|
+
source = self.env.doc2path(self.env.docname)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
raw_rows = parse_csv_with_quote_tracking(text)
|
|
102
|
+
rows = normalize_rows(
|
|
103
|
+
raw_rows,
|
|
104
|
+
source=source,
|
|
105
|
+
strict=strict,
|
|
106
|
+
directive_name=self.directive_name,
|
|
107
|
+
warning_docname=self.env.docname,
|
|
108
|
+
warning_line_offset=self.content_offset - 1,
|
|
109
|
+
)
|
|
110
|
+
except RcsvParseError as exc:
|
|
111
|
+
return self._warn_or_raise(f"{self.directive_name}: {exc}")
|
|
112
|
+
except ValueError as exc:
|
|
113
|
+
return self._warn_or_raise(f"{self.directive_name}: {exc}")
|
|
114
|
+
|
|
115
|
+
classes = [
|
|
116
|
+
"sphinx-tabular",
|
|
117
|
+
self.dialect_class,
|
|
118
|
+
]
|
|
119
|
+
classes.extend(self.options.get("class", []))
|
|
120
|
+
|
|
121
|
+
if "sticky-header" in self.options:
|
|
122
|
+
classes.append("sphinx-tabular-sticky-header")
|
|
123
|
+
|
|
124
|
+
table = build_table_node(
|
|
125
|
+
rows,
|
|
126
|
+
directive=self,
|
|
127
|
+
source=source,
|
|
128
|
+
markup=self.markup,
|
|
129
|
+
caption=caption,
|
|
130
|
+
header_rows=self.options.get("header-rows", 0),
|
|
131
|
+
table_classes=classes,
|
|
132
|
+
table_width=self.options.get("width"),
|
|
133
|
+
sticky_offset=self.options.get("sticky-offset"),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
return [table]
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class RcsvTableDirective(BaseTabularDirective):
|
|
140
|
+
markup = "rst"
|
|
141
|
+
directive_name = "rcsv-table"
|
|
142
|
+
dialect_class = "sphinx-tabular-rcsv"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class McsvTableDirective(BaseTabularDirective):
|
|
146
|
+
markup = "myst"
|
|
147
|
+
directive_name = "mcsv-table"
|
|
148
|
+
dialect_class = "sphinx-tabular-mcsv"
|