epub-generator 0.1.6__py3-none-any.whl → 0.1.7__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.
- epub_generator/context.py +5 -2
- epub_generator/generation/__init__.py +1 -1
- epub_generator/generation/gen_asset.py +20 -15
- epub_generator/generation/gen_chapter.py +6 -6
- epub_generator/generation/gen_content.py +3 -4
- epub_generator/generation/gen_epub.py +3 -31
- epub_generator/generation/gen_toc.py +6 -11
- epub_generator/generation/xml_utils.py +9 -5
- epub_generator/html_tag.py +4 -2
- epub_generator/types.py +22 -3
- epub_generator/validate.py +3 -1
- {epub_generator-0.1.6.dist-info → epub_generator-0.1.7.dist-info}/METADATA +1 -1
- epub_generator-0.1.7.dist-info/RECORD +27 -0
- epub_generator-0.1.6.dist-info/RECORD +0 -27
- {epub_generator-0.1.6.dist-info → epub_generator-0.1.7.dist-info}/LICENSE +0 -0
- {epub_generator-0.1.6.dist-info → epub_generator-0.1.7.dist-info}/WHEEL +0 -0
epub_generator/context.py
CHANGED
|
@@ -18,6 +18,7 @@ class _AssetNode:
|
|
|
18
18
|
media_type: str
|
|
19
19
|
content_hash: str
|
|
20
20
|
|
|
21
|
+
|
|
21
22
|
class Context:
|
|
22
23
|
def __init__(
|
|
23
24
|
self,
|
|
@@ -55,7 +56,7 @@ class Context:
|
|
|
55
56
|
nodes = list(self._hash_to_node.values())
|
|
56
57
|
nodes.sort(key=lambda node: node.file_name)
|
|
57
58
|
return [(node.file_name, node.media_type) for node in nodes]
|
|
58
|
-
|
|
59
|
+
|
|
59
60
|
@property
|
|
60
61
|
def chapters_with_mathml(self) -> set[str]:
|
|
61
62
|
return self._chapters_with_mathml
|
|
@@ -117,6 +118,7 @@ class Context:
|
|
|
117
118
|
)
|
|
118
119
|
return file_name
|
|
119
120
|
|
|
121
|
+
|
|
120
122
|
class Template:
|
|
121
123
|
def __init__(self):
|
|
122
124
|
templates_path = cast(Path, files("epub_generator")) / "data"
|
|
@@ -134,7 +136,8 @@ class Template:
|
|
|
134
136
|
self._templates[name] = template
|
|
135
137
|
return template
|
|
136
138
|
|
|
139
|
+
|
|
137
140
|
def _sha256_hash(data: bytes) -> str:
|
|
138
141
|
hash256 = sha256()
|
|
139
142
|
hash256.update(data)
|
|
140
|
-
return hash256.hexdigest()
|
|
143
|
+
return hash256.hexdigest()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
from .gen_epub import generate_epub
|
|
1
|
+
from .gen_epub import generate_epub
|
|
@@ -22,13 +22,15 @@ _MEDIA_TYPE_MAP = {
|
|
|
22
22
|
|
|
23
23
|
def render_inline_formula(context: Context, formula: Formula) -> Element | None:
|
|
24
24
|
return _render_formula(
|
|
25
|
-
context=context,
|
|
26
|
-
formula=formula,
|
|
25
|
+
context=context,
|
|
26
|
+
formula=formula,
|
|
27
27
|
inline_mode=True,
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
def render_asset_block(
|
|
31
|
+
def render_asset_block(
|
|
32
|
+
context: Context, block: Table | Formula | Image
|
|
33
|
+
) -> Element | None:
|
|
32
34
|
element: Element | None = None
|
|
33
35
|
if isinstance(block, Table):
|
|
34
36
|
element = _render_table(context, block)
|
|
@@ -44,17 +46,17 @@ def _render_table(context: Context, table: Table) -> Element | None:
|
|
|
44
46
|
return None
|
|
45
47
|
|
|
46
48
|
return _wrap_asset_content(
|
|
47
|
-
context=context,
|
|
48
|
-
asset=table,
|
|
49
|
+
context=context,
|
|
50
|
+
asset=table,
|
|
49
51
|
content_element=render_html_tag(context, table.html_content),
|
|
50
52
|
)
|
|
51
53
|
|
|
52
54
|
|
|
53
55
|
def _render_formula(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
context: Context,
|
|
57
|
+
formula: Formula,
|
|
58
|
+
inline_mode: bool,
|
|
59
|
+
) -> Element | None:
|
|
58
60
|
|
|
59
61
|
if context.latex_render == LaTeXRender.CLIPPING:
|
|
60
62
|
return None
|
|
@@ -88,7 +90,7 @@ def _render_formula(
|
|
|
88
90
|
|
|
89
91
|
return _wrap_asset_content(
|
|
90
92
|
context=context,
|
|
91
|
-
asset=formula,
|
|
93
|
+
asset=formula,
|
|
92
94
|
content_element=content_element,
|
|
93
95
|
inline_mode=inline_mode,
|
|
94
96
|
)
|
|
@@ -106,11 +108,12 @@ def _process_image(context: Context, image: Image) -> Element:
|
|
|
106
108
|
img_element.set("alt", "") # Empty alt text, use caption instead
|
|
107
109
|
|
|
108
110
|
return _wrap_asset_content(
|
|
109
|
-
context=context,
|
|
110
|
-
asset=image,
|
|
111
|
+
context=context,
|
|
112
|
+
asset=image,
|
|
111
113
|
content_element=img_element,
|
|
112
114
|
)
|
|
113
115
|
|
|
116
|
+
|
|
114
117
|
def _normalize_expression(expression: str) -> str:
|
|
115
118
|
expression = expression.replace("\n", "")
|
|
116
119
|
expression = expression.strip()
|
|
@@ -159,7 +162,9 @@ def _latex_formula2svg(latex: str, font_size: int = 12):
|
|
|
159
162
|
plt.rc("text", usetex=True)
|
|
160
163
|
plt.rc("font", size=font_size)
|
|
161
164
|
fig, ax = plt.subplots()
|
|
162
|
-
txt = ax.text(
|
|
165
|
+
txt = ax.text(
|
|
166
|
+
0.5, 0.5, f"${latex}$", ha="center", va="center", transform=ax.transAxes
|
|
167
|
+
)
|
|
163
168
|
ax.axis("off")
|
|
164
169
|
fig.canvas.draw()
|
|
165
170
|
bbox = txt.get_window_extent(cast(Any, fig.canvas).get_renderer())
|
|
@@ -174,7 +179,7 @@ def _latex_formula2svg(latex: str, font_size: int = 12):
|
|
|
174
179
|
return output.getvalue()
|
|
175
180
|
except Exception:
|
|
176
181
|
return None
|
|
177
|
-
|
|
182
|
+
|
|
178
183
|
|
|
179
184
|
def _wrap_asset_content(
|
|
180
185
|
context: Context,
|
|
@@ -182,7 +187,7 @@ def _wrap_asset_content(
|
|
|
182
187
|
content_element: Element,
|
|
183
188
|
inline_mode: bool = False,
|
|
184
189
|
) -> Element:
|
|
185
|
-
|
|
190
|
+
|
|
186
191
|
if inline_mode:
|
|
187
192
|
wrapper = Element("span", attrib={"class": "formula-inline"})
|
|
188
193
|
else:
|
|
@@ -16,7 +16,7 @@ from .gen_asset import render_asset_block
|
|
|
16
16
|
from .gen_content import render_inline_content
|
|
17
17
|
from .xml_utils import serialize_element, set_epub_type
|
|
18
18
|
|
|
19
|
-
_MAX_HEADING_LEVEL = 6
|
|
19
|
+
_MAX_HEADING_LEVEL = 6 # HTML standard defines heading levels from h1 to h6
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def generate_chapter(
|
|
@@ -28,15 +28,14 @@ def generate_chapter(
|
|
|
28
28
|
template="part.xhtml",
|
|
29
29
|
i18n=i18n,
|
|
30
30
|
content=[
|
|
31
|
-
serialize_element(child)
|
|
32
|
-
for child in _render_contents(context, chapter)
|
|
31
|
+
serialize_element(child) for child in _render_contents(context, chapter)
|
|
33
32
|
],
|
|
34
33
|
citations=[
|
|
35
|
-
serialize_element(child)
|
|
36
|
-
for child in _render_footnotes(context, chapter)
|
|
34
|
+
serialize_element(child) for child in _render_footnotes(context, chapter)
|
|
37
35
|
],
|
|
38
36
|
)
|
|
39
37
|
|
|
38
|
+
|
|
40
39
|
def _render_contents(
|
|
41
40
|
context: Context,
|
|
42
41
|
chapter: Chapter,
|
|
@@ -46,6 +45,7 @@ def _render_contents(
|
|
|
46
45
|
if layout is not None:
|
|
47
46
|
yield layout
|
|
48
47
|
|
|
48
|
+
|
|
49
49
|
def _render_footnotes(
|
|
50
50
|
context: Context,
|
|
51
51
|
chapter: Chapter,
|
|
@@ -115,6 +115,6 @@ def _render_content_block(context: Context, block: ContentBlock) -> Element | No
|
|
|
115
115
|
return blockquote
|
|
116
116
|
|
|
117
117
|
return container
|
|
118
|
-
|
|
118
|
+
|
|
119
119
|
else:
|
|
120
120
|
return None
|
|
@@ -6,9 +6,7 @@ from .xml_utils import set_epub_type
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def render_inline_content(
|
|
9
|
-
context: Context,
|
|
10
|
-
parent: Element,
|
|
11
|
-
content: list[str | Mark | Formula | HTMLTag]
|
|
9
|
+
context: Context, parent: Element, content: list[str | Mark | Formula | HTMLTag]
|
|
12
10
|
) -> None:
|
|
13
11
|
current_element = parent
|
|
14
12
|
for item in content:
|
|
@@ -31,6 +29,7 @@ def render_inline_content(
|
|
|
31
29
|
|
|
32
30
|
elif isinstance(item, Formula):
|
|
33
31
|
from .gen_asset import render_inline_formula # avoid circular import
|
|
32
|
+
|
|
34
33
|
formula_element = render_inline_formula(context, item)
|
|
35
34
|
if formula_element is not None:
|
|
36
35
|
parent.append(formula_element)
|
|
@@ -56,4 +55,4 @@ def render_html_tag(context: Context, tag: HTMLTag) -> Element:
|
|
|
56
55
|
for attr, value in tag.attributes:
|
|
57
56
|
element.set(attr, value)
|
|
58
57
|
render_inline_content(context, element, tag.content)
|
|
59
|
-
return element
|
|
58
|
+
return element
|
|
@@ -6,14 +6,14 @@ from uuid import uuid4
|
|
|
6
6
|
from zipfile import ZipFile
|
|
7
7
|
|
|
8
8
|
from ..context import Context, Template
|
|
9
|
-
from ..html_tag import search_content
|
|
10
9
|
from ..i18n import I18N
|
|
11
10
|
from ..options import LaTeXRender, TableRender
|
|
12
|
-
from ..types import
|
|
11
|
+
from ..types import EpubData
|
|
13
12
|
from ..validate import validate_chapter, validate_epub_data
|
|
14
13
|
from .gen_chapter import generate_chapter
|
|
15
14
|
from .gen_nav import gen_nav
|
|
16
15
|
from .gen_toc import TocPoint, gen_toc, iter_toc
|
|
16
|
+
from .xml_utils import MATHML_NS
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def generate_epub(
|
|
@@ -125,7 +125,7 @@ def _write_chapters_from_data(
|
|
|
125
125
|
zinfo_or_arcname="OEBPS/Text/" + file_name,
|
|
126
126
|
data=data.encode("utf-8"),
|
|
127
127
|
)
|
|
128
|
-
if latex_render == LaTeXRender.MATHML and
|
|
128
|
+
if latex_render == LaTeXRender.MATHML and MATHML_NS in data:
|
|
129
129
|
context.mark_chapter_has_mathml(file_name)
|
|
130
130
|
assert_not_aborted()
|
|
131
131
|
|
|
@@ -137,34 +137,6 @@ def _search_chapters(epub_data: EpubData, toc_points: list[TocPoint]):
|
|
|
137
137
|
yield ref.file_name, ref.get_chapter
|
|
138
138
|
|
|
139
139
|
|
|
140
|
-
def _chapter_has_formula(chapter: Chapter) -> bool:
|
|
141
|
-
for element in chapter.elements:
|
|
142
|
-
if _content_block_has_formula(element):
|
|
143
|
-
return True
|
|
144
|
-
for footnote in chapter.footnotes:
|
|
145
|
-
for content_block in footnote.contents:
|
|
146
|
-
if _content_block_has_formula(content_block):
|
|
147
|
-
return True
|
|
148
|
-
return False
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
def _content_block_has_formula(content_block: ContentBlock) -> bool:
|
|
152
|
-
if isinstance(content_block, Formula):
|
|
153
|
-
return True
|
|
154
|
-
if isinstance(content_block, TextBlock):
|
|
155
|
-
for item in search_content(content_block.content):
|
|
156
|
-
if isinstance(item, Formula):
|
|
157
|
-
return True
|
|
158
|
-
if isinstance(content_block, BasicAsset):
|
|
159
|
-
for item in search_content(content_block.title):
|
|
160
|
-
if isinstance(item, Formula):
|
|
161
|
-
return True
|
|
162
|
-
for item in search_content(content_block.caption):
|
|
163
|
-
if isinstance(item, Formula):
|
|
164
|
-
return True
|
|
165
|
-
return False
|
|
166
|
-
|
|
167
|
-
|
|
168
140
|
def _write_basic_files(
|
|
169
141
|
context: Context,
|
|
170
142
|
i18n: I18N,
|
|
@@ -21,6 +21,7 @@ class TocPoint:
|
|
|
21
21
|
"""是否有对应的 XHTML 文件"""
|
|
22
22
|
return self.ref is not None
|
|
23
23
|
|
|
24
|
+
|
|
24
25
|
@dataclass
|
|
25
26
|
class TocPointRef:
|
|
26
27
|
part_id: str
|
|
@@ -40,10 +41,7 @@ def gen_toc(epub_data: EpubData) -> list[TocPoint]:
|
|
|
40
41
|
chapters = epub_data.chapters
|
|
41
42
|
|
|
42
43
|
toc_point_generation = _TocPointGenerator(
|
|
43
|
-
chapters_count=(
|
|
44
|
-
_count_toc_items(prefaces) +
|
|
45
|
-
_count_toc_items(chapters)
|
|
46
|
-
),
|
|
44
|
+
chapters_count=(_count_toc_items(prefaces) + _count_toc_items(chapters)),
|
|
47
45
|
)
|
|
48
46
|
toc_points: list[TocPoint] = []
|
|
49
47
|
for chapters_list in (prefaces, chapters):
|
|
@@ -91,15 +89,12 @@ class _TocPointGenerator:
|
|
|
91
89
|
file_name=f"part{part_id}.xhtml",
|
|
92
90
|
get_chapter=toc_item.get_chapter,
|
|
93
91
|
)
|
|
94
|
-
order = self._next_order
|
|
92
|
+
order = self._next_order # 确保 order 以中序遍历为顺序
|
|
95
93
|
self._next_order += 1
|
|
96
94
|
|
|
97
95
|
return TocPoint(
|
|
98
|
-
title=toc_item.title,
|
|
96
|
+
title=toc_item.title,
|
|
99
97
|
order=order,
|
|
100
|
-
ref=ref,
|
|
101
|
-
children=[
|
|
102
|
-
self._create_toc_point(child)
|
|
103
|
-
for child in toc_item.children
|
|
104
|
-
],
|
|
98
|
+
ref=ref,
|
|
99
|
+
children=[self._create_toc_point(child) for child in toc_item.children],
|
|
105
100
|
)
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from xml.etree.ElementTree import Element, tostring
|
|
3
3
|
|
|
4
|
+
MATHML_NS = "http://www.w3.org/1998/Math/MathML"
|
|
4
5
|
_EPUB_NS = "http://www.idpf.org/2007/ops"
|
|
5
|
-
_MATHML_NS = "http://www.w3.org/1998/Math/MathML"
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def set_epub_type(element: Element, epub_type: str) -> None:
|
|
9
9
|
element.set(f"{{{_EPUB_NS}}}type", epub_type)
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
def serialize_element(element: Element) -> str:
|
|
12
13
|
xml_string = tostring(element, encoding="unicode")
|
|
13
14
|
for prefix, namespace_uri, keep_xmlns in (
|
|
14
15
|
("epub", _EPUB_NS, False), # EPUB namespace: remove xmlns (declared at root)
|
|
15
|
-
("m",
|
|
16
|
+
("m", MATHML_NS, True), # MathML namespace: keep xmlns with clean prefix
|
|
16
17
|
):
|
|
17
18
|
xml_string = xml_string.replace(f"{{{namespace_uri}}}", f"{prefix}:")
|
|
18
19
|
pattern = r"xmlns:(ns\d+)=\"" + re.escape(namespace_uri) + r"\""
|
|
@@ -21,15 +22,18 @@ def serialize_element(element: Element) -> str:
|
|
|
21
22
|
for ns_prefix in matches:
|
|
22
23
|
if keep_xmlns:
|
|
23
24
|
xml_string = xml_string.replace(
|
|
24
|
-
f
|
|
25
|
-
f
|
|
25
|
+
f' xmlns:{ns_prefix}="{namespace_uri}"',
|
|
26
|
+
f' xmlns:{prefix}="{namespace_uri}"',
|
|
26
27
|
)
|
|
27
28
|
else:
|
|
28
|
-
xml_string = xml_string.replace(
|
|
29
|
+
xml_string = xml_string.replace(
|
|
30
|
+
f' xmlns:{ns_prefix}="{namespace_uri}"', ""
|
|
31
|
+
)
|
|
29
32
|
xml_string = xml_string.replace(f"{ns_prefix}:", f"{prefix}:")
|
|
30
33
|
|
|
31
34
|
return xml_string
|
|
32
35
|
|
|
36
|
+
|
|
33
37
|
def indent(elem: Element, level: int = 0) -> Element:
|
|
34
38
|
indent_str = " " * level
|
|
35
39
|
next_indent_str = " " * (level + 1)
|
epub_generator/html_tag.py
CHANGED
|
@@ -3,9 +3,11 @@ from typing import Generator
|
|
|
3
3
|
from .types import Formula, HTMLTag, Mark
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def search_content(
|
|
6
|
+
def search_content(
|
|
7
|
+
content: list[str | Mark | Formula | HTMLTag],
|
|
8
|
+
) -> Generator[str | Mark | Formula, None, None]:
|
|
7
9
|
for child in content:
|
|
8
10
|
if isinstance(child, HTMLTag):
|
|
9
11
|
yield from search_content(child.content)
|
|
10
12
|
else:
|
|
11
|
-
yield child
|
|
13
|
+
yield child
|
epub_generator/types.py
CHANGED
|
@@ -24,6 +24,7 @@ class EpubData:
|
|
|
24
24
|
cover_image_path: Path | None = None
|
|
25
25
|
"""Cover image file path (optional, absolute path)"""
|
|
26
26
|
|
|
27
|
+
|
|
27
28
|
@dataclass
|
|
28
29
|
class BookMeta:
|
|
29
30
|
"""Book metadata information."""
|
|
@@ -57,9 +58,11 @@ class BookMeta:
|
|
|
57
58
|
# Table of Contents structure
|
|
58
59
|
# ============================================================================
|
|
59
60
|
|
|
61
|
+
|
|
60
62
|
@dataclass
|
|
61
63
|
class TocItem:
|
|
62
64
|
"""Table of contents item with title, content, and optional nested children."""
|
|
65
|
+
|
|
63
66
|
title: str
|
|
64
67
|
"""Chapter title displayed in table of contents"""
|
|
65
68
|
|
|
@@ -69,6 +72,7 @@ class TocItem:
|
|
|
69
72
|
children: "list[TocItem]" = field(default_factory=list)
|
|
70
73
|
"""Nested sub-chapters (recursive, optional)"""
|
|
71
74
|
|
|
75
|
+
|
|
72
76
|
class TextKind(Enum):
|
|
73
77
|
BODY = "body"
|
|
74
78
|
"""Regular paragraph."""
|
|
@@ -77,21 +81,29 @@ class TextKind(Enum):
|
|
|
77
81
|
QUOTE = "quote"
|
|
78
82
|
"""Quoted text."""
|
|
79
83
|
|
|
84
|
+
|
|
80
85
|
@dataclass
|
|
81
86
|
class Mark:
|
|
82
87
|
"""Citation reference marker."""
|
|
88
|
+
|
|
83
89
|
id: int
|
|
84
90
|
"""Citation ID, matches Footnote.id"""
|
|
85
91
|
|
|
92
|
+
|
|
86
93
|
@dataclass
|
|
87
94
|
class BasicAsset:
|
|
88
95
|
"""Asset as a base class for other assets."""
|
|
89
96
|
|
|
90
|
-
title: list["str | Mark | Formula | HTMLTag"] = field(
|
|
97
|
+
title: list["str | Mark | Formula | HTMLTag"] = field(
|
|
98
|
+
default_factory=list, kw_only=True
|
|
99
|
+
)
|
|
91
100
|
"""Asset title (before content)"""
|
|
92
|
-
caption: list["str | Mark | Formula | HTMLTag"] = field(
|
|
101
|
+
caption: list["str | Mark | Formula | HTMLTag"] = field(
|
|
102
|
+
default_factory=list, kw_only=True
|
|
103
|
+
)
|
|
93
104
|
"""Asset caption (after content)"""
|
|
94
105
|
|
|
106
|
+
|
|
95
107
|
@dataclass
|
|
96
108
|
class Table(BasicAsset):
|
|
97
109
|
"""Table representation."""
|
|
@@ -115,6 +127,7 @@ class Image(BasicAsset):
|
|
|
115
127
|
path: Path
|
|
116
128
|
"""Absolute path to the image file"""
|
|
117
129
|
|
|
130
|
+
|
|
118
131
|
@dataclass
|
|
119
132
|
class TextBlock:
|
|
120
133
|
"""Text block representation."""
|
|
@@ -126,9 +139,11 @@ class TextBlock:
|
|
|
126
139
|
content: list["str | Mark | Formula | HTMLTag"]
|
|
127
140
|
"""Text content with optional citation marks."""
|
|
128
141
|
|
|
142
|
+
|
|
129
143
|
@dataclass
|
|
130
144
|
class Footnote:
|
|
131
145
|
"""Footnote/citation section."""
|
|
146
|
+
|
|
132
147
|
id: int
|
|
133
148
|
"""Footnote ID"""
|
|
134
149
|
|
|
@@ -142,17 +157,21 @@ class Footnote:
|
|
|
142
157
|
ContentBlock = TextBlock | Table | Formula | Image
|
|
143
158
|
"""Union of all content blocks that appear in main chapter content."""
|
|
144
159
|
|
|
160
|
+
|
|
145
161
|
@dataclass
|
|
146
162
|
class Chapter:
|
|
147
163
|
"""Complete content of a single chapter."""
|
|
164
|
+
|
|
148
165
|
elements: list[ContentBlock] = field(default_factory=list)
|
|
149
166
|
"""Main content blocks"""
|
|
150
167
|
|
|
151
168
|
footnotes: list[Footnote] = field(default_factory=list)
|
|
152
169
|
"""Footnotes"""
|
|
153
170
|
|
|
171
|
+
|
|
154
172
|
ChapterGetter = Callable[[], Chapter]
|
|
155
173
|
|
|
174
|
+
|
|
156
175
|
@dataclass
|
|
157
176
|
class HTMLTag:
|
|
158
177
|
"""Generic HTML tag representation."""
|
|
@@ -164,4 +183,4 @@ class HTMLTag:
|
|
|
164
183
|
"""List of (attribute, value) pairs"""
|
|
165
184
|
|
|
166
185
|
content: list["str | Mark | Formula | HTMLTag"] = field(default_factory=list)
|
|
167
|
-
"""Inner HTML content"""
|
|
186
|
+
"""Inner HTML content"""
|
epub_generator/validate.py
CHANGED
|
@@ -113,7 +113,9 @@ def _check_string(value: str | None, field_path: str) -> None:
|
|
|
113
113
|
)
|
|
114
114
|
|
|
115
115
|
|
|
116
|
-
def _check_string_list(
|
|
116
|
+
def _check_string_list(
|
|
117
|
+
values: list[str | Mark | Formula | HTMLTag], field_path: str
|
|
118
|
+
) -> None:
|
|
117
119
|
"""Recursively check a list that may contain strings, marks, formulas, or HTML tags.
|
|
118
120
|
|
|
119
121
|
Args:
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
epub_generator/__init__.py,sha256=G1P_GAUym94iv56PPK31641vlYrukUoMJZgWtmKscog,768
|
|
2
|
+
epub_generator/context.py,sha256=oS39IdttvQ2MR_jJS2DTG62YMbZtYr2c7iQ1jpyc9Rg,4324
|
|
3
|
+
epub_generator/data/container.xml.jinja,sha256=SkACyZgsAVUS5lmiCEhq3SpbFspYdyCnRNjWnLztLt0,252
|
|
4
|
+
epub_generator/data/content.opf.jinja,sha256=DDaR9GZnSBcpNk2BWUu56Uo_248TA91AxE4tKsBuKnQ,2839
|
|
5
|
+
epub_generator/data/cover.xhtml.jinja,sha256=heounlnHfOd-RNFIeytZQtAQ11ByPOiM1aB1lVyY6V4,328
|
|
6
|
+
epub_generator/data/mimetype.jinja,sha256=5GjjUNEUPrZI9gx7C9YDEQHsBUSjYcp07O8laskB9Is,20
|
|
7
|
+
epub_generator/data/nav.xhtml.jinja,sha256=zk5hf-MYoKxd4pcshZV5VliVrtDIgfH7n9f3-1L1cY0,1132
|
|
8
|
+
epub_generator/data/part.xhtml.jinja,sha256=FEQaUjHfCy7EJyyvYZj-6T-lkDcsmz1wvsk0b8LU3E0,558
|
|
9
|
+
epub_generator/data/style.css.jinja,sha256=n_DE-z97ikGzD3qufSwX_1iqkQcE_5kXiCIhyoXNjRA,1400
|
|
10
|
+
epub_generator/generation/__init__.py,sha256=tqkUQbu27fU2JZWpg17THnZzoIfCTelE0i70gmaPT6Q,36
|
|
11
|
+
epub_generator/generation/gen_asset.py,sha256=xJOtJrdrh_y0g78AoqxyES_s5g2cD-DY2I0bgLWQWHk,5975
|
|
12
|
+
epub_generator/generation/gen_chapter.py,sha256=UrnzjEcPIACYNrjM84AkgyidAg128y_V2n5HrcD1Egs,3400
|
|
13
|
+
epub_generator/generation/gen_content.py,sha256=QqUhfGyXOJ1_lf4aLrYyoZxbew5wChz-qegcsmNHgJs,2012
|
|
14
|
+
epub_generator/generation/gen_epub.py,sha256=Sd8tC-3GhBN90EF2IOlHnhUT9-yfcA3KqhQ3BQ9V4jo,5435
|
|
15
|
+
epub_generator/generation/gen_nav.py,sha256=_cjOP18C1CoTn_DELIB06pyMPZZ0CPbkk4oPEvICdKs,1955
|
|
16
|
+
epub_generator/generation/gen_toc.py,sha256=8pe06atBNDbrMcn32nGtV5NVYqAksuW9Z5KK1C8j6Ys,2784
|
|
17
|
+
epub_generator/generation/xml_utils.py,sha256=Ugbdj_2HUoTZz5LgrYviYVq1MPTL9KWMkruRCQbR4Ys,1852
|
|
18
|
+
epub_generator/html_tag.py,sha256=NmBgeUOHXsS8a74Z5O47iYDTsErW61BJiwyEEOfdyWQ,351
|
|
19
|
+
epub_generator/i18n.py,sha256=-L6J6hsy796_IQ4nLpNtAeXIkRM6oFSWSHDlRZXW8aA,705
|
|
20
|
+
epub_generator/options.py,sha256=Er1dnaNvzDSnZRSRJGSqhkJsv1XtsCW2Ym_hUc8o_QI,181
|
|
21
|
+
epub_generator/template.py,sha256=RdN2QRICIrYMzpxCU_x4m4V9WWZEP9VvT6QLp2YCm90,1556
|
|
22
|
+
epub_generator/types.py,sha256=O1PX8pGq1fyEiLA8gQ8Jaq1ldG5w3mYV7sCgTZowaDI,4484
|
|
23
|
+
epub_generator/validate.py,sha256=iZkHH5Xl_U5hGHusytb4sIQTomqI0BMHjKZL06c9lrI,7550
|
|
24
|
+
epub_generator-0.1.7.dist-info/LICENSE,sha256=9Zt_a4mrzkvR2rc0UbqTgbboIjWuumDFgeQyKos0H2E,1066
|
|
25
|
+
epub_generator-0.1.7.dist-info/METADATA,sha256=_RPI7Q8ixvTjibSkNFvnJ-oIPo25iuVkAHisTsjo3mw,16555
|
|
26
|
+
epub_generator-0.1.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
27
|
+
epub_generator-0.1.7.dist-info/RECORD,,
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
epub_generator/__init__.py,sha256=G1P_GAUym94iv56PPK31641vlYrukUoMJZgWtmKscog,768
|
|
2
|
-
epub_generator/context.py,sha256=9jHRpnQsNooRUSBoY_tiQ7aQ_AMZmyKUO22gPoO8Koc,4324
|
|
3
|
-
epub_generator/data/container.xml.jinja,sha256=SkACyZgsAVUS5lmiCEhq3SpbFspYdyCnRNjWnLztLt0,252
|
|
4
|
-
epub_generator/data/content.opf.jinja,sha256=DDaR9GZnSBcpNk2BWUu56Uo_248TA91AxE4tKsBuKnQ,2839
|
|
5
|
-
epub_generator/data/cover.xhtml.jinja,sha256=heounlnHfOd-RNFIeytZQtAQ11ByPOiM1aB1lVyY6V4,328
|
|
6
|
-
epub_generator/data/mimetype.jinja,sha256=5GjjUNEUPrZI9gx7C9YDEQHsBUSjYcp07O8laskB9Is,20
|
|
7
|
-
epub_generator/data/nav.xhtml.jinja,sha256=zk5hf-MYoKxd4pcshZV5VliVrtDIgfH7n9f3-1L1cY0,1132
|
|
8
|
-
epub_generator/data/part.xhtml.jinja,sha256=FEQaUjHfCy7EJyyvYZj-6T-lkDcsmz1wvsk0b8LU3E0,558
|
|
9
|
-
epub_generator/data/style.css.jinja,sha256=n_DE-z97ikGzD3qufSwX_1iqkQcE_5kXiCIhyoXNjRA,1400
|
|
10
|
-
epub_generator/generation/__init__.py,sha256=UIscwHa8ocr2D1mk1KaP-zi3P1x9eYJzxTo0RJ2dnks,35
|
|
11
|
-
epub_generator/generation/gen_asset.py,sha256=WYwfGUvHM_CrwTuIIH7dYm-SL-vdhkTnvaZDymZxXzg,5978
|
|
12
|
-
epub_generator/generation/gen_chapter.py,sha256=P6kmB8hdQnJB6SCheHzu5cOmZrC5H0LqNV-uuuigX1M,3425
|
|
13
|
-
epub_generator/generation/gen_content.py,sha256=2ojjTgalveRnk1MXQaKsY53hPCgb7NHTwbMpLOXVrss,2018
|
|
14
|
-
epub_generator/generation/gen_epub.py,sha256=rxHBp4nP5OFi9SJBfiCrncV1fmhb0j3WKfUqofxJykc,6487
|
|
15
|
-
epub_generator/generation/gen_nav.py,sha256=_cjOP18C1CoTn_DELIB06pyMPZZ0CPbkk4oPEvICdKs,1955
|
|
16
|
-
epub_generator/generation/gen_toc.py,sha256=MK2iTYBpF8VUtPHpwz5JB_H6nWsKRKpVuLzRPYGy0nw,2864
|
|
17
|
-
epub_generator/generation/xml_utils.py,sha256=AVnU3AN6lmqWrdgaZTV7v77L9LonI7DX59BxkMZlef8,1822
|
|
18
|
-
epub_generator/html_tag.py,sha256=P_Y0uRStCEEh7cCtpvK4t432NEcY9OLntAznvdxUF5k,343
|
|
19
|
-
epub_generator/i18n.py,sha256=-L6J6hsy796_IQ4nLpNtAeXIkRM6oFSWSHDlRZXW8aA,705
|
|
20
|
-
epub_generator/options.py,sha256=Er1dnaNvzDSnZRSRJGSqhkJsv1XtsCW2Ym_hUc8o_QI,181
|
|
21
|
-
epub_generator/template.py,sha256=RdN2QRICIrYMzpxCU_x4m4V9WWZEP9VvT6QLp2YCm90,1556
|
|
22
|
-
epub_generator/types.py,sha256=gBrdi1KYOVEnI0qEp1slLsyUw_Sd7v09uHvN8_Hf9Z8,4440
|
|
23
|
-
epub_generator/validate.py,sha256=KBgvBsBuVnWTc4N-29cr2P92X0w_tGR4pMemk_KHy78,7544
|
|
24
|
-
epub_generator-0.1.6.dist-info/LICENSE,sha256=9Zt_a4mrzkvR2rc0UbqTgbboIjWuumDFgeQyKos0H2E,1066
|
|
25
|
-
epub_generator-0.1.6.dist-info/METADATA,sha256=JziMt9LukPRKo8rPy10qf9sIiiv98CgSxKoi7juHcYE,16555
|
|
26
|
-
epub_generator-0.1.6.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
27
|
-
epub_generator-0.1.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|