Skip to content

Commit 63cfa16

Browse files
committed
TYP: Add typed classes around mathtext data objects
1 parent b50753c commit 63cfa16

File tree

1 file changed

+108
-41
lines changed

1 file changed

+108
-41
lines changed

lib/matplotlib/_mathtext.py

Lines changed: 108 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
Implementation details for :mod:`.mathtext`.
33
"""
44

5+
from __future__ import annotations
6+
57
import copy
6-
from collections import namedtuple
78
import enum
89
import functools
910
import logging
@@ -12,6 +13,8 @@
1213
import types
1314
import unicodedata
1415
import string
16+
import typing as T
17+
from typing import NamedTuple
1518

1619
import numpy as np
1720
from pyparsing import (
@@ -34,6 +37,9 @@
3437
else:
3538
from pyparsing import nested_expr
3639

40+
if T.TYPE_CHECKING:
41+
from .ft2font import FT2Font, Glyph
42+
3743
ParserElement.enablePackrat()
3844
_log = logging.getLogger("matplotlib.mathtext")
3945

@@ -64,24 +70,49 @@ def get_unicode_index(symbol): # Publicly exported.
6470
) from err
6571

6672

67-
VectorParse = namedtuple("VectorParse", "width height depth glyphs rects",
68-
module="matplotlib.mathtext")
69-
VectorParse.__doc__ = r"""
70-
The namedtuple type returned by ``MathTextParser("path").parse(...)``.
73+
class VectorParse(NamedTuple):
74+
"""
75+
The namedtuple type returned by ``MathTextParser("path").parse(...)``.
7176
72-
This tuple contains the global metrics (*width*, *height*, *depth*), a list of
73-
*glyphs* (including their positions) and of *rect*\angles.
74-
"""
77+
Attributes
78+
----------
79+
width, height, depth : float
80+
The global metrics.
81+
glyphs : list
82+
The glyphs including their positions.
83+
rect : list
84+
The list of rectangles.
85+
"""
86+
width: float
87+
height: float
88+
depth: float
89+
glyphs: list[tuple[FT2Font, float, int, float, float]]
90+
rects: list[tuple[float, float, float, float]]
7591

92+
VectorParse.__module__ = "matplotlib.mathtext"
7693

77-
RasterParse = namedtuple("RasterParse", "ox oy width height depth image",
78-
module="matplotlib.mathtext")
79-
RasterParse.__doc__ = r"""
80-
The namedtuple type returned by ``MathTextParser("agg").parse(...)``.
8194

