Home > other >  Python - Indent on a Return Statement
Python - Indent on a Return Statement

Time:01-01

I am slightly revamping an old function i wrote a while back to produce a report. Initially, the generated report was routed to a specified path for the user to go pick up, but i decided to try to give the user the option to also download the report at point of request (by incorporating send_file). Hence the code block(s) below.

EXHIBIT A

@VVV.route("/reports/users")
def users_report():
    if not session.get("logged_in"):
        return render_template("login.html")
    else:
        suffix = datetime.now()
        suffix2 = str(suffix)
        suffix3 = suffix2.split(" ")
        suffix4 = suffix.strftime('%H%M%S')
        with open(r'<path>\tahnreports_sysusers_%s_%s.csv' %(suffix3[0],suffix4), 'w', newline='') as start_key:
            #newline parameter avoids the extra line space between rows in the csv.

            csv_header = ("WID", "F_NAME", "L_NAME", "ORG_ROLE", "ORG_STATUS", "SYS_LOGIN_ID")
            csv_out_01 = csv.writer(start_key)
            csv_out_01.writerow(csv_header)
            x15 = divo.session.query(pearl.work_id, pearl.user_fname, pearl.user_lname, pearl.user_category, pearl.user_status,
                                    pearl.login_id)
            for i in x15:
                csv_out_02 = csv.writer(start_key)
                csv_out_02.writerow(i)
            AAA = (r'<path>\tahnreports_sysusers_%s_%s.csv' %(suffix3[0],suffix4))
            return send_file(AAA, as_attachment=True)

EXHIBIT B:

@VVV.route("/reports/users")
def users_report():
    if not session.get("logged_in"):
        return render_template("login.html")
    else:
        suffix = datetime.now()
        suffix2 = str(suffix)
        suffix3 = suffix2.split(" ")
        suffix4 = suffix.strftime('%H%M%S')
        with open(r'<path>\tahnreports_sysusers_%s_%s.csv' %(suffix3[0],suffix4), 'w', newline='') as start_key:
            #newline parameter avoids the extra line space between rows in the csv.

            csv_header = ("WID", "F_NAME", "L_NAME", "ORG_ROLE", "ORG_STATUS", "SYS_LOGIN_ID")
            csv_out_01 = csv.writer(start_key)
            csv_out_01.writerow(csv_header)
            x15 = divo.session.query(pearl.work_id, pearl.user_fname, pearl.user_lname, pearl.user_category, pearl.user_status,
                                    pearl.login_id)
            for i in x15:
                csv_out_02 = csv.writer(start_key)
                csv_out_02.writerow(i)
            AAA = (r'<path>\tahnreports_sysusers_%s_%s.csv' %(suffix3[0],suffix4))
    return send_file(AAA, as_attachment=True)

My issue is trying to understand why these 2 code blocks behave differently. Both functions below are identical except for one small difference - the indent on the return statement. And while they both generate AND also prompt the user to download the report, Exhibit_A sometimes produces an empty file, while Exhibit_B always produces a genuine report. I figure this is tied to the indent of the return statement, but i can't seem to quite put my thumb on it.

To further elaborate on the issue. I generated a report 10 times each, using both functions. Exhibit_A produced 8 out of 10 reports, 2 of which are blank files, while Exhibit_B produces 10 out of 10. Reports from both functions look intact with the exception of the 2 blank files from Exhibit_A. I'd love some feedback on the odd behavior from Exhibit_A.

ADDENDUM: Exhibit_B is likely best practice but my thinking is that Exhibit_A should work as well since the "AAA" variable is outside of the 'for-loop sequence', and it does work - but not all the time. Feedback appreciated. Thanks.

exhibit_A

exhibit_B

CodePudding user response:

In A, you call send_file inside the with context, meaning the file is still open for writing, and may not have been flushed to disk (or readable).

In B, you wait until the with has ended (and hence the file has been closed) before calling send_file.

(edit) FWIW, here's how I'd clean it up for readability -- the extra level of indentation added by the else makes the with subtlety harder to spot, and all the extra variables don't help either. It wasn't even obvious to me on first glance that the file you're sending in send_file is the same one you were writing because the expression that builds the file path is both overly complex and copy pasted in two places. Having a different writer for each row is also confusing -- I don't think it hurts anything, but I don't think it adds any benefit either.

@VVV.route("/reports/users")
def users_report():
    if not session.get("logged_in"):
        return render_template("login.html")

    output_path = (
        r'<path>\tahnreports_sysusers_%s.csv'
        % datetime.now().strftime('%Y-%m-%d_%H%M%S')
    )
    with open(output_path, 'w', newline='') as file:
        csv_out = csv.writer(file)
        csv_out.writerow((
            "WID",
            "F_NAME",
            "L_NAME",
            "ORG_ROLE",
            "ORG_STATUS",
            "SYS_LOGIN_ID"
        ))  # header
        csv_out.writerows(divo.session.query(
            pearl.work_id,
            pearl.user_fname,
            pearl.user_lname,
            pearl.user_category,
            pearl.user_status,
            pearl.login_id
        ))  # data
    return send_file(output_path, as_attachment=True)
  • Related