| 173 | return validator |
| 174 | |
| 175 | def generate_error_file(error_list: list[RowValidator], head_list: list[str]) -> str: |
| 176 | # If no errors, return empty string |
| 177 | if not error_list: |
| 178 | return "" |
| 179 | |
| 180 | # Build DataFrame from error rows (only include rows that had errors) |
| 181 | df_rows = [err.row for err in error_list] |
| 182 | df = pd.DataFrame(df_rows, columns=head_list) |
| 183 | |
| 184 | tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") |
| 185 | tmp_name = tmp.name |
| 186 | tmp.close() |
| 187 | |
| 188 | with pd.ExcelWriter(tmp_name, engine='xlsxwriter', engine_kwargs={'options': {'strings_to_numbers': False}}) as writer: |
| 189 | df.to_excel(writer, sheet_name='Errors', index=False) |
| 190 | |
| 191 | workbook = writer.book |
| 192 | worksheet = writer.sheets['Errors'] |
| 193 | |
| 194 | # header format similar to downTemplate |
| 195 | header_format = workbook.add_format({ |
| 196 | 'bold': True, |
| 197 | 'font_size': 12, |
| 198 | 'font_name': '微软雅黑', |
| 199 | 'align': 'center', |
| 200 | 'valign': 'vcenter', |
| 201 | 'border': 0, |
| 202 | 'text_wrap': False, |
| 203 | }) |
| 204 | |
| 205 | # apply header format and column widths |
| 206 | for i, col in enumerate(df.columns): |
| 207 | max_length = max( |
| 208 | len(str(col).encode('utf-8')) * 1.1, |
| 209 | (df[col].astype(str)).apply(len).max() if len(df) > 0 else 0 |
| 210 | ) |
| 211 | worksheet.set_column(i, i, max_length + 12) |
| 212 | worksheet.write(0, i, col, header_format) |
| 213 | |
| 214 | worksheet.set_row(0, 30) |
| 215 | for row_idx in range(1, len(df) + 1): |
| 216 | worksheet.set_row(row_idx, 25) |
| 217 | |
| 218 | red_format = workbook.add_format({'font_color': 'red'}) |
| 219 | |
| 220 | # Add comments and set red font for each erroneous cell. |
| 221 | # Note: pandas wrote header at row 0, data starts from row 1 in the sheet. |
| 222 | for sheet_row_idx, err in enumerate(error_list, start=1): |
| 223 | for col_idx, message in err.error_info.items(): |
| 224 | if message: |
| 225 | comment_text = str(message) |
| 226 | worksheet.write_comment(sheet_row_idx, col_idx, comment_text) |
| 227 | try: |
| 228 | cell_value = df.iat[sheet_row_idx - 1, col_idx] |
| 229 | except Exception: |
| 230 | cell_value = None |
| 231 | worksheet.write(sheet_row_idx, col_idx, cell_value, red_format) |
| 232 | |