Skip to content

Commit

Permalink
Fix stacklevel of warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
Tolker-KU committed Jul 26, 2023
1 parent 54d2eb0 commit e196953
Show file tree
Hide file tree
Showing 16 changed files with 159 additions and 50 deletions.
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`- [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

0 comments on commit e196953

Please sign in to comment.