peyeeye 1.0.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,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ .pytest_cache/
9
+ .coverage
10
+ htmlcov/
11
+ .mypy_cache/
12
+ .ruff_cache/
13
+ .tox/
14
+ .env
15
+ .DS_Store
peyeeye-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 peyeeye.ai
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.
peyeeye-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,280 @@
1
+ Metadata-Version: 2.4
2
+ Name: peyeeye
3
+ Version: 1.0.0
4
+ Summary: Official Python client for peyeeye.ai — PII redaction & rehydration for LLM prompts.
5
+ Project-URL: Homepage, https://peyeeye.ai
6
+ Project-URL: Documentation, https://peyeeye.ai/docs
7
+ Author-email: "peyeeye.ai" <support@peyeeye.ai>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: ai,ai-safety,anonymization,anthropic,claude,compliance,data-masking,data-privacy,data-protection,gdpr,hipaa,llm,openai,peyeeye,pii,pii-detection,privacy,prompt-engineering,rag,redaction,rehydrate,security,sensitive-data,tokenization
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Classifier: Topic :: Security
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.9
28
+ Requires-Dist: httpx>=0.27
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest-cov>=5; extra == 'dev'
31
+ Requires-Dist: pytest>=8; extra == 'dev'
32
+ Requires-Dist: respx>=0.21; extra == 'dev'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # peyeeye
36
+
37
+ [![PyPI version](https://img.shields.io/pypi/v/peyeeye.svg)](https://pypi.org/project/peyeeye/)
38
+ [![Python versions](https://img.shields.io/pypi/pyversions/peyeeye.svg)](https://pypi.org/project/peyeeye/)
39
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
40
+
41
+ Official Python client for [**peyeeye.ai**](https://peyeeye.ai) — redact PII on
42
+ the way _into_ your LLM prompts and rehydrate it on the way out.
43
+
44
+ - **Homepage**: <https://peyeeye.ai>
45
+ - **API reference**: <https://peyeeye.ai/docs>
46
+ - **PyPI**: <https://pypi.org/project/peyeeye/>
47
+
48
+ ```bash
49
+ pip install peyeeye
50
+ ```
51
+
52
+ Python 3.9+. Single runtime dependency: `httpx`. Fully type-hinted (`py.typed`).
53
+
54
+ ## Quickstart
55
+
56
+ ```python
57
+ import os
58
+ from peyeeye import Peyeeye
59
+ from anthropic import Anthropic
60
+
61
+ peyeeye = Peyeeye(api_key=os.environ["PEYEEYE_KEY"])
62
+ claude = Anthropic()
63
+
64
+ with peyeeye.shield() as shield:
65
+ safe = shield.redact("Hi, I'm Ada, ada@a-e.com")
66
+ reply = claude.messages.create(
67
+ model="claude-sonnet-*",
68
+ max_tokens=256,
69
+ messages=[{"role": "user", "content": safe}],
70
+ )
71
+ print(shield.rehydrate(reply.content[0].text))
72
+ ```
73
+
74
+ `shield()` opens a session, redacts, and cleans up on exit. Inside the block,
75
+ the same real value always maps to the same token — `Ada Lovelace` is always
76
+ `[PERSON_1]` — and tokens never leak across sessions.
77
+
78
+ ## Low-level calls
79
+
80
+ Skip the `shield` helper when you need more control:
81
+
82
+ ```python
83
+ r = peyeeye.redact("Card: 4242 4242 4242 4242")
84
+ # r.redacted → "Card: [CARD_1]"
85
+ # r.session → "ses_…"
86
+ # r.entities → [DetectedEntity(token="[CARD_1]", type="CARD", span=(6, 25), confidence=0.99)]
87
+
88
+ clean = peyeeye.rehydrate("Confirmation for [CARD_1].", session=r.session)
89
+ # clean.text → "Confirmation for 4242 4242 4242 4242."
90
+ ```
91
+
92
+ ## Stateless sealed mode
93
+
94
+ Pass `stateless=True` and peyeeye never stores the mapping — the redact
95
+ response carries a sealed `skey_…` blob you hand back to rehydrate. Nothing
96
+ lives on the server between calls.
97
+
98
+ ```python
99
+ with peyeeye.shield(stateless=True) as shield:
100
+ safe = shield.redact("Email ada@a-e.com")
101
+ clean = shield.rehydrate("Reply: [EMAIL_1]")
102
+ # shield.rehydration_key is the skey_... blob, if you need to persist it
103
+ ```
104
+
105
+ Or with raw calls:
106
+
107
+ ```python
108
+ r = peyeeye.redact("Email ada@a-e.com", session="stateless")
109
+ # r.rehydration_key → "skey_…"
110
+ clean = peyeeye.rehydrate("[EMAIL_1] received.", session=r.rehydration_key)
111
+ ```
112
+
113
+ ## Streaming rehydration
114
+
115
+ When piping an LLM token stream straight to a user, naive rehydration breaks
116
+ on mid-token boundaries. `rehydrate_chunk()` buffers partial tokens across
117
+ chunks; call `flush()` once upstream closes.
118
+
119
+ ```python
120
+ with peyeeye.shield() as shield:
121
+ safe = shield.redact(prompt)
122
+ for chunk in your_llm_stream(safe):
123
+ sys.stdout.write(shield.rehydrate_chunk(chunk))
124
+ sys.stdout.write(shield.flush())
125
+ ```
126
+
127
+ Never call `flush()` while the stream is still delivering chunks — you'll emit
128
+ a half-formed placeholder.
129
+
130
+ ## Streaming redact (SSE)
131
+
132
+ For the `/v1/redact/stream` endpoint (Build plan and higher):
133
+
134
+ ```python
135
+ for event in peyeeye.redact_stream(["Hi, I'm Ada", " — card 4242 4242 4242 4242"]):
136
+ if event.event == "session":
137
+ session_id = event.data["session"]
138
+ elif event.event == "redacted":
139
+ print(event.data["text"])
140
+ elif event.event == "done":
141
+ print("chars:", event.data["chars"])
142
+ ```
143
+
144
+ ## Custom detectors
145
+
146
+ ```python
147
+ peyeeye.create_entity(
148
+ id="ORDER_ID",
149
+ kind="regex",
150
+ pattern=r"#A-\d{6,}",
151
+ examples=["#A-884217", "#A-007431"],
152
+ confidence_floor=0.9,
153
+ )
154
+
155
+ # dry-run a pattern before saving
156
+ peyeeye.test_pattern(pattern=r"#A-\d{6,}", text="ref #A-884217 and #A-1")
157
+ # → TestPatternResponse(count=1, matches=[PatternMatch(value="#A-884217", ...)])
158
+
159
+ # inspect / update / retire
160
+ peyeeye.list_entities()
161
+ peyeeye.update_entity("ORDER_ID", enabled=False)
162
+ peyeeye.delete_entity("ORDER_ID")
163
+
164
+ # starter templates (Twilio SIDs, Stripe keys, AWS access keys, etc.)
165
+ for tpl in peyeeye.entity_templates():
166
+ print(tpl.id, tpl.pattern)
167
+ ```
168
+
169
+ ## Sessions
170
+
171
+ ```python
172
+ peyeeye.get_session("ses_…") # SessionInfo
173
+ peyeeye.delete_session("ses_…") # drop immediately
174
+ ```
175
+
176
+ ## Errors
177
+
178
+ Every non-2xx response raises `PeyeeyeError` with `.code`, `.status`,
179
+ `.message`, and `.request_id`. 429 and 5xx responses are retried with
180
+ exponential backoff (`Retry-After` honoured); terminal errors raise
181
+ immediately.
182
+
183
+ ```python
184
+ from peyeeye import PeyeeyeError
185
+
186
+ try:
187
+ peyeeye.redact("…")
188
+ except PeyeeyeError as e:
189
+ if e.code == "rate_limited":
190
+ ...
191
+ elif e.code == "forbidden":
192
+ ...
193
+ else:
194
+ raise
195
+ ```
196
+
197
+ ## Configuration
198
+
199
+ ```python
200
+ Peyeeye(
201
+ api_key="pk_live_…",
202
+ base_url="https://api.peyeeye.ai",
203
+ timeout=30.0,
204
+ max_retries=3,
205
+ )
206
+ ```
207
+
208
+ For CI / air-gapped use, `Peyeeye(transport=httpx.MockTransport(handler))`
209
+ lets you mount a mock transport without monkey-patching.
210
+
211
+ ## Method reference
212
+
213
+ | Method | HTTP | Purpose |
214
+ | --- | --- | --- |
215
+ | `peyeeye.redact(text, ...)` | `POST /v1/redact` | Redact PII; returns token stream + session. |
216
+ | `peyeeye.rehydrate(text, session=...)` | `POST /v1/rehydrate` | Substitute tokens back. Accepts `ses_…` or `skey_…`. |
217
+ | `peyeeye.redact_stream(chunks, ...)` | `POST /v1/redact/stream` (SSE) | Stream-safe redact. |
218
+ | `peyeeye.get_session(id)` | `GET /v1/sessions/{id}` | Inspect mapping metadata. |
219
+ | `peyeeye.delete_session(id)` | `DELETE /v1/sessions/{id}` | Evict a session. |
220
+ | `peyeeye.list_entities()` | `GET /v1/entities` | Built-ins + your custom detectors. |
221
+ | `peyeeye.create_entity(...)` | `POST /v1/entities` | Custom detector. |
222
+ | `peyeeye.update_entity(id, ...)` | `PATCH /v1/entities/{id}` | Toggle / tweak. |
223
+ | `peyeeye.delete_entity(id)` | `DELETE /v1/entities/{id}` | Retire. |
224
+ | `peyeeye.test_pattern(pattern, text)` | `POST /v1/entities/test` | Dry-run a regex. |
225
+ | `peyeeye.entity_templates()` | `GET /v1/entities/templates` | Starter patterns. |
226
+
227
+ Full request / response schemas: <https://peyeeye.ai/docs>.
228
+
229
+ ## Using this SDK from an AI coding assistant
230
+
231
+ Drop these into your agent's context. Each snippet is self-contained and
232
+ compiles as-is.
233
+
234
+ ```python
235
+ # Install
236
+ # pip install peyeeye
237
+
238
+ from peyeeye import Peyeeye, PeyeeyeError
239
+ import os
240
+
241
+ client = Peyeeye(api_key=os.environ["PEYEEYE_KEY"]) # or explicit base_url
242
+
243
+ # Round-trip: redact → call LLM → rehydrate (session-scoped)
244
+ with client.shield() as shield:
245
+ safe = shield.redact("Hi, I'm Ada, ada@a-e.com")
246
+ # ... send `safe` to the LLM, get `reply` back ...
247
+ out = shield.rehydrate(reply)
248
+
249
+ # Stateless (zero server-side state; key is yours to persist)
250
+ with client.shield(stateless=True) as shield:
251
+ safe = shield.redact("...")
252
+ key = shield.rehydration_key # skey_...
253
+ clean = shield.rehydrate("[EMAIL_1] confirmed.")
254
+
255
+ # Low-level one-shot
256
+ r = client.redact("Card 4242 4242 4242 4242")
257
+ clean = client.rehydrate("Receipt: [CARD_1].", session=r.session)
258
+
259
+ # Error handling
260
+ try:
261
+ client.redact(text)
262
+ except PeyeeyeError as e:
263
+ # e.code ∈ {"rate_limited","forbidden","invalid_request","server_error", ...}
264
+ # e.status, e.message, e.request_id
265
+ raise
266
+ ```
267
+
268
+ **Endpoint envelope**: all requests use `Authorization: Bearer <api_key>` against
269
+ `https://api.peyeeye.ai/v1/*`. Errors follow `{code, message, request_id}`
270
+ and surface as `PeyeeyeError`. Responses are plain JSON (dataclasses via
271
+ `from_dict`).
272
+
273
+ **Do**: reuse one `Peyeeye(...)` per process; call `.close()` or use it as a
274
+ context manager at shutdown.
275
+ **Don't**: open a new client per request, call `flush()` mid-stream, or parse
276
+ `skey_` blobs yourself — the API opens them.
277
+
278
+ ## License
279
+
280
+ MIT.
@@ -0,0 +1,246 @@
1
+ # peyeeye
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/peyeeye.svg)](https://pypi.org/project/peyeeye/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/peyeeye.svg)](https://pypi.org/project/peyeeye/)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ Official Python client for [**peyeeye.ai**](https://peyeeye.ai) — redact PII on
8
+ the way _into_ your LLM prompts and rehydrate it on the way out.
9
+
10
+ - **Homepage**: <https://peyeeye.ai>
11
+ - **API reference**: <https://peyeeye.ai/docs>
12
+ - **PyPI**: <https://pypi.org/project/peyeeye/>
13
+
14
+ ```bash
15
+ pip install peyeeye
16
+ ```
17
+
18
+ Python 3.9+. Single runtime dependency: `httpx`. Fully type-hinted (`py.typed`).
19
+
20
+ ## Quickstart
21
+
22
+ ```python
23
+ import os
24
+ from peyeeye import Peyeeye
25
+ from anthropic import Anthropic
26
+
27
+ peyeeye = Peyeeye(api_key=os.environ["PEYEEYE_KEY"])
28
+ claude = Anthropic()
29
+
30
+ with peyeeye.shield() as shield:
31
+ safe = shield.redact("Hi, I'm Ada, ada@a-e.com")
32
+ reply = claude.messages.create(
33
+ model="claude-sonnet-*",
34
+ max_tokens=256,
35
+ messages=[{"role": "user", "content": safe}],
36
+ )
37
+ print(shield.rehydrate(reply.content[0].text))
38
+ ```
39
+
40
+ `shield()` opens a session, redacts, and cleans up on exit. Inside the block,
41
+ the same real value always maps to the same token — `Ada Lovelace` is always
42
+ `[PERSON_1]` — and tokens never leak across sessions.
43
+
44
+ ## Low-level calls
45
+
46
+ Skip the `shield` helper when you need more control:
47
+
48
+ ```python
49
+ r = peyeeye.redact("Card: 4242 4242 4242 4242")
50
+ # r.redacted → "Card: [CARD_1]"
51
+ # r.session → "ses_…"
52
+ # r.entities → [DetectedEntity(token="[CARD_1]", type="CARD", span=(6, 25), confidence=0.99)]
53
+
54
+ clean = peyeeye.rehydrate("Confirmation for [CARD_1].", session=r.session)
55
+ # clean.text → "Confirmation for 4242 4242 4242 4242."
56
+ ```
57
+
58
+ ## Stateless sealed mode
59
+
60
+ Pass `stateless=True` and peyeeye never stores the mapping — the redact
61
+ response carries a sealed `skey_…` blob you hand back to rehydrate. Nothing
62
+ lives on the server between calls.
63
+
64
+ ```python
65
+ with peyeeye.shield(stateless=True) as shield:
66
+ safe = shield.redact("Email ada@a-e.com")
67
+ clean = shield.rehydrate("Reply: [EMAIL_1]")
68
+ # shield.rehydration_key is the skey_... blob, if you need to persist it
69
+ ```
70
+
71
+ Or with raw calls:
72
+
73
+ ```python
74
+ r = peyeeye.redact("Email ada@a-e.com", session="stateless")
75
+ # r.rehydration_key → "skey_…"
76
+ clean = peyeeye.rehydrate("[EMAIL_1] received.", session=r.rehydration_key)
77
+ ```
78
+
79
+ ## Streaming rehydration
80
+
81
+ When piping an LLM token stream straight to a user, naive rehydration breaks
82
+ on mid-token boundaries. `rehydrate_chunk()` buffers partial tokens across
83
+ chunks; call `flush()` once upstream closes.
84
+
85
+ ```python
86
+ with peyeeye.shield() as shield:
87
+ safe = shield.redact(prompt)
88
+ for chunk in your_llm_stream(safe):
89
+ sys.stdout.write(shield.rehydrate_chunk(chunk))
90
+ sys.stdout.write(shield.flush())
91
+ ```
92
+
93
+ Never call `flush()` while the stream is still delivering chunks — you'll emit
94
+ a half-formed placeholder.
95
+
96
+ ## Streaming redact (SSE)
97
+
98
+ For the `/v1/redact/stream` endpoint (Build plan and higher):
99
+
100
+ ```python
101
+ for event in peyeeye.redact_stream(["Hi, I'm Ada", " — card 4242 4242 4242 4242"]):
102
+ if event.event == "session":
103
+ session_id = event.data["session"]
104
+ elif event.event == "redacted":
105
+ print(event.data["text"])
106
+ elif event.event == "done":
107
+ print("chars:", event.data["chars"])
108
+ ```
109
+
110
+ ## Custom detectors
111
+
112
+ ```python
113
+ peyeeye.create_entity(
114
+ id="ORDER_ID",
115
+ kind="regex",
116
+ pattern=r"#A-\d{6,}",
117
+ examples=["#A-884217", "#A-007431"],
118
+ confidence_floor=0.9,
119
+ )
120
+
121
+ # dry-run a pattern before saving
122
+ peyeeye.test_pattern(pattern=r"#A-\d{6,}", text="ref #A-884217 and #A-1")
123
+ # → TestPatternResponse(count=1, matches=[PatternMatch(value="#A-884217", ...)])
124
+
125
+ # inspect / update / retire
126
+ peyeeye.list_entities()
127
+ peyeeye.update_entity("ORDER_ID", enabled=False)
128
+ peyeeye.delete_entity("ORDER_ID")
129
+
130
+ # starter templates (Twilio SIDs, Stripe keys, AWS access keys, etc.)
131
+ for tpl in peyeeye.entity_templates():
132
+ print(tpl.id, tpl.pattern)
133
+ ```
134
+
135
+ ## Sessions
136
+
137
+ ```python
138
+ peyeeye.get_session("ses_…") # SessionInfo
139
+ peyeeye.delete_session("ses_…") # drop immediately
140
+ ```
141
+
142
+ ## Errors
143
+
144
+ Every non-2xx response raises `PeyeeyeError` with `.code`, `.status`,
145
+ `.message`, and `.request_id`. 429 and 5xx responses are retried with
146
+ exponential backoff (`Retry-After` honoured); terminal errors raise
147
+ immediately.
148
+
149
+ ```python
150
+ from peyeeye import PeyeeyeError
151
+
152
+ try:
153
+ peyeeye.redact("…")
154
+ except PeyeeyeError as e:
155
+ if e.code == "rate_limited":
156
+ ...
157
+ elif e.code == "forbidden":
158
+ ...
159
+ else:
160
+ raise
161
+ ```
162
+
163
+ ## Configuration
164
+
165
+ ```python
166
+ Peyeeye(
167
+ api_key="pk_live_…",
168
+ base_url="https://api.peyeeye.ai",
169
+ timeout=30.0,
170
+ max_retries=3,
171
+ )
172
+ ```
173
+
174
+ For CI / air-gapped use, `Peyeeye(transport=httpx.MockTransport(handler))`
175
+ lets you mount a mock transport without monkey-patching.
176
+
177
+ ## Method reference
178
+
179
+ | Method | HTTP | Purpose |
180
+ | --- | --- | --- |
181
+ | `peyeeye.redact(text, ...)` | `POST /v1/redact` | Redact PII; returns token stream + session. |
182
+ | `peyeeye.rehydrate(text, session=...)` | `POST /v1/rehydrate` | Substitute tokens back. Accepts `ses_…` or `skey_…`. |
183
+ | `peyeeye.redact_stream(chunks, ...)` | `POST /v1/redact/stream` (SSE) | Stream-safe redact. |
184
+ | `peyeeye.get_session(id)` | `GET /v1/sessions/{id}` | Inspect mapping metadata. |
185
+ | `peyeeye.delete_session(id)` | `DELETE /v1/sessions/{id}` | Evict a session. |
186
+ | `peyeeye.list_entities()` | `GET /v1/entities` | Built-ins + your custom detectors. |
187
+ | `peyeeye.create_entity(...)` | `POST /v1/entities` | Custom detector. |
188
+ | `peyeeye.update_entity(id, ...)` | `PATCH /v1/entities/{id}` | Toggle / tweak. |
189
+ | `peyeeye.delete_entity(id)` | `DELETE /v1/entities/{id}` | Retire. |
190
+ | `peyeeye.test_pattern(pattern, text)` | `POST /v1/entities/test` | Dry-run a regex. |
191
+ | `peyeeye.entity_templates()` | `GET /v1/entities/templates` | Starter patterns. |
192
+
193
+ Full request / response schemas: <https://peyeeye.ai/docs>.
194
+
195
+ ## Using this SDK from an AI coding assistant
196
+
197
+ Drop these into your agent's context. Each snippet is self-contained and
198
+ compiles as-is.
199
+
200
+ ```python
201
+ # Install
202
+ # pip install peyeeye
203
+
204
+ from peyeeye import Peyeeye, PeyeeyeError
205
+ import os
206
+
207
+ client = Peyeeye(api_key=os.environ["PEYEEYE_KEY"]) # or explicit base_url
208
+
209
+ # Round-trip: redact → call LLM → rehydrate (session-scoped)
210
+ with client.shield() as shield:
211
+ safe = shield.redact("Hi, I'm Ada, ada@a-e.com")
212
+ # ... send `safe` to the LLM, get `reply` back ...
213
+ out = shield.rehydrate(reply)
214
+
215
+ # Stateless (zero server-side state; key is yours to persist)
216
+ with client.shield(stateless=True) as shield:
217
+ safe = shield.redact("...")
218
+ key = shield.rehydration_key # skey_...
219
+ clean = shield.rehydrate("[EMAIL_1] confirmed.")
220
+
221
+ # Low-level one-shot
222
+ r = client.redact("Card 4242 4242 4242 4242")
223
+ clean = client.rehydrate("Receipt: [CARD_1].", session=r.session)
224
+
225
+ # Error handling
226
+ try:
227
+ client.redact(text)
228
+ except PeyeeyeError as e:
229
+ # e.code ∈ {"rate_limited","forbidden","invalid_request","server_error", ...}
230
+ # e.status, e.message, e.request_id
231
+ raise
232
+ ```
233
+
234
+ **Endpoint envelope**: all requests use `Authorization: Bearer <api_key>` against
235
+ `https://api.peyeeye.ai/v1/*`. Errors follow `{code, message, request_id}`
236
+ and surface as `PeyeeyeError`. Responses are plain JSON (dataclasses via
237
+ `from_dict`).
238
+
239
+ **Do**: reuse one `Peyeeye(...)` per process; call `.close()` or use it as a
240
+ context manager at shutdown.
241
+ **Don't**: open a new client per request, call `flush()` mid-stream, or parse
242
+ `skey_` blobs yourself — the API opens them.
243
+
244
+ ## License
245
+
246
+ MIT.
@@ -0,0 +1,41 @@
1
+ """peyeeye — PII redaction & rehydration client.
2
+
3
+ from peyeeye import Peyeeye
4
+
5
+ pe = Peyeeye(api_key="pk_live_...")
6
+ with pe.shield() as shield:
7
+ safe = shield.redact("Hi, I'm Ada, ada@a-e.com")
8
+ reply = call_your_model(safe)
9
+ print(shield.rehydrate(reply))
10
+ """
11
+
12
+ from .client import Peyeeye, Shield
13
+ from .errors import PeyeeyeError
14
+ from .models import (
15
+ CustomDetector,
16
+ DetectedEntity,
17
+ EntitiesList,
18
+ EntityTemplate,
19
+ RedactResponse,
20
+ RehydrateResponse,
21
+ SessionInfo,
22
+ StreamEvent,
23
+ TestPatternResponse,
24
+ )
25
+
26
+ __all__ = [
27
+ "Peyeeye",
28
+ "PeyeeyeError",
29
+ "Shield",
30
+ "DetectedEntity",
31
+ "RedactResponse",
32
+ "RehydrateResponse",
33
+ "SessionInfo",
34
+ "CustomDetector",
35
+ "EntitiesList",
36
+ "EntityTemplate",
37
+ "TestPatternResponse",
38
+ "StreamEvent",
39
+ ]
40
+
41
+ __version__ = "1.0.0"