dispose 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.
dispose-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 hiddendispatches
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 LICENSE README.md pyproject.toml
2
+ recursive-include src/dispose *
3
+ recursive-include tests *.py
4
+ prune src/dispose.egg-info
5
+ recursive-exclude * __pycache__ *.py[cod] .DS_Store
6
+ global-exclude install.sh sample.eml logo.png
dispose-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,213 @@
1
+ Metadata-Version: 2.4
2
+ Name: dispose
3
+ Version: 0.1.0
4
+ Summary: Local privacy classifier and redactor for sensitive files (emails, text, markdown, PDFs)
5
+ Author: hiddendispatches
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 hiddendispatches
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://codeberg.org/hiddendispatches/dispose
29
+ Project-URL: Repository, https://codeberg.org/hiddendispatches/dispose
30
+ Project-URL: Issues, https://codeberg.org/hiddendispatches/dispose/issues
31
+ Keywords: privacy,pii,redaction,classifier,cli,email
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Environment :: Console
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Operating System :: OS Independent
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3.9
39
+ Classifier: Programming Language :: Python :: 3.10
40
+ Classifier: Programming Language :: Python :: 3.11
41
+ Classifier: Programming Language :: Python :: 3.12
42
+ Classifier: Programming Language :: Python :: 3.13
43
+ Classifier: Topic :: Security
44
+ Classifier: Topic :: Text Processing :: Filters
45
+ Requires-Python: >=3.9
46
+ Description-Content-Type: text/markdown
47
+ License-File: LICENSE
48
+ Requires-Dist: click>=8.1
49
+ Requires-Dist: pypdf>=4.0
50
+ Provides-Extra: dev
51
+ Requires-Dist: pytest>=7.0; extra == "dev"
52
+ Requires-Dist: build; extra == "dev"
53
+ Requires-Dist: twine; extra == "dev"
54
+ Dynamic: license-file
55
+
56
+ # dispose
57
+
58
+ Local privacy classifier and redactor for sensitive files — text, markdown, email (`.eml`), and PDF.
59
+
60
+ Built for scrubbing **iCloud / personal email exports** before you feed them to an AI agent. Sensitive spans are replaced with `[REDACTED]`. Nothing is sent to OpenAI or any other network service.
61
+
62
+ **Source:** [codeberg.org/hiddendispatches/dispose](https://codeberg.org/hiddendispatches/dispose)
63
+
64
+ ## Install
65
+
66
+ Requires Python 3.9+.
67
+
68
+ ```bash
69
+ pip install dispose
70
+ ```
71
+
72
+ Then:
73
+
74
+ ```bash
75
+ dispose --version
76
+ dispose categories
77
+ ```
78
+
79
+ ### From source (contributors)
80
+
81
+ ```bash
82
+ git clone https://codeberg.org/hiddendispatches/dispose.git
83
+ cd dispose
84
+ pip install -e ".[dev]"
85
+ pytest
86
+ ```
87
+
88
+ ## Eight privacy categories
89
+
90
+ Same taxonomy as OpenAI Privacy Filter (without using their model or tool):
91
+
92
+ | Category | What gets redacted |
93
+ |---|---|
94
+ | `account_number` | SSNs, credit cards (Luhn), bank accounts, routing numbers, IBANs, labeled account / member / policy IDs |
95
+ | `private_address` | Street addresses, city/state/ZIP, PO boxes |
96
+ | `private_email` | Email addresses |
97
+ | `private_person` | Names in email headers, salutations, signatures |
98
+ | `private_phone` | Phone numbers |
99
+ | `private_url` | URLs and IP addresses (including iCloud / share links) |
100
+ | `private_date` | Dates, especially DOB-labeled dates |
101
+ | `secret` | Passwords, API keys, tokens, JWTs, PEM private keys |
102
+
103
+ Classifiers are deterministic pattern engines tuned for high recall on structured PII in correspondence. They run entirely offline.
104
+
105
+ ## Usage
106
+
107
+ ```bash
108
+ # List the eight categories
109
+ dispose categories
110
+
111
+ # Read an .eml: decode base64 / quoted-printable so you can actually read it
112
+ dispose view path/to/mail.eml
113
+ dispose decode path/to/mail.eml # alias for view
114
+ dispose view mail.eml --pager # open in less/more
115
+ dispose view mail.eml -o readable.txt # save decoded text
116
+
117
+ # Read decoded content AND redact privacy spans
118
+ dispose view mail.eml --redact
119
+ dispose view mail.eml --redact -o clean.txt
120
+
121
+ # Classify a file (report spans, do not write)
122
+ dispose classify path/to/email.eml
123
+ dispose classify ./exports --recursive --json
124
+
125
+ # Redact → writes path.redacted.ext by default
126
+ dispose redact path/to/notes.md
127
+ dispose redact ./icloud-export --recursive
128
+
129
+ # Print redacted text to stdout (pipe into an agent)
130
+ dispose redact message.eml --stdout
131
+
132
+ # Pipe / stdin
133
+ cat message.eml | dispose view -
134
+ cat message.eml | dispose redact -
135
+
136
+ # Overwrite in place (careful)
137
+ dispose redact sensitive.txt --in-place
138
+
139
+ # Only certain categories
140
+ dispose redact mail.eml -c private_email -c private_phone -c account_number
141
+
142
+ # Labeled placeholders: [REDACTED:private_email]
143
+ dispose redact mail.eml --label-categories
144
+
145
+ # OpenAI Privacy Filter-style alias
146
+ dispose filter mail.eml --stdout
147
+ ```
148
+
149
+ ### Supported inputs
150
+
151
+ - Text / markdown: `.txt`, `.md`, `.markdown`, `.rst`, `.log`, …
152
+ - Email: `.eml` (MIME-parsed into headers + body by default; **base64** and quoted-printable transfer encodings are decoded before redaction, including multipart bodies, nested messages, text attachments, and RFC 2047 headers)
153
+ - Structured text: `.csv`, `.json`, `.yaml`, `.html`, …
154
+ - PDF: `.pdf` (text is extracted, redacted, and written as a clean text PDF or plain text if you choose a non-`.pdf` output path)
155
+
156
+ ## Library use
157
+
158
+ ```python
159
+ from dispose import PrivacyPipeline
160
+
161
+ pipeline = PrivacyPipeline()
162
+ result = pipeline.redact(open("mail.eml").read())
163
+ print(result.redacted)
164
+ print(result.summary())
165
+ for span in result.spans:
166
+ print(span.category, span.text, span.score)
167
+ ```
168
+
169
+ ## Safety notes
170
+
171
+ - `dispose` is a **data minimization aid**, not a legal anonymization guarantee.
172
+ - Pattern classifiers can miss novel formats and can over-redact lookalikes.
173
+ - Review high-sensitivity outputs before sharing, even with an AI agent you trust.
174
+ - Prefer `--stdout` or a separate output directory over `--in-place` until you trust the result.
175
+
176
+ ## Releasing (maintainers)
177
+
178
+ Version lives only in `pyproject.toml`. Tag on Codeberg matches that version:
179
+
180
+ ```bash
181
+ # after bumping version in pyproject.toml
182
+ git tag -a v0.1.0 -m "dispose 0.1.0"
183
+ git push origin main --tags
184
+
185
+ pip install -e ".[dev]"
186
+ pytest
187
+ python -m build
188
+ python -m twine check dist/*
189
+ # TestPyPI, then PyPI (API token; username __token__)
190
+ twine upload --repository testpypi dist/*
191
+ twine upload dist/*
192
+ ```
193
+
194
+ PyPI does not require GitHub; Codeberg is the source host. Publish with a PyPI API token + `twine` (Trusted Publishing from Codeberg is not available yet).
195
+
196
+ ## License
197
+
198
+ MIT — see [LICENSE](LICENSE).
199
+
200
+ ## Contributions
201
+ If you found this package useful, please consider donating or supporting development as a solo founder I've been without gainful employment for years.
202
+
203
+ Donations
204
+ ```
205
+ SOL AH7TXdVn2ZddT7DALxSQz97AJBvweBXZdvV5vAojqgBy
206
+ ZEC BNB Chain 0xF7fE0DD3165053bD87217BF3e09041e123736175
207
+ TON/GRAM UQAnfI9jJj1iI5nxRcc0jXjrFtg41Ik7XvskB77mLNNMKwwK
208
+ ```
209
+
210
+ Dev Studio `https://6-castles.xyz`
211
+
212
+ Support `dispose-dev AT beconfidential DOT co`
213
+
@@ -0,0 +1,158 @@
1
+ # dispose
2
+
3
+ Local privacy classifier and redactor for sensitive files — text, markdown, email (`.eml`), and PDF.
4
+
5
+ Built for scrubbing **iCloud / personal email exports** before you feed them to an AI agent. Sensitive spans are replaced with `[REDACTED]`. Nothing is sent to OpenAI or any other network service.
6
+
7
+ **Source:** [codeberg.org/hiddendispatches/dispose](https://codeberg.org/hiddendispatches/dispose)
8
+
9
+ ## Install
10
+
11
+ Requires Python 3.9+.
12
+
13
+ ```bash
14
+ pip install dispose
15
+ ```
16
+
17
+ Then:
18
+
19
+ ```bash
20
+ dispose --version
21
+ dispose categories
22
+ ```
23
+
24
+ ### From source (contributors)
25
+
26
+ ```bash
27
+ git clone https://codeberg.org/hiddendispatches/dispose.git
28
+ cd dispose
29
+ pip install -e ".[dev]"
30
+ pytest
31
+ ```
32
+
33
+ ## Eight privacy categories
34
+
35
+ Same taxonomy as OpenAI Privacy Filter (without using their model or tool):
36
+
37
+ | Category | What gets redacted |
38
+ |---|---|
39
+ | `account_number` | SSNs, credit cards (Luhn), bank accounts, routing numbers, IBANs, labeled account / member / policy IDs |
40
+ | `private_address` | Street addresses, city/state/ZIP, PO boxes |
41
+ | `private_email` | Email addresses |
42
+ | `private_person` | Names in email headers, salutations, signatures |
43
+ | `private_phone` | Phone numbers |
44
+ | `private_url` | URLs and IP addresses (including iCloud / share links) |
45
+ | `private_date` | Dates, especially DOB-labeled dates |
46
+ | `secret` | Passwords, API keys, tokens, JWTs, PEM private keys |
47
+
48
+ Classifiers are deterministic pattern engines tuned for high recall on structured PII in correspondence. They run entirely offline.
49
+
50
+ ## Usage
51
+
52
+ ```bash
53
+ # List the eight categories
54
+ dispose categories
55
+
56
+ # Read an .eml: decode base64 / quoted-printable so you can actually read it
57
+ dispose view path/to/mail.eml
58
+ dispose decode path/to/mail.eml # alias for view
59
+ dispose view mail.eml --pager # open in less/more
60
+ dispose view mail.eml -o readable.txt # save decoded text
61
+
62
+ # Read decoded content AND redact privacy spans
63
+ dispose view mail.eml --redact
64
+ dispose view mail.eml --redact -o clean.txt
65
+
66
+ # Classify a file (report spans, do not write)
67
+ dispose classify path/to/email.eml
68
+ dispose classify ./exports --recursive --json
69
+
70
+ # Redact → writes path.redacted.ext by default
71
+ dispose redact path/to/notes.md
72
+ dispose redact ./icloud-export --recursive
73
+
74
+ # Print redacted text to stdout (pipe into an agent)
75
+ dispose redact message.eml --stdout
76
+
77
+ # Pipe / stdin
78
+ cat message.eml | dispose view -
79
+ cat message.eml | dispose redact -
80
+
81
+ # Overwrite in place (careful)
82
+ dispose redact sensitive.txt --in-place
83
+
84
+ # Only certain categories
85
+ dispose redact mail.eml -c private_email -c private_phone -c account_number
86
+
87
+ # Labeled placeholders: [REDACTED:private_email]
88
+ dispose redact mail.eml --label-categories
89
+
90
+ # OpenAI Privacy Filter-style alias
91
+ dispose filter mail.eml --stdout
92
+ ```
93
+
94
+ ### Supported inputs
95
+
96
+ - Text / markdown: `.txt`, `.md`, `.markdown`, `.rst`, `.log`, …
97
+ - Email: `.eml` (MIME-parsed into headers + body by default; **base64** and quoted-printable transfer encodings are decoded before redaction, including multipart bodies, nested messages, text attachments, and RFC 2047 headers)
98
+ - Structured text: `.csv`, `.json`, `.yaml`, `.html`, …
99
+ - PDF: `.pdf` (text is extracted, redacted, and written as a clean text PDF or plain text if you choose a non-`.pdf` output path)
100
+
101
+ ## Library use
102
+
103
+ ```python
104
+ from dispose import PrivacyPipeline
105
+
106
+ pipeline = PrivacyPipeline()
107
+ result = pipeline.redact(open("mail.eml").read())
108
+ print(result.redacted)
109
+ print(result.summary())
110
+ for span in result.spans:
111
+ print(span.category, span.text, span.score)
112
+ ```
113
+
114
+ ## Safety notes
115
+
116
+ - `dispose` is a **data minimization aid**, not a legal anonymization guarantee.
117
+ - Pattern classifiers can miss novel formats and can over-redact lookalikes.
118
+ - Review high-sensitivity outputs before sharing, even with an AI agent you trust.
119
+ - Prefer `--stdout` or a separate output directory over `--in-place` until you trust the result.
120
+
121
+ ## Releasing (maintainers)
122
+
123
+ Version lives only in `pyproject.toml`. Tag on Codeberg matches that version:
124
+
125
+ ```bash
126
+ # after bumping version in pyproject.toml
127
+ git tag -a v0.1.0 -m "dispose 0.1.0"
128
+ git push origin main --tags
129
+
130
+ pip install -e ".[dev]"
131
+ pytest
132
+ python -m build
133
+ python -m twine check dist/*
134
+ # TestPyPI, then PyPI (API token; username __token__)
135
+ twine upload --repository testpypi dist/*
136
+ twine upload dist/*
137
+ ```
138
+
139
+ PyPI does not require GitHub; Codeberg is the source host. Publish with a PyPI API token + `twine` (Trusted Publishing from Codeberg is not available yet).
140
+
141
+ ## License
142
+
143
+ MIT — see [LICENSE](LICENSE).
144
+
145
+ ## Contributions
146
+ If you found this package useful, please consider donating or supporting development as a solo founder I've been without gainful employment for years.
147
+
148
+ Donations
149
+ ```
150
+ SOL AH7TXdVn2ZddT7DALxSQz97AJBvweBXZdvV5vAojqgBy
151
+ ZEC BNB Chain 0xF7fE0DD3165053bD87217BF3e09041e123736175
152
+ TON/GRAM UQAnfI9jJj1iI5nxRcc0jXjrFtg41Ik7XvskB77mLNNMKwwK
153
+ ```
154
+
155
+ Dev Studio `https://6-castles.xyz`
156
+
157
+ Support `dispose-dev AT beconfidential DOT co`
158
+
@@ -0,0 +1,54 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "dispose"
7
+ version = "0.1.0"
8
+ description = "Local privacy classifier and redactor for sensitive files (emails, text, markdown, PDFs)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { file = "LICENSE" }
12
+ authors = [{ name = "hiddendispatches" }]
13
+ keywords = ["privacy", "pii", "redaction", "classifier", "cli", "email"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Environment :: Console",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Security",
27
+ "Topic :: Text Processing :: Filters",
28
+ ]
29
+ dependencies = [
30
+ "click>=8.1",
31
+ "pypdf>=4.0",
32
+ ]
33
+
34
+ [project.optional-dependencies]
35
+ dev = [
36
+ "pytest>=7.0",
37
+ "build",
38
+ "twine",
39
+ ]
40
+
41
+ [project.urls]
42
+ Homepage = "https://codeberg.org/hiddendispatches/dispose"
43
+ Repository = "https://codeberg.org/hiddendispatches/dispose"
44
+ Issues = "https://codeberg.org/hiddendispatches/dispose/issues"
45
+
46
+ [project.scripts]
47
+ dispose = "dispose.cli:main"
48
+
49
+ [tool.setuptools.packages.find]
50
+ where = ["src"]
51
+
52
+ [tool.pytest.ini_options]
53
+ testpaths = ["tests"]
54
+ pythonpath = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,19 @@
1
+ """dispose — local privacy classifier and redactor for sensitive communications."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ from dispose.pipeline import PrivacyPipeline, RedactionResult
6
+ from dispose.taxonomy import CATEGORIES, Category
7
+
8
+ try:
9
+ __version__ = version("dispose")
10
+ except PackageNotFoundError:
11
+ __version__ = "0.0.0+local"
12
+
13
+ __all__ = [
14
+ "CATEGORIES",
15
+ "Category",
16
+ "PrivacyPipeline",
17
+ "RedactionResult",
18
+ "__version__",
19
+ ]
@@ -0,0 +1,6 @@
1
+ """python -m dispose entry point."""
2
+
3
+ from dispose.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()