forked from anvilco/python-anvil
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodels.py
More file actions
75 lines (62 loc) · 2.89 KB
/
models.py
File metadata and controls
75 lines (62 loc) · 2.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import base64
import os
from io import BufferedReader, BytesIO
from mimetypes import guess_type
from pydantic import BaseModel, ConfigDict
from python_anvil.api_resources.base import underscore_to_camel
class FileCompatibleBaseModel(BaseModel):
"""
Patched model_dump to extract file objects from SerializationIterator.
Becaus of Pydantic V2. Return as BufferedReader or base64 encoded dict as needed.
"""
# Allow extra fields even if it is not defined. This will allow models
# to be more flexible if features are added in the Anvil API, but
# explicit support hasn't been added yet to this library.
model_config = ConfigDict(
alias_generator=underscore_to_camel, populate_by_name=True, extra="allow"
)
def _iterator_to_buffered_reader(self, value):
content = bytearray()
try:
while True:
content.extend(next(value))
except StopIteration:
# Create a BytesIO with the content
bio = BytesIO(bytes(content))
# Create a BufferedReader with the content
reader = BufferedReader(bio) # type: ignore[arg-type]
return reader
def _check_if_serialization_iterator(self, value):
return str(type(value).__name__) == 'SerializationIterator' and hasattr(
value, '__next__'
)
def _process_file_data(self, file_obj):
"""Process file object into base64 encoded dict format."""
# Read the file data and encode it as base64
file_content = file_obj.read()
# Get filename - handle both regular files and BytesIO objects
filename = getattr(file_obj, 'name', "document.pdf")
if isinstance(filename, (bytes, bytearray)):
filename = filename.decode('utf-8')
# manage mimetype based on file extension
mimetype = guess_type(filename)[0] or 'application/pdf'
return {
'data': base64.b64encode(file_content).decode('utf-8'),
'mimetype': mimetype,
'filename': os.path.basename(filename),
}
def model_dump(self, **kwargs):
data = super().model_dump(**kwargs)
for key, value in data.items():
if key == 'file' and self._check_if_serialization_iterator(value):
# Direct file case
file_obj = self._iterator_to_buffered_reader(value)
data[key] = self._process_file_data(file_obj)
elif key == 'files' and isinstance(value, list):
# List of objects case
for index, item in enumerate(value):
if isinstance(item, dict) and 'file' in item:
if self._check_if_serialization_iterator(item['file']):
file_obj = self._iterator_to_buffered_reader(item['file'])
data[key][index]['file'] = self._process_file_data(file_obj)
return data