epub-blocks 0.1.0__tar.gz

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,11 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented here. The project uses
4
+ [Semantic Versioning](https://semver.org/).
5
+
6
+ ## Unreleased
7
+
8
+ ## 0.1.0 - 2026-09-04
9
+
10
+ - Initial public release of EPUB inspection, block discovery, versioned
11
+ extraction recipes, TSV output, safety limits, and validation.
@@ -0,0 +1,36 @@
1
+ # Contributing
2
+
3
+ `epub-blocks` requires Python 3.13 or later and uses
4
+ [uv](https://docs.astral.sh/uv/) for its development environment.
5
+
6
+ ## Set up the project
7
+
8
+ ```bash
9
+ git clone https://github.com/jtauber/epub-blocks.git
10
+ cd epub-blocks
11
+ uv sync
12
+ ```
13
+
14
+ ## Check a change
15
+
16
+ Run the same checks used by continuous integration:
17
+
18
+ ```bash
19
+ uv run ruff check .
20
+ uv run pyright
21
+ uv run coverage erase
22
+ uv run coverage run -m unittest discover -s tests
23
+ uv run coverage report
24
+ uv run python -m build
25
+ uv run twine check dist/*
26
+ uv run pyright --verifytypes epub_blocks --ignoreexternal
27
+ ```
28
+
29
+ New behavior and bug fixes should include tests. Tests create conforming EPUB
30
+ fixtures in temporary directories; do not commit copyrighted EPUB files.
31
+
32
+ Please open an issue before proposing an incompatible recipe-format or public
33
+ API change. Recipe version 1 readers intentionally reject unknown fields, so
34
+ an incompatible semantic change needs a new recipe version.
35
+
36
+ See the [release checklist](docs/releasing.md) for the packaging process.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 James Tauber
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,6 @@
1
+ include CHANGELOG.md
2
+ include CONTRIBUTING.md
3
+ include LICENSE
4
+ include README.md
5
+ recursive-include docs *.md
6
+ recursive-include schemas *.json
@@ -0,0 +1,189 @@
1
+ Metadata-Version: 2.4
2
+ Name: epub-blocks
3
+ Version: 0.1.0
4
+ Summary: Recipe-driven extraction of structured text blocks from EPUB files
5
+ Author: James Tauber
6
+ License-Expression: MIT
7
+ Project-URL: Documentation, https://github.com/jtauber/epub-blocks#readme
8
+ Project-URL: Issues, https://github.com/jtauber/epub-blocks/issues
9
+ Project-URL: Repository, https://github.com/jtauber/epub-blocks
10
+ Keywords: epub,text extraction,digital humanities
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Typing :: Typed
17
+ Classifier: Topic :: Text Processing
18
+ Requires-Python: >=3.13
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Dynamic: license-file
22
+
23
+ # epub-blocks
24
+
25
+ `epub-blocks` is a small, dependency-free Python library for recipe-driven
26
+ extraction of ordered text blocks from EPUB 2 and EPUB 3 containers. It
27
+ also exposes locator-bearing source blocks so that consuming projects can
28
+ prepare and review recipes reproducibly.
29
+
30
+ It requires Python 3.13 or later.
31
+
32
+ This project is at an early 0.x stage. Its public API and recipe format may
33
+ evolve before 1.0.
34
+
35
+ ## Installation
36
+
37
+ Install the 0.1.0 release directly from GitHub:
38
+
39
+ ```bash
40
+ python -m pip install "git+https://github.com/jtauber/epub-blocks.git@v0.1.0"
41
+ ```
42
+
43
+ For development, install from a local checkout:
44
+
45
+ ```bash
46
+ python -m pip install .
47
+ ```
48
+
49
+ The runtime package has no third-party dependencies.
50
+
51
+ ## Scope
52
+
53
+ The package handles the reusable EPUB layer:
54
+
55
+ - locating and parsing the EPUB package document;
56
+ - reading identifiers and the XHTML spine;
57
+ - excluding auxiliary `linear="no"` spine items by default;
58
+ - selecting spine documents with case-insensitive glob patterns;
59
+ - extracting paragraph, heading, quotation, list-item, and preformatted text
60
+ blocks with stable source locators;
61
+ - excluding document paths, element locators, CSS classes, page-breaks, and
62
+ note references; and
63
+ - selecting, omitting, slicing, joining, and normalizing XHTML fragments;
64
+ - applying explicit extraction recipes to produce `id`, `type`, and `text`
65
+ records; and
66
+ - writing those records as headerless TSV files.
67
+
68
+ It deliberately leaves the interpretation and downstream use of extracted
69
+ records to consuming projects.
70
+
71
+ ## Example
72
+
73
+ ```python
74
+ from pathlib import Path
75
+
76
+ from epub_blocks import extract_blocks
77
+
78
+ blocks = extract_blocks(
79
+ Path("book.epub"),
80
+ include_documents=["*chapter*.xhtml"],
81
+ exclude_classes=["image-caption"],
82
+ )
83
+
84
+ for block in blocks:
85
+ print(block.source_locator, block.tag, block.text)
86
+ ```
87
+
88
+ `source_locator` has the form
89
+ `s008:text/chapter-01.xhtml#1.3.2`. Element-path components are one-based child
90
+ positions within the XHTML `body`.
91
+
92
+ ## Extraction recipes
93
+
94
+ An extraction recipe pins the EPUB identity and explicitly maps output blocks
95
+ to XHTML fragments:
96
+
97
+ ```json
98
+ {
99
+ "recipe_version": "1",
100
+ "epub": {
101
+ "identifier": "9780000000000",
102
+ "sha256": "f4f9c2d902a41b80732b2dce7ad01a57f615859c21417a5019e3cd8e4d271282"
103
+ },
104
+ "normalization": {
105
+ "collapse_whitespace": true,
106
+ "strip": true,
107
+ "unicode_normalization": "NFC"
108
+ },
109
+ "omit_epub_types": ["noteref", "pagebreak"],
110
+ "blocks": [
111
+ {
112
+ "id": "01.001",
113
+ "type": "{p}",
114
+ "parts": [
115
+ {
116
+ "document": "text/chapter-01.xhtml",
117
+ "element_path": "1.3.2"
118
+ }
119
+ ]
120
+ }
121
+ ]
122
+ }
123
+ ```
124
+
125
+ The command-line interface writes a three-column, headerless TSV containing
126
+ the identifier, type, and text of each extracted record:
127
+
128
+ ```bash
129
+ epub-blocks book.epub recipe.json records.tsv
130
+ ```
131
+
132
+ Identifiers and types are opaque strings chosen by the recipe. See the
133
+ [complete recipe format](https://github.com/jtauber/epub-blocks/blob/main/docs/recipe-format.md)
134
+ for the full field reference, locator and slicing semantics, normalization
135
+ order, validation rules, and worked examples. A strict
136
+ [JSON Schema](https://github.com/jtauber/epub-blocks/blob/main/schemas/recipe-v1.schema.json)
137
+ is also available for editor and pipeline integration.
138
+
139
+ ## Safety and trust model
140
+
141
+ EPUB files are untrusted ZIP and XML input. The default extraction APIs bound
142
+ archive membership, individual and cumulative reads, compression ratios, XML
143
+ document size, element count, and nesting depth. Duplicate or unsafe archive
144
+ paths, encrypted members, external or internal DTDs, and entity declarations
145
+ are rejected. The declaration-only HTML5 `<!DOCTYPE html>` is permitted.
146
+ Custom positive limits can be supplied with `SafetyLimits` when a legitimate
147
+ book is larger than a default.
148
+
149
+ These checks reduce resource-exhaustion and ambiguity risks; they are not a
150
+ sandbox for arbitrary code. The package does not execute EPUB scripts or fetch
151
+ network resources.
152
+
153
+ ## Public API
154
+
155
+ The supported import surface is the names exported by `epub_blocks`: the
156
+ result and option data classes, `SafetyLimits`, `inspect_epub`,
157
+ `extract_blocks`, the recipe-loading and extraction functions, `write_tsv`,
158
+ and `EpubBlocksError`. Helpers in submodules are implementation details and
159
+ may change during the pre-1.0 period.
160
+
161
+ ## Development
162
+
163
+ ```bash
164
+ uv sync
165
+ uv run coverage run -m unittest discover -s tests
166
+ uv run coverage report
167
+ uv run ruff check .
168
+ uv run pyright
169
+ uv run python -m build
170
+ uv run twine check dist/*
171
+ uv run pyright --verifytypes epub_blocks --ignoreexternal
172
+ ```
173
+
174
+ Coverage includes branch measurement and enforces a 90% minimum. Run
175
+ `uv run coverage html` after the test command for a browsable report in
176
+ `htmlcov/`.
177
+
178
+ No EPUB files are committed to this repository. Tests construct small synthetic
179
+ EPUB containers in temporary directories.
180
+
181
+ See [CONTRIBUTING.md](https://github.com/jtauber/epub-blocks/blob/main/CONTRIBUTING.md)
182
+ for the complete check sequence and change policy, and
183
+ [CHANGELOG.md](https://github.com/jtauber/epub-blocks/blob/main/CHANGELOG.md)
184
+ for release notes. Bugs and proposals are tracked in the
185
+ [issue tracker](https://github.com/jtauber/epub-blocks/issues).
186
+
187
+ ## License
188
+
189
+ `epub-blocks` is available under the [MIT License](LICENSE).
@@ -0,0 +1,167 @@
1
+ # epub-blocks
2
+
3
+ `epub-blocks` is a small, dependency-free Python library for recipe-driven
4
+ extraction of ordered text blocks from EPUB 2 and EPUB 3 containers. It
5
+ also exposes locator-bearing source blocks so that consuming projects can
6
+ prepare and review recipes reproducibly.
7
+
8
+ It requires Python 3.13 or later.
9
+
10
+ This project is at an early 0.x stage. Its public API and recipe format may
11
+ evolve before 1.0.
12
+
13
+ ## Installation
14
+
15
+ Install the 0.1.0 release directly from GitHub:
16
+
17
+ ```bash
18
+ python -m pip install "git+https://github.com/jtauber/epub-blocks.git@v0.1.0"
19
+ ```
20
+
21
+ For development, install from a local checkout:
22
+
23
+ ```bash
24
+ python -m pip install .
25
+ ```
26
+
27
+ The runtime package has no third-party dependencies.
28
+
29
+ ## Scope
30
+
31
+ The package handles the reusable EPUB layer:
32
+
33
+ - locating and parsing the EPUB package document;
34
+ - reading identifiers and the XHTML spine;
35
+ - excluding auxiliary `linear="no"` spine items by default;
36
+ - selecting spine documents with case-insensitive glob patterns;
37
+ - extracting paragraph, heading, quotation, list-item, and preformatted text
38
+ blocks with stable source locators;
39
+ - excluding document paths, element locators, CSS classes, page-breaks, and
40
+ note references; and
41
+ - selecting, omitting, slicing, joining, and normalizing XHTML fragments;
42
+ - applying explicit extraction recipes to produce `id`, `type`, and `text`
43
+ records; and
44
+ - writing those records as headerless TSV files.
45
+
46
+ It deliberately leaves the interpretation and downstream use of extracted
47
+ records to consuming projects.
48
+
49
+ ## Example
50
+
51
+ ```python
52
+ from pathlib import Path
53
+
54
+ from epub_blocks import extract_blocks
55
+
56
+ blocks = extract_blocks(
57
+ Path("book.epub"),
58
+ include_documents=["*chapter*.xhtml"],
59
+ exclude_classes=["image-caption"],
60
+ )
61
+
62
+ for block in blocks:
63
+ print(block.source_locator, block.tag, block.text)
64
+ ```
65
+
66
+ `source_locator` has the form
67
+ `s008:text/chapter-01.xhtml#1.3.2`. Element-path components are one-based child
68
+ positions within the XHTML `body`.
69
+
70
+ ## Extraction recipes
71
+
72
+ An extraction recipe pins the EPUB identity and explicitly maps output blocks
73
+ to XHTML fragments:
74
+
75
+ ```json
76
+ {
77
+ "recipe_version": "1",
78
+ "epub": {
79
+ "identifier": "9780000000000",
80
+ "sha256": "f4f9c2d902a41b80732b2dce7ad01a57f615859c21417a5019e3cd8e4d271282"
81
+ },
82
+ "normalization": {
83
+ "collapse_whitespace": true,
84
+ "strip": true,
85
+ "unicode_normalization": "NFC"
86
+ },
87
+ "omit_epub_types": ["noteref", "pagebreak"],
88
+ "blocks": [
89
+ {
90
+ "id": "01.001",
91
+ "type": "{p}",
92
+ "parts": [
93
+ {
94
+ "document": "text/chapter-01.xhtml",
95
+ "element_path": "1.3.2"
96
+ }
97
+ ]
98
+ }
99
+ ]
100
+ }
101
+ ```
102
+
103
+ The command-line interface writes a three-column, headerless TSV containing
104
+ the identifier, type, and text of each extracted record:
105
+
106
+ ```bash
107
+ epub-blocks book.epub recipe.json records.tsv
108
+ ```
109
+
110
+ Identifiers and types are opaque strings chosen by the recipe. See the
111
+ [complete recipe format](https://github.com/jtauber/epub-blocks/blob/main/docs/recipe-format.md)
112
+ for the full field reference, locator and slicing semantics, normalization
113
+ order, validation rules, and worked examples. A strict
114
+ [JSON Schema](https://github.com/jtauber/epub-blocks/blob/main/schemas/recipe-v1.schema.json)
115
+ is also available for editor and pipeline integration.
116
+
117
+ ## Safety and trust model
118
+
119
+ EPUB files are untrusted ZIP and XML input. The default extraction APIs bound
120
+ archive membership, individual and cumulative reads, compression ratios, XML
121
+ document size, element count, and nesting depth. Duplicate or unsafe archive
122
+ paths, encrypted members, external or internal DTDs, and entity declarations
123
+ are rejected. The declaration-only HTML5 `<!DOCTYPE html>` is permitted.
124
+ Custom positive limits can be supplied with `SafetyLimits` when a legitimate
125
+ book is larger than a default.
126
+
127
+ These checks reduce resource-exhaustion and ambiguity risks; they are not a
128
+ sandbox for arbitrary code. The package does not execute EPUB scripts or fetch
129
+ network resources.
130
+
131
+ ## Public API
132
+
133
+ The supported import surface is the names exported by `epub_blocks`: the
134
+ result and option data classes, `SafetyLimits`, `inspect_epub`,
135
+ `extract_blocks`, the recipe-loading and extraction functions, `write_tsv`,
136
+ and `EpubBlocksError`. Helpers in submodules are implementation details and
137
+ may change during the pre-1.0 period.
138
+
139
+ ## Development
140
+
141
+ ```bash
142
+ uv sync
143
+ uv run coverage run -m unittest discover -s tests
144
+ uv run coverage report
145
+ uv run ruff check .
146
+ uv run pyright
147
+ uv run python -m build
148
+ uv run twine check dist/*
149
+ uv run pyright --verifytypes epub_blocks --ignoreexternal
150
+ ```
151
+
152
+ Coverage includes branch measurement and enforces a 90% minimum. Run
153
+ `uv run coverage html` after the test command for a browsable report in
154
+ `htmlcov/`.
155
+
156
+ No EPUB files are committed to this repository. Tests construct small synthetic
157
+ EPUB containers in temporary directories.
158
+
159
+ See [CONTRIBUTING.md](https://github.com/jtauber/epub-blocks/blob/main/CONTRIBUTING.md)
160
+ for the complete check sequence and change policy, and
161
+ [CHANGELOG.md](https://github.com/jtauber/epub-blocks/blob/main/CHANGELOG.md)
162
+ for release notes. Bugs and proposals are tracked in the
163
+ [issue tracker](https://github.com/jtauber/epub-blocks/issues).
164
+
165
+ ## License
166
+
167
+ `epub-blocks` is available under the [MIT License](LICENSE).