82-
This tuple contains the global metrics (*width*, *height*, *depth*), and a
83-
raster *image*. The offsets *ox*, *oy* are always zero.
84-
"""
95+
class RasterParse(NamedTuple):
96+
"""
97+
The namedtuple type returned by ``MathTextParser("agg").parse(...)``.
98+
99+
Attributes
100+
----------
101+
ox, oy : float
102+
The offsets are always zero.
103+
width, height, depth : float
104+
The global metrics.
105+
image : FT2Image
106+
A raster image.
107+
"""
108+
ox: float
109+
oy: float
110+
width: float
111+
height: float
112+
depth: float
113+
image: FT2Image
114+
115+
RasterParse.__module__ = "matplotlib.mathtext"
85116

86117

87118
class Output:
@@ -143,6 +174,48 @@ def to_raster(self, *, antialiased):
143174
return RasterParse(0, 0, w, h + d, d, image)
144175

145176

177+
class FontMetrics(NamedTuple):
178+
"""
179+
Metrics of a font.
180+
181+
Attributes
182+
----------
183+
advance : float
184+
The advance distance (in points) of the glyph.
185+
height : float
186+
The height of the glyph in points.
187+
width : float
188+
The width of the glyph in points.
189+
xmin, xmax, ymin, ymax : float
190+
The ink rectangle of the glyph.
191+
iceberg : float
192+
The distance from the baseline to the top of the glyph. (This corresponds to
193+
TeX's definition of "height".)
194+
slanted : bool
195+
Whether the glyph should be considered as "slanted" (currently used for kerning
196+
sub/superscripts).
197+
"""
198+
advance: float
199+
height: float
200+
width: float
201+
xmin: float
202+
xmax: float
203+
ymin: float
204+
ymax: float
205+
iceberg: float
206+
slanted: bool
207+
208+
209+
class FontInfo(NamedTuple):
210+
font: FT2Font
211+
fontsize: float
212+
postscript_name: str
213+
metrics: FontMetrics
214+
num: int
215+
glyph: Glyph
216+
offset: float
217+
218+
146219
class Fonts:
147220
"""
148221
An abstract base class for a system of fonts to use for mathtext.
@@ -197,19 +270,7 @@ def get_metrics(self, font, font_class, sym, fontsize, dpi):
197270
198271
Returns
199272
-------
200-
object
201-
202-
The returned object has the following attributes (all floats,
203-
except *slanted*):
204-
205-
- *advance*: The advance distance (in points) of the glyph.
206-
- *height*: The height of the glyph in points.
207-
- *width*: The width of the glyph in points.
208-
- *xmin*, *xmax*, *ymin*, *ymax*: The ink rectangle of the glyph
209-
- *iceberg*: The distance from the baseline to the top of the
210-
glyph. (This corresponds to TeX's definition of "height".)
211-
- *slanted*: Whether the glyph should be considered as "slanted"
212-
(currently used for kerning sub/superscripts).
273+
FontMetrics
213274
"""
214275
info = self._get_info(font, font_class, sym, fontsize, dpi)
215276
return info.metrics
@@ -295,7 +356,7 @@ def _get_info(self, fontname, font_class, sym, fontsize, dpi):
295356

296357
xmin, ymin, xmax, ymax = [val/64.0 for val in glyph.bbox]
297358
offset = self._get_offset(font, glyph, fontsize, dpi)
298-
metrics = types.SimpleNamespace(
359+
metrics = FontMetrics(
299360
advance = glyph.linearHoriAdvance/65536.0,
300361
height = glyph.height/64.0,
301362
width = glyph.width/64.0,
@@ -308,7 +369,7 @@ def _get_info(self, fontname, font_class, sym, fontsize, dpi):
308369
slanted = slanted
309370
)
310371

311-
return types.SimpleNamespace(
372+
return FontInfo(
312373
font = font,
313374
fontsize = fontsize,
314375
postscript_name = font.postscript_name,
@@ -810,33 +871,33 @@ class FontConstantsBase:
810871
be reliably retrieved from the font metrics in the font itself.
811872
"""
812873
# Percentage of x-height of additional horiz. space after sub/superscripts
813-
script_space = 0.05
874+
script_space: T.ClassVar[float] = 0.05
814875

815876
# Percentage of x-height that sub/superscripts drop below the baseline
816-
subdrop = 0.4
877+
subdrop: T.ClassVar[float] = 0.4
817878

818879
# Percentage of x-height that superscripts are raised from the baseline
819-
sup1 = 0.7
880+
sup1: T.ClassVar[float] = 0.7
820881

821882
# Percentage of x-height that subscripts drop below the baseline
822-
sub1 = 0.3
883+
sub1: T.ClassVar[float] = 0.3
823884

824885
# Percentage of x-height that subscripts drop below the baseline when a
825886
# superscript is present
826-
sub2 = 0.5
887+
sub2: T.ClassVar[float] = 0.5
827888

828889
# Percentage of x-height that sub/superscripts are offset relative to the
829890
# nucleus edge for non-slanted nuclei
830-
delta = 0.025
891+
delta: T.ClassVar[float] = 0.025
831892

832893
# Additional percentage of last character height above 2/3 of the
833894
# x-height that superscripts are offset relative to the subscript
834895
# for slanted nuclei
835-
delta_slanted = 0.2
896+
delta_slanted: T.ClassVar[float] = 0.2
836897

837898
# Percentage of x-height that superscripts and subscripts are offset for
838899
# integrals
839-
delta_integral = 0.1
900+
delta_integral: T.ClassVar[float] = 0.1
840901

841902

842903
class ComputerModernFontConstants(FontConstantsBase):
@@ -1333,8 +1394,14 @@ def __init__(self, state):
13331394
super().__init__(thickness, np.inf, np.inf, state)
13341395

13351396

1336-
_GlueSpec = namedtuple(
1337-
"_GlueSpec", "width stretch stretch_order shrink shrink_order")
1397+
class _GlueSpec(NamedTuple):
1398+
width: float
1399+
stretch: float
1400+
stretch_order: int
1401+
shrink: float
1402+
shrink_order: int
1403+
1404+
13381405
_GlueSpec._named = { # type: ignore[attr-defined]
13391406
'fil': _GlueSpec(0., 1., 1, 0., 0),
13401407
'fill': _GlueSpec(0., 1., 2, 0., 0),
@@ -1358,7 +1425,7 @@ class Glue(Node):
13581425
def __init__(self, glue_type):
13591426
super().__init__()
13601427
if isinstance(glue_type, str):
1361-
glue_spec = _GlueSpec._named[glue_type]
1428+
glue_spec = _GlueSpec._named[glue_type] # type: ignore[attr-defined]
13621429
elif isinstance(glue_type, _GlueSpec):
13631430
glue_spec = glue_type
13641431
else:

0 commit comments

Comments
 (0)