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.
@@ -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"