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

1import html 

2 

3import tablib 

4from tablib.formats import registry 

5 

6 

7class Format: 

8 def get_title(self): 

9 return type(self) 

10 

11 def create_dataset(self, in_stream): 

12 """ 

13 Create dataset from given string. 

14 """ 

15 raise NotImplementedError() 

16 

17 def export_data(self, dataset, escape_output=False, **kwargs): 

18 """ 

19 Returns format representation for given dataset. 

20 """ 

21 raise NotImplementedError() 

22 

23 def is_binary(self): 

24 """ 

25 Returns if this format is binary. 

26 """ 

27 return True 

28 

29 def get_read_mode(self): 

30 """ 

31 Returns mode for opening files. 

32 """ 

33 return 'rb' 

34 

35 def get_extension(self): 

36 """ 

37 Returns extension for this format files. 

38 """ 

39 return "" 

40 

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' 

45 

46 @classmethod 

47 def is_available(cls): 

48 return True 

49 

50 def can_import(self): 

51 return False 

52 

53 def can_export(self): 

54 return False 

55 

56 

57class TablibFormat(Format): 

58 TABLIB_MODULE = None 

59 CONTENT_TYPE = 'application/octet-stream' 

60 

61 def __init__(self, encoding=None): 

62 self.encoding = encoding 

63 

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) 

72 

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 

80 

81 def get_title(self): 

82 return self.get_format().title 

83 

84 def create_dataset(self, in_stream, **kwargs): 

85 return tablib.import_set(in_stream, format=self.get_title()) 

86 

87 def export_data(self, dataset, escape_output=False, **kwargs): 

88 return dataset.export(self.get_title(), **kwargs) 

89 

90 def get_extension(self): 

91 return self.get_format().extensions[0] 

92 

93 def get_content_type(self): 

94 return self.CONTENT_TYPE 

95 

96 def can_import(self): 

97 return hasattr(self.get_format(), 'import_set') 

98 

99 def can_export(self): 

100 return hasattr(self.get_format(), 'export_set') 

101 

102 

103class TextFormat(TablibFormat): 

104 

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) 

109 

110 def get_read_mode(self): 

111 return 'r' 

112 

113 def is_binary(self): 

114 return False 

115 

116 

117class CSV(TextFormat): 

118 TABLIB_MODULE = 'tablib.formats._csv' 

119 CONTENT_TYPE = 'text/csv' 

120 

121 

122class JSON(TextFormat): 

123 TABLIB_MODULE = 'tablib.formats._json' 

124 CONTENT_TYPE = 'application/json' 

125 

126 

127class YAML(TextFormat): 

128 TABLIB_MODULE = 'tablib.formats._yaml' 

129 # See https://stackoverflow.com/questions/332129/yaml-mime-type 

130 CONTENT_TYPE = 'text/yaml' 

131 

132 

133class TSV(TextFormat): 

134 TABLIB_MODULE = 'tablib.formats._tsv' 

135 CONTENT_TYPE = 'text/tab-separated-values' 

136 

137 def create_dataset(self, in_stream, **kwargs): 

138 return super().create_dataset(in_stream, **kwargs) 

139 

140 

141class ODS(TextFormat): 

142 TABLIB_MODULE = 'tablib.formats._ods' 

143 CONTENT_TYPE = 'application/vnd.oasis.opendocument.spreadsheet' 

144 

145 

146class HTML(TextFormat): 

147 TABLIB_MODULE = 'tablib.formats._html' 

148 CONTENT_TYPE = 'text/html' 

149 

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) 

157 

158 

159class XLS(TablibFormat): 

160 TABLIB_MODULE = 'tablib.formats._xls' 

161 CONTENT_TYPE = 'application/vnd.ms-excel' 

162 

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] 

171 

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 

176 

177 

178class XLSX(TablibFormat): 

179 TABLIB_MODULE = 'tablib.formats._xlsx' 

180 CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 

181 

182 def create_dataset(self, in_stream): 

183 """ 

184 Create dataset from first sheet. 

185 """ 

186 from io import BytesIO 

187 

188 import openpyxl 

189 

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) 

192 

193 dataset = tablib.Dataset() 

194 sheet = xlsx_book.active 

195 

196 # obtain generator 

197 rows = sheet.rows 

198 dataset.headers = [cell.value for cell in next(rows)] 

199 

200 for row in rows: 

201 row_values = [cell.value for cell in row] 

202 dataset.append(row_values) 

203 return dataset 

204 

205 

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()]