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

Fix stacklevel of warnings #869

Merged
merged 2 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
- text overflow is better handled by `FPDF.write()` & `FPDF.write_html()` - _cf._ [issue #847](https://github.com/PyFPDF/fpdf2/issues/847)
- the initial text color is preserved when using `FPDF.write_html()` - _cf._ [issue #846](https://github.com/PyFPDF/fpdf2/issues/846)
- handle superscript and subscript correctly when rendering `TextLine`- thanks to @Tolker-KU - _cf._ [Pull Request #862](https://github.com/PyFPDF/fpdf2/pull/862)
- make sure warnings always point to the users code - _cf._ [Pull request #869](https://github.com/PyFPDF/fpdf2/pull/869)
### Deprecated
- the `center` optional parameter of [`FPDF.cell()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.cell) is **no more** deprecated, as it allows for horizontal positioning, which is different from text alignment control with `align="C"`

Expand Down
28 changes: 26 additions & 2 deletions fpdf/deprecation.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import contextlib
import inspect
import os.path
import warnings
from types import ModuleType

Expand All @@ -19,7 +22,7 @@ def __getattr__(self, name):
" have been deprecated in favour of"
" FPDF(font_cache_dir=...)",
DeprecationWarning,
stacklevel=2,
stacklevel=get_stack_level(),
)
return None
return super().__getattribute__(name)
Expand All @@ -32,7 +35,28 @@ def __setattr__(self, name, value):
" have been deprecated in favour of"
" FPDF(font_cache_dir=...)",
DeprecationWarning,
stacklevel=2,
stacklevel=get_stack_level(),
)
return
super().__setattr__(name, value)


def get_stack_level() -> int:
"""Get the first place in the call stack that is not inside fpdf2"""

# pylint: disable=import-outside-toplevel
import fpdf # pylint: disable=cyclic-import

pkg_dir = os.path.dirname(fpdf.__file__)
contextlib_dir = os.path.dirname(contextlib.__file__)

frame = inspect.currentframe()
n = 0
while frame is not None:
fname = inspect.getfile(frame)
if fname.startswith(pkg_dir) or fname.startswith(contextlib_dir):
frame = frame.f_back
n += 1
else:
break
return n
47 changes: 28 additions & 19 deletions fpdf/fpdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Image:
PDFEmbeddedFile,
DEFAULT_ANNOT_FLAGS,
)
from .deprecation import WarnOnDeprecatedModuleAttributes
from .deprecation import get_stack_level, WarnOnDeprecatedModuleAttributes
from .encryption import StandardSecurityHandler
from .enums import (
AccessPermission,
Expand Down Expand Up @@ -257,7 +257,7 @@ def __init__(
warnings.warn(
'"font_cache_dir" parameter is deprecated, unused and will soon be removed',
DeprecationWarning,
stacklevel=2,
stacklevel=get_stack_level(),
)
super().__init__()
self.page = 0 # current page number
Expand Down Expand Up @@ -698,7 +698,7 @@ def set_doc_option(self, opt, value):
"set_doc_option() is deprecated and will be removed in a future release. "
"Simply set the `.core_fonts_encoding` property as a replacement.",
DeprecationWarning,
stacklevel=2,
stacklevel=get_stack_level(),
)
if opt != "core_fonts_encoding":
raise FPDFException(f'Unknown document option "{opt}"')
Expand Down Expand Up @@ -1196,7 +1196,7 @@ def polyline(self, point_list, fill=False, polygon=False, style=None):
warnings.warn(
'"fill" parameter is deprecated, use style="F" or style="DF" instead',
DeprecationWarning,
stacklevel=5 if polygon else 3,
stacklevel=get_stack_level(),
)
if fill and style is None:
style = RenderStyle.DF
Expand Down Expand Up @@ -1253,7 +1253,7 @@ def dashed_line(self, x1, y1, x2, y2, dash_length=1, space_length=1):
"dashed_line() is deprecated, and will be removed in a future release. "
"Use set_dash_pattern() and the normal drawing operations instead.",
DeprecationWarning,
stacklevel=3,
stacklevel=get_stack_level(),
)
self.set_dash_pattern(dash_length, space_length)
self.line(x1, y1, x2, y2)
Expand Down Expand Up @@ -1734,7 +1734,7 @@ def add_font(self, family=None, style="", fname=None, uni="DEPRECATED"):
warnings.warn(
'"uni" parameter is deprecated, unused and will soon be removed',
DeprecationWarning,
stacklevel=2,
stacklevel=get_stack_level(),
)

style = "".join(sorted(style.upper()))
Expand All @@ -1759,7 +1759,10 @@ def add_font(self, family=None, style="", fname=None, uni="DEPRECATED"):
fontkey = f"{family.lower()}{style}"
# Check if font already added or one of the core fonts
if fontkey in self.fonts or fontkey in CORE_FONTS:
warnings.warn(f"Core font or font already added '{fontkey}': doing nothing")
warnings.warn(
f"Core font or font already added '{fontkey}': doing nothing",
stacklevel=get_stack_level(),
)
return

self.fonts[fontkey] = TTFFont(self, font_file_path, fontkey, style)
Expand Down Expand Up @@ -1808,13 +1811,15 @@ def set_font(self, family=None, style="", size=0):
if family in self.font_aliases and family + style not in self.fonts:
warnings.warn(
f"Substituting font {family} by core font "
f"{self.font_aliases[family]}"
f"{self.font_aliases[family]}",
stacklevel=get_stack_level(),
)
family = self.font_aliases[family]
elif family in ("symbol", "zapfdingbats") and style:
warnings.warn(
f"Built-in font {family} only has a single 'style' and can't be bold "
f"or italic"
f"or italic",
stacklevel=get_stack_level(),
)
style = ""

Expand Down Expand Up @@ -2352,7 +2357,7 @@ def rotate(self, angle, x=None, y=None):
"It will be removed in a future release. "
"Use the rotation() context manager instead.",
DeprecationWarning,
stacklevel=3,
stacklevel=get_stack_level(),
)
if x is None:
x = self.x
Expand Down Expand Up @@ -2658,7 +2663,8 @@ def cell(
)
if isinstance(border, int) and border not in (0, 1):
warnings.warn(
'Integer values for "border" parameter other than 1 are currently ignored'
'Integer values for "border" parameter other than 1 are currently ignored',
stacklevel=get_stack_level(),
)
border = 1
new_x = XPos.coerce(new_x)
Expand Down Expand Up @@ -2690,7 +2696,7 @@ def cell(
f" Instead of ln={ln} use new_x=XPos.{new_x.name}, new_y=YPos.{new_y.name}."
),
DeprecationWarning,
stacklevel=3,
stacklevel=get_stack_level(),
)
# Font styles preloading must be performed before any call to FPDF.get_string_width:
txt = self.normalize_text(txt)
Expand Down Expand Up @@ -2766,7 +2772,8 @@ def _render_styled_text_line(
"""
if isinstance(border, int) and border not in (0, 1):
warnings.warn(
'Integer values for "border" parameter other than 1 are currently ignored'
'Integer values for "border" parameter other than 1 are currently ignored',
stacklevel=get_stack_level(),
)
border = 1
styled_txt_width = text_line.text_width
Expand Down Expand Up @@ -3344,7 +3351,7 @@ def multi_cell(
'The parameter "split_only" is deprecated.'
' Use instead dry_run=True and output="LINES".',
DeprecationWarning,
stacklevel=3,
stacklevel=get_stack_level(),
)
if dry_run or split_only:
with self._disable_writing():
Expand Down Expand Up @@ -3404,7 +3411,7 @@ def multi_cell(
f" Instead of ln={ln} use new_x=XPos.{new_x.name}, new_y=YPos.{new_y.name}."
),
DeprecationWarning,
stacklevel=3,
stacklevel=get_stack_level(),
)
align = Align.coerce(align)

Expand Down Expand Up @@ -3709,7 +3716,7 @@ def image(
warnings.warn(
'"type" parameter is deprecated, unused and will soon be removed',
DeprecationWarning,
stacklevel=3,
stacklevel=get_stack_level(),
)
if str(name).endswith(".svg"):
# Insert it as a PDF path:
Expand Down Expand Up @@ -3851,7 +3858,8 @@ def _vector_image(
svg = SVGObject(img.getvalue())
if not svg.viewbox and svg.width and svg.height:
warnings.warn(
'<svg> has no "viewBox", using its "width" & "height" as default "viewBox"'
'<svg> has no "viewBox", using its "width" & "height" as default "viewBox"',
stacklevel=get_stack_level(),
)
svg.viewbox = 0, 0, svg.width, svg.height
if w == 0 and h == 0:
Expand Down Expand Up @@ -4345,7 +4353,8 @@ def code39(self, txt, x, y, w=1.5, h=5):
warnings.warn(
# pylint: disable=implicit-str-concat
"Code 39 input must start and end with a '*' character to be valid."
" This method does not insert it automatically."
" This method does not insert it automatically.",
stacklevel=get_stack_level(),
)
chars = {
"0": "nnnwwnwnn",
Expand Down Expand Up @@ -4717,7 +4726,7 @@ def output(
warnings.warn(
'"dest" parameter is deprecated, unused and will soon be removed',
DeprecationWarning,
stacklevel=2,
stacklevel=get_stack_level(),
)
# Finish document if necessary:
if not self.buffer:
Expand Down
3 changes: 2 additions & 1 deletion fpdf/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from .enums import TextEmphasis, XPos, YPos
from .errors import FPDFException
from .deprecation import get_stack_level
from .fonts import FontFace
from .table import Table, TableBordersLayout

Expand Down Expand Up @@ -726,5 +727,5 @@ def __init__(self, *args, **kwargs):
"The HTMLMixin class is deprecated. "
"Simply use the FPDF class as a replacement.",
DeprecationWarning,
stacklevel=2,
stacklevel=get_stack_level(),
)
4 changes: 3 additions & 1 deletion fpdf/recorder.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import types, warnings
from copy import deepcopy

from .deprecation import get_stack_level
from .errors import FPDFException


Expand Down Expand Up @@ -48,7 +49,8 @@ def replay(self):
result = func(*args, **kwargs)
if isinstance(result, types.GeneratorType):
warnings.warn(
"Detected usage of a context manager inside an unbreakable() section, which is not supported"
"Detected usage of a context manager inside an unbreakable() section, which is not supported",
stacklevel=get_stack_level(),
)
# The results of other methods can also be invalidated: .pages_count, page_no(), get_x() / get_y(), will_page_break()
except Exception as error:
Expand Down
7 changes: 4 additions & 3 deletions fpdf/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import csv, locale, warnings

from .deprecation import get_stack_level
from .errors import FPDFException
from .fpdf import FPDF

Expand Down Expand Up @@ -480,7 +481,7 @@ def _code39(
warnings.warn(
"code39 arguments x/y/w/h are deprecated, please use x1/y1/y2/size instead",
DeprecationWarning,
stacklevel=2,
stacklevel=get_stack_level(),
)
pdf = self.pdf
if pdf.fill_color.serialize().lower() != _rgb_as_str(foreground):
Expand Down Expand Up @@ -637,7 +638,7 @@ def __init__(
warnings.warn(
'"infile" is deprecated, unused and will soon be removed',
DeprecationWarning,
stacklevel=2,
stacklevel=get_stack_level(),
)
for arg in (
"format",
Expand Down Expand Up @@ -684,7 +685,7 @@ def render(self, outfile=None, dest=None):
warnings.warn(
'"dest" is deprecated, unused and will soon be removed',
DeprecationWarning,
stacklevel=2,
stacklevel=get_stack_level(),
)
self.pdf.set_font("helvetica", "B", 16)
self.pdf.set_auto_page_break(False, margin=0)
Expand Down
5 changes: 4 additions & 1 deletion test/errors/test_FPDF_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def test_units():

def test_doc_option_only_core_fonts_encoding():
pdf = fpdf.FPDF()
with pytest.warns(DeprecationWarning):
with pytest.warns(DeprecationWarning) as record:
pdf.set_doc_option("core_fonts_encoding", 4)
assert pdf.core_fonts_encoding == 4

Expand All @@ -83,6 +83,9 @@ def test_doc_option_only_core_fonts_encoding():
msg = 'Unknown document option "not core_fonts_encoding"'
assert str(e.value) == msg

for r in record:
assert r.filename == __file__


def test_adding_content_after_closing():
pdf = fpdf.FPDF()
Expand Down
Loading