Skip to content

Commit 52103f8

Browse files
committed
Use custom exceptions.
1 parent 872e199 commit 52103f8

File tree

4 files changed

+51
-27
lines changed

4 files changed

+51
-27
lines changed

fontbro/exceptions.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class ArgumentError(ValueError):
2+
pass
3+
4+
5+
class DataError(ValueError):
6+
pass
7+
8+
9+
class OperationError(TypeError):
10+
pass
11+
12+
13+
class SanitizationError(Exception):
14+
pass

fontbro/font.py

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
from fontTools.varLib.instancer import OverlapMode
1818
from PIL import Image, ImageDraw, ImageFont
1919

20+
from fontbro.exceptions import (
21+
ArgumentError,
22+
DataError,
23+
OperationError,
24+
SanitizationError,
25+
)
2026
from fontbro.flags import get_flag, set_flag
2127
from fontbro.math import get_euclidean_distance
2228
from fontbro.subset import parse_unicodes
@@ -229,7 +235,7 @@ def __init__(self, filepath, **kwargs):
229235
self._init_with_ttfont(filepath, **kwargs)
230236
else:
231237
filepath_type = type(filepath).__name__
232-
raise ValueError(
238+
raise ArgumentError(
233239
f"Invalid filepath type: expected pathlib.Path or str, found {filepath_type!r}."
234240
)
235241

@@ -240,7 +246,7 @@ def _init_with_filepath(self, filepath, **kwargs):
240246
self._ttfont = TTFont(self._filepath, **kwargs)
241247

242248
except TTLibError as error:
243-
raise ValueError(f"Invalid font at filepath: {filepath!r}.") from error
249+
raise ArgumentError(f"Invalid font at filepath: {filepath!r}.") from error
244250

245251
def _init_with_fileobject(self, fileobject, **kwargs):
246252
try:
@@ -249,7 +255,9 @@ def _init_with_fileobject(self, fileobject, **kwargs):
249255
self._ttfont = TTFont(self._fileobject, **kwargs)
250256

251257
except TTLibError as error:
252-
raise ValueError(f"Invalid font at fileobject: {fileobject!r}.") from error
258+
raise ArgumentError(
259+
f"Invalid font at fileobject: {fileobject!r}."
260+
) from error
253261

254262
def _init_with_font(self, font, **kwargs):
255263
self._init_with_ttfont(font.get_ttfont())
@@ -311,7 +319,7 @@ def get_characters(self, *, ignore_blank=False):
311319
font = self.get_ttfont()
312320
cmap = font.getBestCmap()
313321
if cmap is None:
314-
raise TypeError("Unable to find the 'best' unicode cmap dict.")
322+
raise DataError("Unable to find the 'best' unicode cmap dict.")
315323
glyfs = font.get("glyf")
316324
for code, char_name in cmap.items():
317325
code_hex = f"{code:04X}"
@@ -515,7 +523,7 @@ def get_fingerprint_match(self, other, *, tolerance=10, text=""):
515523
other_font = other
516524
else:
517525
other_type = type(other).__name__
518-
raise ValueError(
526+
raise ArgumentError(
519527
"Invalid other filepath/font: expected str or Font instance, "
520528
f"found {other_type!r}."
521529
)
@@ -551,7 +559,7 @@ def get_format(self, *, ignore_flavor=False):
551559
elif version == "wOF2":
552560
format = self.FORMAT_WOFF2
553561
if format is None:
554-
raise TypeError("Unable to get the font format.")
562+
raise DataError("Unable to get the font format.")
555563
return format
556564

557565
def get_glyphs(self):
@@ -644,8 +652,9 @@ def _get_name_id(cls, key):
644652
elif isinstance(key, str):
645653
return cls._NAMES_BY_KEY[key]["id"]
646654
else:
647-
raise TypeError(
648-
f"Invalid key type, expected int or str, found {type(key).__name__!r}."
655+
key_type = type(key).__name__
656+
raise ArgumentError(
657+
f"Invalid key type, expected int or str, found {key_type!r}."
649658
)
650659

651660
def get_name(self, key):
@@ -1107,8 +1116,8 @@ def rename(self, *, family_name="", style_name="", update_style_flags=True):
11071116
postscript_name = re.sub(r"[\-]+", "-", postscript_name).strip("-")
11081117
postscript_name_length = len(postscript_name)
11091118
if postscript_name_length > 63:
1110-
raise ValueError(
1111-
"PostScript name max-length (63 characters) exceeded"
1119+
raise ArgumentError(
1120+
"Computed PostScript name exceeded 63 characters max-length"
11121121
f" ({postscript_name_length} characters)."
11131122
)
11141123

@@ -1165,17 +1174,18 @@ def sanitize(self, *, strict=True):
11651174
error_code = result.returncode
11661175
errors = result.stderr
11671176
if error_code:
1168-
exc = Exception(
1177+
raise SanitizationError(
11691178
f"OpenType Sanitizer returned non-zero exit code ({error_code}): \n{errors}"
11701179
)
1171-
print(exc)
1172-
raise exc
1180+
11731181
elif strict:
11741182
warnings = result.stdout
11751183
success_message = "File sanitized successfully!\n"
11761184
if warnings != success_message:
11771185
warnings = warnings.rstrip(success_message)
1178-
raise Exception(f"OpenType Sanitizer warnings: \n{warnings}")
1186+
raise SanitizationError(
1187+
f"OpenType Sanitizer warnings: \n{warnings}"
1188+
)
11791189

11801190
def save(self, filepath=None, *, overwrite=False):
11811191
"""
@@ -1196,7 +1206,7 @@ def save(self, filepath=None, *, overwrite=False):
11961206
not specififed.
11971207
"""
11981208
if not filepath and not self._filepath:
1199-
raise ValueError(
1209+
raise ArgumentError(
12001210
"Font doesn't have a filepath. Please specify a filepath to save to."
12011211
)
12021212

@@ -1220,7 +1230,7 @@ def save(self, filepath=None, *, overwrite=False):
12201230
filename = fsutil.join_filename(basename, extension)
12211231
filepath = fsutil.join_filepath(dirpath, filename)
12221232
if fsutil.is_file(filepath) and not overwrite:
1223-
raise ValueError(
1233+
raise ArgumentError(
12241234
f"Invalid filepath, a file already exists at {filepath!r} "
12251235
"and 'overwrite' option is 'False' (consider using 'overwrite=True')."
12261236
)
@@ -1313,7 +1323,7 @@ def save_variable_instances(
13131323
:raises TypeError: If the font is not a variable font.
13141324
"""
13151325
if not self.is_variable():
1316-
raise TypeError("Only a variable font can be instantiated.")
1326+
raise OperationError("Only a variable font can be instantiated.")
13171327

13181328
fsutil.assert_not_file(dirpath)
13191329
fsutil.make_dirs(dirpath)
@@ -1501,7 +1511,7 @@ def subset(self, *, unicodes="", glyphs=None, text="", **options):
15011511
"""
15021512
font = self.get_ttfont()
15031513
if not any([unicodes, glyphs, text]):
1504-
raise ValueError(
1514+
raise ArgumentError(
15051515
"Subsetting requires at least one of the following args: unicode,"
15061516
" glyphs, text."
15071517
)
@@ -1555,7 +1565,7 @@ def to_sliced_variable(self, *, coordinates, **options):
15551565
:raises ValueError: If the coordinates axes are all pinned
15561566
"""
15571567
if not self.is_variable():
1558-
raise TypeError("Only a variable font can be sliced.")
1568+
raise OperationError("Only a variable font can be sliced.")
15591569

15601570
font = self.get_ttfont()
15611571
coordinates = coordinates or {}
@@ -1576,10 +1586,10 @@ def to_sliced_variable(self, *, coordinates, **options):
15761586

15771587
# ensure that coordinates axes are defined and that are not all pinned
15781588
if len(coordinates_axes_tags) == 0:
1579-
raise ValueError("Invalid coordinates: axes not defined.")
1589+
raise ArgumentError("Invalid coordinates: axes not defined.")
15801590
elif set(coordinates_axes_tags) == set(self.get_variable_axes_tags()):
15811591
if self._all_axes_pinned(coordinates):
1582-
raise ValueError(
1592+
raise ArgumentError(
15831593
"Invalid coordinates: all axes are pinned (use to_static method)."
15841594
)
15851595

@@ -1622,19 +1632,19 @@ def to_static(
16221632
:raises ValueError: If the coordinates axes are not all pinned
16231633
"""
16241634
if not self.is_variable():
1625-
raise TypeError("Only a variable font can be made static.")
1635+
raise OperationError("Only a variable font can be made static.")
16261636

16271637
font = self.get_ttfont()
16281638

16291639
# take coordinates from instance with specified style name
16301640
if style_name:
16311641
if coordinates:
1632-
raise ValueError(
1642+
raise ArgumentError(
16331643
"Invalid arguments: 'coordinates' and 'style_name' are mutually exclusive."
16341644
)
16351645
instance = self.get_variable_instance_by_style_name(style_name=style_name)
16361646
if not instance:
1637-
raise ValueError(
1647+
raise ArgumentError(
16381648
f"Invalid style name: instance with style name {style_name!r} not found."
16391649
)
16401650
coordinates = instance["coordinates"].copy()
@@ -1650,7 +1660,7 @@ def to_static(
16501660

16511661
# ensure that coordinates axes are all pinned
16521662
if not self._all_axes_pinned(coordinates):
1653-
raise ValueError("Invalid coordinates: all axes must be pinned.")
1663+
raise ArgumentError("Invalid coordinates: all axes must be pinned.")
16541664

16551665
# get instance closest to coordinates
16561666
instance = self.get_variable_instance_closest_to_coordinates(coordinates)

tests/test_issues.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class IssuesTestCase(AbstractTestCase):
88

99
def test_issue_0048_get_characters_count(self):
1010
font = self._get_font("/issues/issue-0048/test.ttf")
11-
with self.assertRaises(TypeError):
11+
with self.assertRaises(ValueError):
1212
font.get_characters_count()
1313

1414
def test_issue_0050_get_features(self):

tests/test_names.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def test_get_name_by_key(self):
1919

2020
def test_get_name_by_invalid_type(self):
2121
font = self._get_font("/Roboto_Mono/static/RobotoMono-Regular.ttf")
22-
with self.assertRaises(TypeError):
22+
with self.assertRaises(ValueError):
2323
font.get_name(font)
2424

2525
def test_get_name_by_invalid_key(self):

0 commit comments

Comments
 (0)