From d26ad5f5d6addf842e7318c803fc8c732f46af00 Mon Sep 17 00:00:00 2001 From: Tyler Porter Date: Mon, 18 May 2026 20:21:51 -0400 Subject: [PATCH 1/2] Add a custom warning class to avoid monkeypatching global warning format --- src/bdfparser/bdfparser.py | 46 +++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/bdfparser/bdfparser.py b/src/bdfparser/bdfparser.py index e325ddc..4e72f35 100644 --- a/src/bdfparser/bdfparser.py +++ b/src/bdfparser/bdfparser.py @@ -10,11 +10,10 @@ from sys import version_info as python_version -def format_warning(message, category, filename, lineno, file=None, line=None): - return '%s:%s\n%s: %s\n' % (filename, lineno, 'bdfparser warning', message) - - -warnings.formatwarning = format_warning +class BDFParserWarning(UserWarning): + '''Warning category for bdfparser. Users can filter or format these + independently of other warnings via the standard `warnings` machinery.''' + pass class Font(object): @@ -175,15 +174,17 @@ def __parse_headers(self): self.headers[key.lower()] = int(value) elif key == 'CHARS': warnings.warn( - "It looks like the font does not have property block beginning with 'STARTPROPERTIES' keyword") + "It looks like the font does not have property block beginning with 'STARTPROPERTIES' keyword", + BDFParserWarning) self.__parse_headers_after() self.__curline_chars = line self.__parse_glyph_count() return elif key == 'STARTCHAR': warnings.warn( - "It looks like the font does not have property block beginning with 'STARTPROPERTIES' keyword") - warnings.warn("Cannot find 'CHARS' line") + "It looks like the font does not have property block beginning with 'STARTPROPERTIES' keyword", + BDFParserWarning) + warnings.warn("Cannot find 'CHARS' line", BDFParserWarning) self.__parse_headers_after() self.__curline_startchar = line self.__prepare_glyphs() @@ -191,8 +192,9 @@ def __parse_headers(self): if l == 1 and kvlist[0].strip() == 'ENDFONT': warnings.warn( - "It looks like the font does not have property block beginning with 'STARTPROPERTIES' keyword") - warnings.warn("This font does not have any glyphs") + "It looks like the font does not have property block beginning with 'STARTPROPERTIES' keyword", + BDFParserWarning) + warnings.warn("This font does not have any glyphs", BDFParserWarning) return def __parse_headers_after(self): @@ -223,7 +225,7 @@ def __parse_props(self): self.__parse_glyph_count() return if key == 'ENDFONT': - warnings.warn("This font does not have any glyphs") + warnings.warn("This font does not have any glyphs", BDFParserWarning) return else: self.props[key] = None @@ -239,7 +241,7 @@ def __parse_glyph_count(self): self.__curline_chars = None if line.strip() == 'ENDFONT': - warnings.warn("This font does not have any glyphs") + warnings.warn("This font does not have any glyphs", BDFParserWarning) return kvlist = line.split(None, 1) @@ -248,7 +250,8 @@ def __parse_glyph_count(self): else: self.__curline_startchar = line warnings.warn( - "Cannot find 'CHARS' line next to 'ENDPROPERTIES' line") + "Cannot find 'CHARS' line next to 'ENDPROPERTIES' line", + BDFParserWarning) self.__prepare_glyphs() def __prepare_glyphs(self): @@ -267,7 +270,7 @@ def __prepare_glyphs(self): self.__curline_startchar = None if line is None: - warnings.warn("This font does not have 'ENDFONT' keyword") + warnings.warn("This font does not have 'ENDFONT' keyword", BDFParserWarning) self.__prepare_glyphs_after() return @@ -342,12 +345,14 @@ def __prepare_glyphs_after(self): if self.__glyph_count_to_check != l: if self.__glyph_count_to_check is None: warnings.warn( - "The glyph count next to 'CHARS' keyword does not exist") + "The glyph count next to 'CHARS' keyword does not exist", + BDFParserWarning) else: warnings.warn( "The glyph count next to 'CHARS' keyword is " + str(self.__glyph_count_to_check) + - ", which does not match the actual glyph count " + str(l) + ", which does not match the actual glyph count " + str(l), + BDFParserWarning ) # Use old style for Python 3.5 support. For 3.6+: # f"The glyph count next to 'CHARS' keyword is {str(self.__glyph_count_to_check)}, which does not match the actual glyph count {str(l)}" @@ -420,7 +425,8 @@ def glyphbycp(self, codepoint): if codepoint not in self.glyphs: warnings.warn( "Glyph \"" + chr(codepoint) + "\" (codepoint " + - str(codepoint) + ") does not exist in the font. Will return `None`" + str(codepoint) + ") does not exist in the font. Will return `None`", + BDFParserWarning ) # Use old style for Python 3.5 support. For 3.6+: # f"Glyph \"{chr(codepoint)}\" (codepoint {str(codepoint)}) does not exist in the font. Will return `None`" @@ -874,9 +880,9 @@ def overlay(self, bitmap): bindata_a = self.bindata # no mutation, do not need deep copy bindata_b = bitmap.bindata if len(bindata_a) != len(bindata_b): - warnings.warn("the bitmaps to overlay have different height") + warnings.warn("the bitmaps to overlay have different height", BDFParserWarning) if len(bindata_a[0]) != len(bindata_b[0]): - warnings.warn("the bitmaps to overlay have different width") + warnings.warn("the bitmaps to overlay have different width", BDFParserWarning) # b over a self.bindata = [''.join(str(int(b) or int(a)) for a, b in zip( la, lb)) for la, lb in zip(bindata_a, bindata_b)] @@ -1178,7 +1184,7 @@ def bits2byte(octet): } else: if mode != 'RGB': - warnings.warn("Unknown mode, fallback to RGB") + warnings.warn("Unknown mode, fallback to RGB", BDFParserWarning) bytesdict = bytesdict or { 0: b'\xff\xff\xff', 1: b'\x00\x00\x00', From 4f0021e5c0a6a932e8a553b07469dcfd35a2046e Mon Sep 17 00:00:00 2001 From: Tyler Porter Date: Mon, 18 May 2026 20:41:47 -0400 Subject: [PATCH 2/2] Add best-practice stacklevel=2 to warn() calls --- src/bdfparser/bdfparser.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/bdfparser/bdfparser.py b/src/bdfparser/bdfparser.py index 4e72f35..f03bd2f 100644 --- a/src/bdfparser/bdfparser.py +++ b/src/bdfparser/bdfparser.py @@ -175,7 +175,7 @@ def __parse_headers(self): elif key == 'CHARS': warnings.warn( "It looks like the font does not have property block beginning with 'STARTPROPERTIES' keyword", - BDFParserWarning) + BDFParserWarning, stacklevel=2) self.__parse_headers_after() self.__curline_chars = line self.__parse_glyph_count() @@ -183,8 +183,8 @@ def __parse_headers(self): elif key == 'STARTCHAR': warnings.warn( "It looks like the font does not have property block beginning with 'STARTPROPERTIES' keyword", - BDFParserWarning) - warnings.warn("Cannot find 'CHARS' line", BDFParserWarning) + BDFParserWarning, stacklevel=2) + warnings.warn("Cannot find 'CHARS' line", BDFParserWarning, stacklevel=2) self.__parse_headers_after() self.__curline_startchar = line self.__prepare_glyphs() @@ -193,8 +193,8 @@ def __parse_headers(self): if l == 1 and kvlist[0].strip() == 'ENDFONT': warnings.warn( "It looks like the font does not have property block beginning with 'STARTPROPERTIES' keyword", - BDFParserWarning) - warnings.warn("This font does not have any glyphs", BDFParserWarning) + BDFParserWarning, stacklevel=2) + warnings.warn("This font does not have any glyphs", BDFParserWarning, stacklevel=2) return def __parse_headers_after(self): @@ -225,7 +225,7 @@ def __parse_props(self): self.__parse_glyph_count() return if key == 'ENDFONT': - warnings.warn("This font does not have any glyphs", BDFParserWarning) + warnings.warn("This font does not have any glyphs", BDFParserWarning, stacklevel=2) return else: self.props[key] = None @@ -241,7 +241,7 @@ def __parse_glyph_count(self): self.__curline_chars = None if line.strip() == 'ENDFONT': - warnings.warn("This font does not have any glyphs", BDFParserWarning) + warnings.warn("This font does not have any glyphs", BDFParserWarning, stacklevel=2) return kvlist = line.split(None, 1) @@ -251,7 +251,7 @@ def __parse_glyph_count(self): self.__curline_startchar = line warnings.warn( "Cannot find 'CHARS' line next to 'ENDPROPERTIES' line", - BDFParserWarning) + BDFParserWarning, stacklevel=2) self.__prepare_glyphs() def __prepare_glyphs(self): @@ -270,7 +270,7 @@ def __prepare_glyphs(self): self.__curline_startchar = None if line is None: - warnings.warn("This font does not have 'ENDFONT' keyword", BDFParserWarning) + warnings.warn("This font does not have 'ENDFONT' keyword", BDFParserWarning, stacklevel=2) self.__prepare_glyphs_after() return @@ -346,13 +346,13 @@ def __prepare_glyphs_after(self): if self.__glyph_count_to_check is None: warnings.warn( "The glyph count next to 'CHARS' keyword does not exist", - BDFParserWarning) + BDFParserWarning, stacklevel=2) else: warnings.warn( "The glyph count next to 'CHARS' keyword is " + str(self.__glyph_count_to_check) + ", which does not match the actual glyph count " + str(l), - BDFParserWarning + BDFParserWarning, stacklevel=2 ) # Use old style for Python 3.5 support. For 3.6+: # f"The glyph count next to 'CHARS' keyword is {str(self.__glyph_count_to_check)}, which does not match the actual glyph count {str(l)}" @@ -426,7 +426,7 @@ def glyphbycp(self, codepoint): warnings.warn( "Glyph \"" + chr(codepoint) + "\" (codepoint " + str(codepoint) + ") does not exist in the font. Will return `None`", - BDFParserWarning + BDFParserWarning, stacklevel=2 ) # Use old style for Python 3.5 support. For 3.6+: # f"Glyph \"{chr(codepoint)}\" (codepoint {str(codepoint)}) does not exist in the font. Will return `None`" @@ -880,9 +880,9 @@ def overlay(self, bitmap): bindata_a = self.bindata # no mutation, do not need deep copy bindata_b = bitmap.bindata if len(bindata_a) != len(bindata_b): - warnings.warn("the bitmaps to overlay have different height", BDFParserWarning) + warnings.warn("the bitmaps to overlay have different height", BDFParserWarning, stacklevel=2) if len(bindata_a[0]) != len(bindata_b[0]): - warnings.warn("the bitmaps to overlay have different width", BDFParserWarning) + warnings.warn("the bitmaps to overlay have different width", BDFParserWarning, stacklevel=2) # b over a self.bindata = [''.join(str(int(b) or int(a)) for a, b in zip( la, lb)) for la, lb in zip(bindata_a, bindata_b)] @@ -1184,7 +1184,7 @@ def bits2byte(octet): } else: if mode != 'RGB': - warnings.warn("Unknown mode, fallback to RGB", BDFParserWarning) + warnings.warn("Unknown mode, fallback to RGB", BDFParserWarning, stacklevel=2) bytesdict = bytesdict or { 0: b'\xff\xff\xff', 1: b'\x00\x00\x00',