SoFunction
Updated on 2025-05-20

A practical guide to file and exception handling in Python Flask

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!