Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

local_context() blocks appear to "leak" into one another #1204

Closed
smitelli opened this issue Jun 16, 2024 · 6 comments
Closed

local_context() blocks appear to "leak" into one another #1204

smitelli opened this issue Jun 16, 2024 · 6 comments
Assignees

Comments

@smitelli
Copy link

smitelli commented Jun 16, 2024

When using local_context() in the main document and header/footer methods, the parameters set in the document leak into the header/footer in unexpected ways:

from fpdf import FPDF


class SubclassFPDF(FPDF):
    def header(self):
        with self.local_context(text_color='#00ff00', font_size=12):  # LABEL A
            self.cell(text=f'Header {self.page_no()}')
        self.ln()

    def footer(self):
        self.set_y(-15)
        with self.local_context(text_color='#0000ff', font_size=12):  # LABEL B
            self.cell(text=f'Footer {self.page_no()}')


pdf = SubclassFPDF()
pdf.set_font(family='helvetica', size=12)
pdf.add_page()

with pdf.local_context(font_size=36):  # LABEL C
    pdf.multi_cell(w=0, text='\n'.join(f'Line {i + 1}' for i in range(50)))

pdf.output('testcase.pdf')

The expected output is that all header/footer text is in font size 12. The actual output is that the 36pt font defined at label C leaks into the footer() function and overrides the 12pt font defined at label B -- but this only happens on the last page of the document. There is no obvious way to make the font size at B take effect consistently without removing the set_context() at C.

Furthermore, based on my understanding of the set_context() philosophy (briefly... any values set explicitly will take effect, unspecified values continue to use whatever the outer environment had, and when the context exits everything is exactly the way is was before the context was entered) I would think I don't need the explicit font_size=12 at labels A or B at all to use the main document font size. But omitting them causes all headers/footers after the top of page 1 to get the 36pt font from C.

This is fpdf2 version 2.7.9 on both Python 3.9.16 and 3.12.3.

@smitelli smitelli added the bug label Jun 16, 2024
@smitelli
Copy link
Author

Even this is not enough to get the footer on page 3 to use 12pt font:

    def footer(self):
        self.set_y(-15)
        self.set_font_size(12)
        with self.local_context(text_color='#0000ff', font_size=12):
            self.set_font_size(12)
            self.cell(text=f'Footer {self.page_no()}')

@Lucas-C
Copy link
Member

Lucas-C commented Jun 17, 2024

Hi @smitelli

Thank you for the detailed bug report.
I'm having a look at this now

@Lucas-C
Copy link
Member

Lucas-C commented Jun 17, 2024

@allcontributors please add @smitelli for bug

Copy link

@Lucas-C

I've put up a pull request to add @smitelli! 🎉

@Lucas-C Lucas-C self-assigned this Jun 17, 2024
@Lucas-C
Copy link
Member

Lucas-C commented Jun 17, 2024

This is indeed a bug.
I'm trying to figure the best way to fix this...

In the meantime, for this use case, I suggest that use you use the use_font_face() method instead, which is more reliable for now:

from fpdf import FPDF, FontFace


class PDF(FPDF):
    def header(self):
        with self.use_font_face(FontFace(color="#00ff00", size_pt=12)):  # LABEL A
            self.cell(text=f"Header {self.page_no()}")
        self.ln()

    def footer(self):
        self.set_y(-15)
        with self.use_font_face(FontFace(color="#0000ff", size_pt=12)):  # LABEL B
            self.cell(text=f"Footer {self.page_no()}")

pdf = PDF()
pdf.set_font(family="helvetica", size=12)
pdf.add_page()
with pdf.use_font_face(FontFace(size_pt=36)):  # LABEL C
    pdf.multi_cell(w=0, text="\n".join(f"Line {i + 1}" for i in range(21)))

@Lucas-C
Copy link
Member

Lucas-C commented Jun 17, 2024

I opened PR #1207 to fix this bug.

@smitelli If you want, you can test this fix by installing fpdf2 from the master branch:

pip install git+https://github.com/py-pdf/fpdf2.git@master

With this fix, this code should now work as expected, with only a single call to .local_context() needed:

from fpdf import FPDF

class PDF(FPDF):
    def header(self):
        self.cell(text=f"Header {self.page_no()}")
        self.ln()

    def footer(self):
        self.set_y(-15)
        self.cell(text=f"Footer {self.page_no()}")

pdf = PDF()
pdf.set_font(family="helvetica", size=12)
pdf.add_page()
with pdf.local_context(font_size_pt=36):  # LABEL C
    pdf.multi_cell(w=0, text="\n".join(f"Line {i + 1}" for i in range(21)))
pdf.output('testcase.pdf')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants