introduction
File processing and exception handling are common requirements when developing web applications. Especially when using the Flask framework for file upload, processing, and downloading, it is crucial to properly handle return value types and exceptions. This article will analyze how to optimize file processing logic in Python Flask applications and solve common exception problems through a practical case.
Problem background
In a Flask-based file processing tool, the user uploads the Excel file and returns the result file after the system processes it. But in actual operation, the following error occurs:
AttributeError: 'list' object has no attribute 'read'
This error indicates that Flask's send_file method expects to receive a file path (string), but actually passes in a list, which makes the file content unable to be read.
In addition, the following logs appear:
2025-05-20 01:05:37,500 - ERROR - process_and_export_results Returns an invalid type
This indicates that the return value type of the backend processing function does not meet expectations, resulting in the failure of subsequent operations.
Problem analysis
1. Cause of error
The process_single_thread function returns [output_file] (a list containing a single file path), but what send_file requires is output_file (a string).
The caller did not type check the return value and passed it directly to the send_file, resulting in an AttributeError.
2. Deep causes
Interface design is inconsistent: the processing function returns a list, but the caller expects a string.
Inadequate exception handling: The return value is not checked, causing the error to propagate to the Flask middleware.
Log information is incomplete: The error log fails to clearly indicate the problem.
Solution
1. Optimize process_single_thread return value
Original code:
def process_single_thread(raw_results, cookie, timestamp, base_filename, secretKey, receiver_email): # ...processing logic... return [output_file] # Return to list
After optimization:
def process_single_thread(raw_results, cookie, timestamp, base_filename, secretKey, receiver_email): """Single-threaded data processing Args: raw_results: List of pending raw data cookies: cookies used for processing timestamp: timestamp, used to generate filenames base_filename: base file name receiver_email: The email address of the received result Returns: str: Output file path (returns directly to strings, not lists) """ # ...processing logic... return output_file # Return the string directly
Optimization points:
- Modify the return value to a string, which is in line with the expected send_file.
- Update the function document and specify the return value type.
2. Caller enhances verification
In , add a check for the return value:
try: output_file = process_and_export_results(filepath, cookie, nationwide, receiver_email) # Check whether the return value is a valid path if not isinstance(output_file, str): (f"Invalid return value type: {type(output_file)}") return "Handling errors:Internal service exception", 500 if not (output_file): (f"The file does not exist: {output_file}") return "Handling errors:The result file is not generated", 500 return send_file(output_file, as_attachment=True, download_name='') except Exception as e: (f"File handling exception: {str(e)}", exc_info=True) return f"Handling errors:{str(e)}", 500
Optimization points:
- Checks whether the return value is a string.
- Make sure the file exists and avoid FileNotFoundError.
- Catch and log exceptions, returning friendly error messages.
3. Log Optimization
Add detailed logs in key steps to facilitate troubleshooting:
(f"Start processing files: {filepath}") (f"National Matching Mode: {'Open' if nationwide else 'closure'}") (f"Receive email: {receiver_email}") output_file = process_and_export_results(filepath, cookie, nationwide, receiver_email) (f"Processing is completed,Output file: {output_file}")
Completely optimized code
deal_excel_file.py (after optimization)
import os import logging from datetime import datetime logger = (__name__) def process_single_thread(raw_results, cookie, timestamp, base_filename, secretKey, receiver_email): """Single thread processing data, returning file path (string)""" final_results = [] total_count = len(raw_results) success_count = 0 for idx, item in enumerate(raw_results, 1): record = process_single_item(item, idx, cookie, secretKey, False) final_results.append(record) if record["Match Status"] == "success": success_count += 1 success_rate = (success_count / total_count) * 100 if total_count > 0 else 0 output_file = f"result_{timestamp}_{base_filename}.xlsx" ( f"[{base_filename}] Processing is completed - total: {total_count}, " f"success: {success_count}, fail: {total_count - success_count}, " f"success率: {success_rate:.2f}%" ) export_to_excel(final_results, output_file) if receiver_email: try: send_email_with_attachment(output_file, receiver_email) (f"[{base_filename}] The results have been sent to the email address: {receiver_email}") except Exception as e: (f"[{base_filename}] 邮件发送fail: {str(e)}") return output_file # Return the string directly
(After optimization)
from flask import Flask, request, send_file import os import logging app = Flask(__name__) ['UPLOAD_FOLDER'] = 'uploads' (['UPLOAD_FOLDER'], exist_ok=True) ( level=, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[(''), ()] ) logger = (__name__) @('/', methods=['POST']) def upload_file(): try: cookie = ('cookie', '').strip() nationwide = ('nationwide') == '1' receiver_email = ('email', '').strip() (f"Start processing of requests,Cookie: {cookie[:10]}...") # Avoid log leaks complete cookies if not cookie: return "Please provide validCookie", 400 # Check file upload if 'file' not in : return "File not uploaded", 400 file = ['file'] if not ('.xlsx'): return "Support only .xlsx files", 400 # Save uploaded file timestamp = ().strftime("%Y%m%d%H%M%S") filepath = (['UPLOAD_FOLDER'], f'upload_{timestamp}.xlsx') (filepath) # Process files output_file = process_and_export_results(filepath, cookie, nationwide, receiver_email) # Check the return value if not isinstance(output_file, str): (f"Invalid return value type: {type(output_file)}") return "Internal service error", 500 if not (output_file): (f"The file does not exist: {output_file}") return "The result file generation failed", 500 return send_file(output_file, as_attachment=True, download_name='') except Exception as e: (f"An error occurred while processing the request: {str(e)}", exc_info=True) return f"Server Error: {str(e)}", 500 if __name__ == '__main__': (host='0.0.0.0', port=5000)
Summarize
Key Optimization Points
1. Unified return value types: Ensure that the processing function returns the string path, not the list.
2. Enhance exception handling:
- Check if the file exists.
- Catch and record exceptions to avoid 500 errors being exposed directly to the user.
3. Improve logs:
- Key steps logging.
- Avoid leakage of sensitive information (such as complete cookies).
Best Practices
- Interface design consistency: The function return value should meet the caller's expectations.
- Defensive programming: Verify input and return values.
- Detailed log: Easy to quickly locate problems.
Through the above optimizations, the system can process files more stably and provide clear error information to improve the user experience.
This is the article about this practical guide on file and exception handling in Python Flask. For more related Python Flask application content, please search for my previous articles or continue browsing the related articles below. I hope you will support me in the future!