py-pdf / fpdf2

Simple PDF generation for Python
https://py-pdf.github.io/fpdf2/
GNU Lesser General Public License v3.0
1.12k stars 254 forks source link

Improve Error Reporting for 'FPDFException: Content cannot be added on a finalized document, after calling output()' #692

Closed robertblindt closed 1 year ago

robertblindt commented 1 year ago

Please explain your intent I got the error message "FPDFException: Content cannot be added on a finalized document, after calling output()" while moving from 'example space' to a finalized project, and it was not clear to me at first what was wrong with my code. Below is an image of the code I was struggling with, with one line in its 'non-functional' state. The mistake that I made was using 'pdf.add_page('L')' in the class instantiation instead of 'self.add_page('L')', and it gave me the above exception.

Describe the solution you'd like Since I never used a '.output()' prior to getting the exception, would it be possible to alter the error message to tell me that I needed to operate on 'self' ie the instance, rather than the pdf object.

FPDF_pdf_inplaceof_self

Lucas-C commented 1 year ago

Hi @robertblindt!

Thank you for reporting this 😊

What's not clear for me here is where does the pdf variable comes from in this code ? It must be defined in parts of you code you did not share, otherwise you would have seen an error like NameError: name 'pdf' is not defined.

I'd be open to improve exception messages of fpdf2 but, with the information your provided, I do not see how I could do this for now. Could you maybe try to craft a minimal error-reproducing code? https://stackoverflow.com/help/minimal-reproducible-example

gmischler commented 1 year ago

Since I never used a '.output()' prior to getting the exception, would it be possible to alter the error message to tell me that I needed to operate on 'self' ie the instance, rather than the pdf object.

How is the library supposed to know what name you are using to access its current instance? That is fundamentally impossible, and also entirely irrelevant to its inner workings.

However, it is a bad sign for your application design, that apparently an already "spent" FPDF() instance is in scope under the (global?) name "pdf" in the code shown above (there is no such thing as a "pdf object"). The exception you see quite commonly happens when people move their code to a web environment, where some CMS may offer to keep variables in scope between method calls. Always make sure to use a fresh instance for a new document, and avoid keeping old instances accessible.

robertblindt commented 1 year ago

Very sorry about my delayed response. I am pretty much brand new to programming in a program with dreadful guidance, and my mentor pushed me to submit this against my belief that this was a real issue. (I explained to him that this was my own issue with being not careful, but he went on a tirade about how it shouldn't be like this) I am sorry that I do not know the correct terminology, and I will be sure to not submit something like this again. Have a great day!

Lucas-C commented 1 year ago

Very sorry about my delayed response. I am pretty much brand new to programming in a program with dreadful guidance, and my mentor pushed me to submit this against my belief that this was a real issue. (I explained to him that this was my own issue with being not careful, but he went on a tirade about how it shouldn't be like this) I am sorry that I do not know the correct terminology, and I will be sure to not submit something like this again. Have a great day!

Hey @robertblindt! It's totally fine 😊 Welcome to the new world of programming ^^ I don't know your mentor, but as for myself, I find it a good thing that you took this opportunity to connect with us over GitHub! As a maintainer, I welcome all questions. As long as people try to learn and do not repear the same mistakes, I'm fine with even the dumbest of them! :D

robertblindt commented 1 year ago

Thanks! It has been an adventure getting up and running, but I am starting to see concepts and processes fit together in a more cohesive way. I'm encouraged that in time I will get faster and better at finding these little parsing/referencing issues.

I just tried to replicate my issue on a pair of fresh documents, and pinned down exactly where it came from. In the file that I had created the customized FPDF class I had left a 'test pdf build' block not commented out, so I think when I called "pdf.add_page('L')", it was trying to interact with the pdf that would have been ran during my import.

File containing class:

from fpdf import FPDF

class PDF(FPDF):
    def header(self):
        self.set_font("helvetica", "BUI", 12)
        self.cell(0, 5, "Album Comparison Report", border=0, align="C")
        self.ln(8)

    def add_textbox(self):
        self.add_page()
        self.cell(0, 10,'sometext goes here')
        self.ln(8)

    def add_another_textbox(self):
        pdf.add_page('L')
        self.cell(0,10,'something')
        self.ln(8)
        self.cell(0,10,'adding another function the wrong way')

pdf = PDF()
pdf.add_textbox()
pdf.add_another_textbox()
pdf.output('new_pdf.pdf')

File containing app:

import streamlit as st
from fpdf_self_ref_issue_02222023 import PDF

export_as_pdf = st.button("Export Report")

if export_as_pdf:
    pdf = PDF()
    pdf.add_textbox()
    pdf.add_another_textbox()
    pdf.output('new_pdf.pdf')

When I comment out the building of the PDF in the 'file containing class', the app threw an error telling me that there was no reference for 'pdf' on the problem line mentioned before. This just further points towards the fact that I need to just be more careful with modularizing my functions and managing my variable space when doing imports. Thank you for reaching out!

Im sorry that the markdown isn't working. Just in case someone gets pinged every time I edit this, I will stop messing with it for now. Ill try to look into what I am doing wrong here later.

indentation is correct 0

indentation is correct 1

Lucas-C commented 1 year ago

Im sorry that the markdown isn't working. Just in case someone gets pinged every time I edit this, I will stop messing with it for now. Ill try to look into what I am doing wrong here later.

Don't worry, we are not notified for each and every of your edits ^^

Also, check those links to better understand how to put blocks of code with GitHub Markdown:

I edited your last comment to insert triple backquotes instead of simple backquotes