retab 0.0.67__py3-none-any.whl → 0.0.69__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.
- retab/__init__.py +2 -2
- retab/client.py +92 -7
- retab/generate_types.py +2 -2
- retab/resources/documents/client.py +44 -138
- retab/resources/extractions/__init__.py +3 -0
- retab/resources/extractions/client.py +425 -0
- retab/resources/projects/client.py +32 -79
- retab/resources/schemas.py +0 -8
- retab/types/documents/create_messages.py +10 -12
- retab/types/documents/extract.py +16 -81
- retab/types/documents/parse.py +0 -2
- retab/types/inference_settings.py +6 -4
- retab/types/mime.py +53 -45
- retab/types/pagination.py +6 -0
- retab/types/projects/__init__.py +2 -27
- retab/types/projects/model.py +63 -26
- retab/types/schemas/generate.py +0 -4
- {retab-0.0.67.dist-info → retab-0.0.69.dist-info}/METADATA +1 -1
- {retab-0.0.67.dist-info → retab-0.0.69.dist-info}/RECORD +21 -27
- retab/client copy.py +0 -693
- retab/resources/projects/documents.py +0 -257
- retab/resources/projects/iterations.py +0 -433
- retab/types/browser_canvas.py +0 -3
- retab/types/projects/Untitled-2.py +0 -16671
- retab/types/projects/documents.py +0 -38
- retab/types/projects/iterations.py +0 -123
- retab/types/projects/v2.py +0 -137
- {retab-0.0.67.dist-info → retab-0.0.69.dist-info}/WHEEL +0 -0
- {retab-0.0.67.dist-info → retab-0.0.69.dist-info}/top_level.txt +0 -0
retab/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .client import AsyncRetab, Retab
|
|
1
|
+
from .client import AsyncRetab, Retab, SignatureVerificationError
|
|
2
2
|
from . import utils
|
|
3
3
|
from . import types
|
|
4
|
-
__all__ = ["Retab", "AsyncRetab", "utils", "types"]
|
|
4
|
+
__all__ = ["Retab", "AsyncRetab", "SignatureVerificationError", "utils", "types"]
|
retab/client.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import hmac
|
|
1
3
|
import json
|
|
2
4
|
import os
|
|
3
5
|
from types import TracebackType
|
|
@@ -8,10 +10,15 @@ import backoff.types
|
|
|
8
10
|
import httpx
|
|
9
11
|
import truststore
|
|
10
12
|
|
|
11
|
-
from .resources import documents, models, schemas, projects
|
|
13
|
+
from .resources import documents, models, schemas, projects, extractions
|
|
12
14
|
from .types.standards import PreparedRequest, FieldUnset
|
|
13
15
|
|
|
14
16
|
|
|
17
|
+
class SignatureVerificationError(Exception):
|
|
18
|
+
"""Raised when webhook signature verification fails."""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
15
22
|
class MaxRetriesExceeded(Exception):
|
|
16
23
|
pass
|
|
17
24
|
|
|
@@ -34,7 +41,7 @@ class BaseRetab:
|
|
|
34
41
|
Args:
|
|
35
42
|
api_key (str, optional): Retab API key. If not provided, will look for RETAB_API_KEY env variable.
|
|
36
43
|
base_url (str, optional): Base URL for API requests. Defaults to https://api.retab.com
|
|
37
|
-
timeout (float): Request timeout in seconds. Defaults to
|
|
44
|
+
timeout (float): Request timeout in seconds. Defaults to 1800.0 (30 minutes)
|
|
38
45
|
max_retries (int): Maximum number of retries for failed requests. Defaults to 3
|
|
39
46
|
openai_api_key (str, optional): OpenAI API key. Will look for OPENAI_API_KEY env variable if not provided
|
|
40
47
|
|
|
@@ -46,7 +53,7 @@ class BaseRetab:
|
|
|
46
53
|
self,
|
|
47
54
|
api_key: Optional[str] = None,
|
|
48
55
|
base_url: Optional[str] = None,
|
|
49
|
-
timeout: float =
|
|
56
|
+
timeout: float = 1800.0,
|
|
50
57
|
max_retries: int = 3,
|
|
51
58
|
openai_api_key: Optional[str] = FieldUnset,
|
|
52
59
|
gemini_api_key: Optional[str] = FieldUnset,
|
|
@@ -140,7 +147,7 @@ class Retab(BaseRetab):
|
|
|
140
147
|
Args:
|
|
141
148
|
api_key (str, optional): Retab API key. If not provided, will look for RETAB_API_KEY env variable.
|
|
142
149
|
base_url (str, optional): Base URL for API requests. Defaults to https://api.retab.com
|
|
143
|
-
timeout (float): Request timeout in seconds. Defaults to
|
|
150
|
+
timeout (float): Request timeout in seconds. Defaults to 1800.0 (30 minutes)
|
|
144
151
|
max_retries (int): Maximum number of retries for failed requests. Defaults to 3
|
|
145
152
|
openai_api_key (str, optional): OpenAI API key. Will look for OPENAI_API_KEY env variable if not provided
|
|
146
153
|
gemini_api_key (str, optional): Gemini API key. Will look for GEMINI_API_KEY env variable if not provided
|
|
@@ -161,7 +168,7 @@ class Retab(BaseRetab):
|
|
|
161
168
|
self,
|
|
162
169
|
api_key: Optional[str] = None,
|
|
163
170
|
base_url: Optional[str] = None,
|
|
164
|
-
timeout: float =
|
|
171
|
+
timeout: float = 1800.0,
|
|
165
172
|
max_retries: int = 3,
|
|
166
173
|
openai_api_key: Optional[str] = FieldUnset,
|
|
167
174
|
gemini_api_key: Optional[str] = FieldUnset,
|
|
@@ -177,6 +184,7 @@ class Retab(BaseRetab):
|
|
|
177
184
|
|
|
178
185
|
self.client = httpx.Client(timeout=self.timeout)
|
|
179
186
|
self.projects = projects.Projects(client=self)
|
|
187
|
+
self.extractions = extractions.Extractions(client=self)
|
|
180
188
|
self.documents = documents.Documents(client=self)
|
|
181
189
|
self.models = models.Models(client=self)
|
|
182
190
|
self.schemas = schemas.Schemas(client=self)
|
|
@@ -385,6 +393,44 @@ class Retab(BaseRetab):
|
|
|
385
393
|
"""
|
|
386
394
|
self.close()
|
|
387
395
|
|
|
396
|
+
@staticmethod
|
|
397
|
+
def verify_event(event_body: bytes, event_signature: str, secret: str) -> Any:
|
|
398
|
+
"""Verify the signature of a webhook event.
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
event_body: The raw request body as bytes
|
|
402
|
+
event_signature: The signature from the request header (x-retab-signature)
|
|
403
|
+
secret: The webhook secret key used for signing
|
|
404
|
+
|
|
405
|
+
Returns:
|
|
406
|
+
Any: The parsed event payload (JSON)
|
|
407
|
+
|
|
408
|
+
Raises:
|
|
409
|
+
SignatureVerificationError: If the signature verification fails
|
|
410
|
+
|
|
411
|
+
Example:
|
|
412
|
+
```python
|
|
413
|
+
from retab import Retab
|
|
414
|
+
|
|
415
|
+
# In your webhook handler
|
|
416
|
+
secret = "your_webhook_secret"
|
|
417
|
+
body = request.body # Raw bytes
|
|
418
|
+
signature = request.headers.get("x-retab-signature")
|
|
419
|
+
|
|
420
|
+
try:
|
|
421
|
+
event = Retab.verify_event(body, signature, secret)
|
|
422
|
+
print(f"Verified event: {event}")
|
|
423
|
+
except SignatureVerificationError:
|
|
424
|
+
print("Invalid signature!")
|
|
425
|
+
```
|
|
426
|
+
"""
|
|
427
|
+
expected_signature = hmac.new(secret.encode(), event_body, hashlib.sha256).hexdigest()
|
|
428
|
+
|
|
429
|
+
if not hmac.compare_digest(event_signature, expected_signature):
|
|
430
|
+
raise SignatureVerificationError("Invalid signature")
|
|
431
|
+
|
|
432
|
+
return json.loads(event_body.decode("utf-8"))
|
|
433
|
+
|
|
388
434
|
|
|
389
435
|
class AsyncRetab(BaseRetab):
|
|
390
436
|
"""Asynchronous client for interacting with the Retab API.
|
|
@@ -395,7 +441,7 @@ class AsyncRetab(BaseRetab):
|
|
|
395
441
|
Args:
|
|
396
442
|
api_key (str, optional): Retab API key. If not provided, will look for RETAB_API_KEY env variable.
|
|
397
443
|
base_url (str, optional): Base URL for API requests. Defaults to https://api.retab.com
|
|
398
|
-
timeout (float): Request timeout in seconds. Defaults to
|
|
444
|
+
timeout (float): Request timeout in seconds. Defaults to 1800.0 (30 minutes)
|
|
399
445
|
max_retries (int): Maximum number of retries for failed requests. Defaults to 3
|
|
400
446
|
openai_api_key (str, optional): OpenAI API key. Will look for OPENAI_API_KEY env variable if not provided
|
|
401
447
|
claude_api_key (str, optional): Claude API key. Will look for CLAUDE_API_KEY env variable if not provided
|
|
@@ -418,7 +464,7 @@ class AsyncRetab(BaseRetab):
|
|
|
418
464
|
self,
|
|
419
465
|
api_key: Optional[str] = None,
|
|
420
466
|
base_url: Optional[str] = None,
|
|
421
|
-
timeout: float =
|
|
467
|
+
timeout: float = 1800.0,
|
|
422
468
|
max_retries: int = 3,
|
|
423
469
|
openai_api_key: Optional[str] = FieldUnset,
|
|
424
470
|
gemini_api_key: Optional[str] = FieldUnset,
|
|
@@ -435,6 +481,7 @@ class AsyncRetab(BaseRetab):
|
|
|
435
481
|
self.client = httpx.AsyncClient(timeout=self.timeout)
|
|
436
482
|
|
|
437
483
|
self.projects = projects.AsyncProjects(client=self)
|
|
484
|
+
self.extractions = extractions.AsyncExtractions(client=self)
|
|
438
485
|
self.documents = documents.AsyncDocuments(client=self)
|
|
439
486
|
self.models = models.AsyncModels(client=self)
|
|
440
487
|
self.schemas = schemas.AsyncSchemas(client=self)
|
|
@@ -661,3 +708,41 @@ class AsyncRetab(BaseRetab):
|
|
|
661
708
|
traceback: The traceback of the exception that was raised, if any
|
|
662
709
|
"""
|
|
663
710
|
await self.close()
|
|
711
|
+
@staticmethod
|
|
712
|
+
def verify_event(event_body: bytes, event_signature: str, secret: str) -> Any:
|
|
713
|
+
"""Verify the signature of a webhook event.
|
|
714
|
+
|
|
715
|
+
Args:
|
|
716
|
+
event_body: The raw request body as bytes
|
|
717
|
+
event_signature: The signature from the request header (x-retab-signature)
|
|
718
|
+
secret: The webhook secret key used for signing
|
|
719
|
+
|
|
720
|
+
Returns:
|
|
721
|
+
Any: The parsed event payload (JSON)
|
|
722
|
+
|
|
723
|
+
Raises:
|
|
724
|
+
SignatureVerificationError: If the signature verification fails
|
|
725
|
+
|
|
726
|
+
Example:
|
|
727
|
+
```python
|
|
728
|
+
from retab import AsyncRetab
|
|
729
|
+
|
|
730
|
+
# In your async webhook handler
|
|
731
|
+
secret = "your_webhook_secret"
|
|
732
|
+
body = await request.body() # Raw bytes
|
|
733
|
+
signature = request.headers.get("x-retab-signature")
|
|
734
|
+
|
|
735
|
+
try:
|
|
736
|
+
event = AsyncRetab.verify_event(body, signature, secret)
|
|
737
|
+
print(f"Verified event: {event}")
|
|
738
|
+
except SignatureVerificationError:
|
|
739
|
+
print("Invalid signature!")
|
|
740
|
+
```
|
|
741
|
+
"""
|
|
742
|
+
expected_signature = hmac.new(secret.encode(), event_body, hashlib.sha256).hexdigest()
|
|
743
|
+
|
|
744
|
+
if not hmac.compare_digest(event_signature, expected_signature):
|
|
745
|
+
raise SignatureVerificationError("Invalid signature")
|
|
746
|
+
|
|
747
|
+
return json.loads(event_body.decode("utf-8"))
|
|
748
|
+
|
retab/generate_types.py
CHANGED
|
@@ -59,7 +59,7 @@ def type_to_zod(field_type: Any, put_names: bool = True, ts: bool = False) -> st
|
|
|
59
59
|
optional = True
|
|
60
60
|
typename = make_union([type_to_zod(x) for x in args])
|
|
61
61
|
ts_typename = make_ts_union([type_to_zod(x, ts=True) for x in args])
|
|
62
|
-
elif issubclass(origin, BaseModel) or is_typeddict(origin) or is_typeddict_ext(origin):
|
|
62
|
+
elif isinstance(origin, type) and (issubclass(origin, BaseModel) or is_typeddict(origin) or is_typeddict_ext(origin)):
|
|
63
63
|
if put_names:
|
|
64
64
|
name = get_class_name(origin)
|
|
65
65
|
typename = "Z" + name
|
|
@@ -77,7 +77,7 @@ def type_to_zod(field_type: Any, put_names: bool = True, ts: bool = False) -> st
|
|
|
77
77
|
|
|
78
78
|
typename += "z.object({\n"
|
|
79
79
|
ts_typename += "{\n"
|
|
80
|
-
props = [(n, f.annotation, f.default) for n, f in origin.model_fields.items() if not f.exclude] if issubclass(origin, BaseModel) else \
|
|
80
|
+
props = [(n, f.annotation, f.default) for n, f in origin.model_fields.items() if not f.exclude] if isinstance(origin, type) and issubclass(origin, BaseModel) else \
|
|
81
81
|
[(n, f, PydanticUndefined) for n, f in origin.__annotations__.items()]
|
|
82
82
|
|
|
83
83
|
for field_name, field, default in props:
|