Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/import_export/formats/base_formats.py: 58%
120 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1import html
3import tablib
4from tablib.formats import registry
7class Format:
8 def get_title(self):
9 return type(self)
11 def create_dataset(self, in_stream):
12 """
13 Create dataset from given string.
14 """
15 raise NotImplementedError()
17 def export_data(self, dataset, escape_output=False, **kwargs):
18 """
19 Returns format representation for given dataset.
20 """
21 raise NotImplementedError()
23 def is_binary(self):
24 """
25 Returns if this format is binary.
26 """
27 return True
29 def get_read_mode(self):
30 """
31 Returns mode for opening files.
32 """
33 return 'rb'
35 def get_extension(self):
36 """
37 Returns extension for this format files.
38 """
39 return ""
41 def get_content_type(self):
42 # For content types see
43 # https://www.iana.org/assignments/media-types/media-types.xhtml
44 return 'application/octet-stream'
46 @classmethod
47 def is_available(cls):
48 return True
50 def can_import(self):
51 return False
53 def can_export(self):
54 return False
57class TablibFormat(Format):
58 TABLIB_MODULE = None
59 CONTENT_TYPE = 'application/octet-stream'
61 def __init__(self, encoding=None):
62 self.encoding = encoding
64 def get_format(self):
65 """
66 Import and returns tablib module.
67 """
68 if not self.TABLIB_MODULE: 68 ↛ 69line 68 didn't jump to line 69, because the condition on line 68 was never true
69 raise AttributeError("TABLIB_MODULE must be defined")
70 key = self.TABLIB_MODULE.split('.')[-1].replace('_', '')
71 return registry.get_format(key)
73 @classmethod
74 def is_available(cls):
75 try:
76 cls().get_format()
77 except (tablib.core.UnsupportedFormat, ImportError):
78 return False
79 return True
81 def get_title(self):
82 return self.get_format().title
84 def create_dataset(self, in_stream, **kwargs):
85 return tablib.import_set(in_stream, format=self.get_title())
87 def export_data(self, dataset, escape_output=False, **kwargs):
88 return dataset.export(self.get_title(), **kwargs)
90 def get_extension(self):
91 return self.get_format().extensions[0]
93 def get_content_type(self):
94 return self.CONTENT_TYPE
96 def can_import(self):
97 return hasattr(self.get_format(), 'import_set')
99 def can_export(self):
100 return hasattr(self.get_format(), 'export_set')
103class TextFormat(TablibFormat):
105 def create_dataset(self, in_stream, **kwargs):
106 if isinstance(in_stream, bytes) and self.encoding:
107 in_stream = in_stream.decode(self.encoding)
108 return super().create_dataset(in_stream, **kwargs)
110 def get_read_mode(self):
111 return 'r'
113 def is_binary(self):
114 return False
117class CSV(TextFormat):
118 TABLIB_MODULE = 'tablib.formats._csv'
119 CONTENT_TYPE = 'text/csv'
122class JSON(TextFormat):
123 TABLIB_MODULE = 'tablib.formats._json'
124 CONTENT_TYPE = 'application/json'
127class YAML(TextFormat):
128 TABLIB_MODULE = 'tablib.formats._yaml'
129 # See https://stackoverflow.com/questions/332129/yaml-mime-type
130 CONTENT_TYPE = 'text/yaml'
133class TSV(TextFormat):
134 TABLIB_MODULE = 'tablib.formats._tsv'
135 CONTENT_TYPE = 'text/tab-separated-values'
137 def create_dataset(self, in_stream, **kwargs):
138 return super().create_dataset(in_stream, **kwargs)
141class ODS(TextFormat):
142 TABLIB_MODULE = 'tablib.formats._ods'
143 CONTENT_TYPE = 'application/vnd.oasis.opendocument.spreadsheet'
146class HTML(TextFormat):
147 TABLIB_MODULE = 'tablib.formats._html'
148 CONTENT_TYPE = 'text/html'
150 def export_data(self, dataset, escape_output=False, **kwargs):
151 if escape_output:
152 for _ in dataset:
153 row = dataset.lpop()
154 row = [html.escape(str(cell)) for cell in row]
155 dataset.append(row)
156 return dataset.export(self.get_title(), **kwargs)
159class XLS(TablibFormat):
160 TABLIB_MODULE = 'tablib.formats._xls'
161 CONTENT_TYPE = 'application/vnd.ms-excel'
163 def create_dataset(self, in_stream):
164 """
165 Create dataset from first sheet.
166 """
167 import xlrd
168 xls_book = xlrd.open_workbook(file_contents=in_stream)
169 dataset = tablib.Dataset()
170 sheet = xls_book.sheets()[0]
172 dataset.headers = sheet.row_values(0)
173 for i in range(1, sheet.nrows):
174 dataset.append(sheet.row_values(i))
175 return dataset
178class XLSX(TablibFormat):
179 TABLIB_MODULE = 'tablib.formats._xlsx'
180 CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
182 def create_dataset(self, in_stream):
183 """
184 Create dataset from first sheet.
185 """
186 from io import BytesIO
188 import openpyxl
190 # 'data_only' means values are read from formula cells, not the formula itself
191 xlsx_book = openpyxl.load_workbook(BytesIO(in_stream), read_only=True, data_only=True)
193 dataset = tablib.Dataset()
194 sheet = xlsx_book.active
196 # obtain generator
197 rows = sheet.rows
198 dataset.headers = [cell.value for cell in next(rows)]
200 for row in rows:
201 row_values = [cell.value for cell in row]
202 dataset.append(row_values)
203 return dataset
206#: These are the default formats for import and export. Whether they can be
207#: used or not is depending on their implementation in the tablib library.
208DEFAULT_FORMATS = [fmt for fmt in (
209 CSV,
210 XLS,
211 XLSX,
212 TSV,
213 ODS,
214 JSON,
215 YAML,
216 HTML,
217) if fmt.is_available()]