10000 Merge pull request #10520 from anntzer/py3mathtext · matplotlib/matplotlib@a94f839 · GitHub
[go: up one dir, main page]

Skip to content

Commit a94f839

Browse files
authored
Merge pull request #10520 from anntzer/py3mathtext
Py3fy mathtext.py.
2 parents 2e8b9f3 + 86a1f78 commit a94f839

File tree

2 files changed

+65
-80
lines changed

2 files changed

+65
-80
lines changed
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Deprecations
22
````````````
3-
``cbook.is_numlike`` is deprecated. Use ``isinstance(..., numbers.Number)``
4-
instead.
3+
The following functions are deprecated:
4+
- ``cbook.is_numlike`` (use ``isinstance(..., numbers.Number)`` instead)
5+
- ``mathtext.unichr_safe`` (use ``chr`` instead)

lib/matplotlib/mathtext.py

Lines changed: 62 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,13 @@
1414
arbitrary fonts, but results may vary without proper tweaking and
1515
metrics for those fonts.
1616
"""
17-
from __future__ import (absolute_import, division, print_function,
18-
unicode_literals)
19-
20-
import six
21-
from six import unichr
2217

18+
import functools
19+
from io import StringIO
2320
import os
24-
from math import ceil
2521
import types
2622
import unicodedata
27-
from warnings import warn
28-
from functools import lru_cache
23+
import warnings
2924

3025
import numpy as np
3126

@@ -36,7 +31,7 @@
3631

3732
ParserElement.enablePackrat()
3833

39-
from matplotlib import _png, colors as mcolors, get_data_path, rcParams
34+
from matplotlib import _png, cbook, colors as mcolors, get_data_path, rcParams
4035
from matplotlib.afm import AFM
4136
from matplotlib.cbook import get_realpath_and_stat
4237
from matplotlib.ft2font import FT2Image, KERNING_DEFAULT, LOAD_NO_HINTING
@@ -81,14 +76,9 @@ def get_unicode_index(symbol, math=True):
8176
TeX/Type1 symbol"""%locals()
8277
raise ValueError(message)
8378

84-
def unichr_safe(index):
85-
"""Return the Unicode character corresponding to the index,
86-
or the replacement character if this is a narrow build of Python
87-
and the requested character is outside the BMP."""
88-
try:
89-
return unichr(index)
90-
except ValueError:
91-
return unichr(0xFFFD)
79+
80+
unichr_safe = cbook.deprecated("3.0")(chr)
81+
9282

9383
class MathtextBackend(object):
9484
"""
@@ -166,7 +156,7 @@ def _update_bbox(self, x1, y1, x2, y2):
166156
def set_canvas_size(self, w, h, d):
167157
MathtextBackend.set_canvas_size(self, w, h, d)
168158
if self.mode != 'bbox':
169-
self.image = FT2Image(ceil(w), ceil(h + max(d, 0)))
159+
self.image = FT2Image(np.ceil(w), np.ceil(h + max(d, 0)))
170160

171161
def render_glyph(self, ox, oy, info):
172162
if self.mode == 'bbox':
@@ -189,7 +179,7 @@ def render_rect_filled(self, x1, y1, x2, y2):
189179
y = int(center - (height + 1) / 2.0)
190180
else:
191181
y = int(y1)
192-
self.image.draw_rect_filled(int(x1), y, ceil(x2), y + height)
182+
self.image.draw_rect_filled(int(x1), y, np.ceil(x2), y + height)
193183

194184
def get_results(self, box, used_characters):
195185
self.mode = 'bbox'
@@ -230,7 +220,7 @@ class MathtextBackendPs(MathtextBackend):
230220
backend.
231221
"""
232222
def __init__(self):
233-
self.pswriter = six.moves.cStringIO()
223+
self.pswriter = StringIO()
234224
self.lastfont = None
235225

236226
def render_glyph(self, ox, oy, info):
@@ -361,7 +351,7 @@ def __init__(self):
361351

362352
def render_glyph(self, ox, oy, info):
363353
oy = oy - info.offset - self.height
364-
thetext = unichr_safe(info.num)
354+
thetext = chr(info.num)
365355
self.glyphs.append(
366356
(info.font, info.fontsize, thetext, ox, oy))
367357

@@ -464,8 +454,9 @@ def set_canvas_size(self, w, h, d):
464454
Set the size of the buffer used to render the math expression.
465455
Only really necessary for the bitmap backends.
466456
"""
467-
self.width, self.height, self.depth = ceil(w), ceil(h), ceil(d)
468-
self.mathtext_backend.set_canvas_size(self.width, self.height, self.depth)
457+
self.width, self.height, self.depth = np.ceil([w, h, d])
458+
self.mathtext_backend.set_canvas_size(
459+
self.width, self.height, self.depth)
469460

470461
def render_glyph(self, ox, oy, facename, font_class, sym, fontsize, dpi):
471462
"""
@@ -661,7 +652,7 @@ def __init__(self, *args, **kwargs):
661652

662653
TruetypeFonts.__init__(self, *args, **kwargs)
663654
self.fontmap = {}
664-
for key, val in six.iteritems(self._fontmap):
655+
for key, val in self._fontmap.items():
665656
fullpath = findfont(val)
666657
self.fontmap[key] = fullpath
667658
self.fontmap[val] = fullpath
@@ -801,9 +792,9 @@ def _get_glyph(self, fontname, font_class, sym, fontsize, math=True):
801792
found_symbol = True
802793
except ValueError:
803794
uniindex = ord('?')
804-
warn("No TeX to unicode mapping for '%s'" %
805-
sym.encode('ascii', 'backslashreplace'),
806-
MathTextWarning)
795+
warnings.warn(
796+
"No TeX to unicode mapping for {!a}.".format(sym),
797+
MathTextWarning)
807798

808799
fontname, uniindex = self._map_virtual_font(
809800
fontname, font_class, uniindex)
@@ -815,7 +806,7 @@ def _get_glyph(self, fontname, font_class, sym, fontsize, math=True):
815806
if found_symbol:
816807
if fontname == 'it':
817808
if uniindex < 0x10000:
818-
unistring = unichr(uniindex)
809+
unistring = chr(uniindex)
819810
if (not unicodedata.category(unistring)[0] == "L"
820811
or unicodedata.name(unistring).startswith("GREEK CAPITAL")):
821812
new_fontname = 'rm'
@@ -831,8 +822,9 @@ def _get_glyph(self, fontname, font_class, sym, fontsize, math=True):
831822
if not found_symbol:
832823
if self.cm_fallback:
833824
if isinstance(self.cm_fallback, BakomaFonts):
834-
warn("Substituting with a symbol from Computer Modern.",
835-
MathTextWarning)
825+
warnings.warn(
826+
"Substituting with a symbol from Computer Modern.",
827+
MathTextWarning)
836828
if (fontname in ('it', 'regular') and
837829
isinstance(self.cm_fallback, StixFonts)):
838830
return self.cm_fallback._get_glyph(
@@ -841,14 +833,14 @@ def _get_glyph(self, fontname, font_class, sym, fontsize, math=True):
841833
return self.cm_fallback._get_glyph(
842834
fontname, font_class, sym, fontsize)
843835
else:
844-
if fontname in ('it', 'regular') and isinstance(self, StixFonts):
836+
if (fontname in ('it', 'regular')
837+
and isinstance(self, StixFonts)):
845838
return self._get_glyph('rm', font_class, sym, fontsize)
846-
warn("Font '%s' does not have a glyph for '%s' [U+%x]" %
847-
(new_fontname,
848-
sym.encode('ascii', 'backslashreplace').decode('ascii'),
849-
uniindex),
850-
MathTextWarning)
851-
warn("Substituting with a dummy symbol.", MathTextWarning)
839+
warnings.warn(
840+
"Font {!r} does not have a glyph for {!a} [U+{:x}], "
841+
"substituting with a dummy symbol.".format(
842+
new_fontname, sym, uniindex),
843+
MathTextWarning)
852844
fontname = 'rm'
853845
new_fontname = fontname
854846
font = self._get_font(fontname)
@@ -885,7 +877,7 @@ def __init__(self, *args, **kwargs):
885877
3 : 'STIXSizeThreeSym',
886878
4 : 'STIXSizeFourSym',
887879
5 : 'STIXSizeFiveSym'})
888-
for key, name in six.iteritems(self._fontmap):
880+
for key, name in self._fontmap.items():
889881
fullpath = findfont(name)
890882
self.fontmap[key] = fullpath
891883
self.fontmap[name] = fullpath
@@ -972,7 +964,7 @@ class StixFonts(UnicodeFonts):
972964
def __init__(self, *args, **kwargs):
973965
TruetypeFonts.__init__(self, *args, **kwargs)
974966
7802 self.fontmap = {}
975-
for key, name in six.iteritems(self._fontmap):
967+
for key, name in self._fontmap.items():
976968
fullpath = findfont(name)
977969
self.fontmap[key] = fullpath
978970
self.fontmap[name] = fullpath
@@ -1048,7 +1040,7 @@ def get_sized_alternatives_for_symbol(self, fontname, sym):
10481040
font = self._get_font(i)
10491041
glyphindex = font.get_char_index(uniindex)
10501042
if glyphindex != 0:
1051-
alternatives.append((i, unichr_safe(uniindex)))
1043+
alternatives.append((i, chr(uniindex)))
10521044

10531045
# The largest size of the radical symbol in STIX has incorrect
10541046
# metrics that cause it to be disconnected from the stem.
@@ -1099,7 +1091,7 @@ def __init__(self, default_font_prop):
10991091

11001092
self.fonts['default'] = default_font
11011093
self.fonts['regular'] = default_font
1102-
self.pswriter = six.moves.cStringIO()
1094+
self.pswriter = StringIO()
11031095

11041096
def _get_font(self, font):
11051097
if font in self.fontmap:
@@ -1117,7 +1109,7 @@ def _get_font(self, font):
11171109
self.fonts[cached_font.get_fontname()] = cached_font
11181110
return cached_font
11191111

1120-
def _get_info (self, fontname, font_class, sym, fontsize, dpi, math=True):
1112+
def _get_info(self, fontname, font_class, sym, fontsize, dpi, math=True):
11211113
'load the cmfont, metrics and glyph with caching'
11221114
key = fontname, sym, fontsize, dpi
11231115
tup = self.glyphd.get(key)
@@ -1128,8 +1120,7 @@ def _get_info (self, fontname, font_class, sym, fontsize, dpi, math=True):
11281120
# Only characters in the "Letter" class should really be italicized.
11291121
# This class includes greek letters, so we're ok
11301122
if (fontname == 'it' and
1131-
(len(sym) > 1 or
1132-
not unicodedata.category(six.text_type(sym)).startswith("L"))):
1123+
(len(sym) > 1 or not unicodedata.category(sym).startswith("L"))):
11331124
fontname = 'rm'
11341125

11351126
found_symbol = False
@@ -1143,8 +1134,9 @@ def _get_info (self, fontname, font_class, sym, fontsize, dpi, math=True):
11431134
num = ord(glyph)
11441135
found_symbol = True
11451136
else:
1146-
warn("No TeX to built-in Postscript mapping for {!r}".format(sym),
1147-
MathTextWarning)
1137+
warnings.warn(
1138+
"No TeX to built-in Postscript mapping for {!r}".format(sym),
1139+
MathTextWarning)
11481140

11491141
slanted = (fontname == 'it')
11501142
font = self._get_font(fontname)
@@ -1153,8 +1145,10 @@ def _get_info (self, fontname, font_class, sym, fontsize, dpi, math=True):
11531145
try:
11541146
symbol_name = font.get_name_char(glyph)
11551147
except KeyError:
1156-
warn("No glyph in standard Postscript font {!r} for {!r}"
1157-
.format(font.get_fontname(), sym), MathTextWarning)
1148+
warnings.warn(
1149+
"No glyph in standard Postscript font {!r} for {!r}"
1150+
.format(font.get_fontname(), sym),
1151+
MathTextWarning)
11581152
found_symbol = False
11591153

11601154
if not found_symbol:
@@ -1581,8 +1575,9 @@ def _set_glue(self, x, sign, totals, error_type):
15811575
self.glue_ratio = 0.
15821576
if o == 0:
15831577
if len(self.children):
1584-
warn("%s %s: %r" % (error_type, self.__class__.__name__, self),
1585-
MathTextWarning)
1578+
warnings.warn(
1579+
"%s %s: %r" % (error_type, self.__class__.__name__, self),
1580+
MathTextWarning)
15861581

15871582
def shrink(self):
15881583
for child in self.children:
@@ -1824,19 +1819,19 @@ def __init__(self, state):
18241819
class Glue(Node):
18251820
"""
18261821
Most of the information in this object is stored in the underlying
1827-
:class:`GlueSpec` class, which is shared between multiple glue objects. (This
1828-
is a memory optimization which probably doesn't matter anymore, but it's
1829-
easier to stick to what TeX does.)
1822+
:class:`GlueSpec` class, which is shared between multiple glue objects.
1823+
(This is a memory optimization which probably doesn't matter anymore, but
1824+
it's easier to stick to what TeX does.)
18301825
"""
18311826
def __init__(self, glue_type, copy=False):
18321827
Node.__init__(self)
18331828
self.glue_subtype = 'normal'
1834-
if isinstance(glue_type, six.string_types):
1829+
if isinstance(glue_type, str):
18351830
glue_spec = GlueSpec.factory(glue_type)
18361831
elif isinstance(glue_type, GlueSpec):
18371832
glue_spec = glue_type
18381833
else:
1839-
raise ValueError("glue_type must be a glue spec name or instance.")
1834+
raise ValueError("glue_type must be a glue spec name or instance")
18401835
if copy:
18411836
glue_spec = glue_spec.copy()
18421837
self.glue_spec = glue_spec
@@ -2515,11 +2510,10 @@ def parse(self, s, fonts_object, fontsize, dpi):
25152510
try:
25162511
result = self._expression.parseString(s)
25172512
except ParseBaseException as err:
2518-
raise ValueError("\n".join([
2519-
"",
2520-
err.line,
2521-
" " * (err.column - 1) + "^",
2522-
six.text_type(err)]))
2513+
raise ValueError("\n".join(["",
2514+
err.line,
2515+
" " * (err.column - 1) + "^",
2516+
str(err)]))
25232517
self._state_stack = None
25242518
self._em_width_cache = {}
25252519
self._expression.resetCache()
@@ -2641,14 +2635,11 @@ def symbol(self, s, loc, toks):
26412635
if c in self._spaced_symbols:
26422636
# iterate until we find previous character, needed for cases
26432637
# such as ${ -2}$, $ -2$, or $ -2$.
2644-
for i in six.moves.xrange(1, loc + 1):
2645-
prev_char = s[loc-i]
2646-
if prev_char != ' ':
2647-
break
2638+
prev_char = next((c for c in s[:loc][::-1] if c != ' '), '')
26482639
# Binary operators at start of string should not be spaced
26492640
if (c in self._binary_operators and
26502641
(len(s[:loc].split()) == 0 or prev_char == '{' or
2651-
prev_char in self._left_delim)):
2642+
prev_char in self._left_delim)):
26522643
return [char]
26532644
else:
26542645
return [Hlist([self._make_space(0.2),
@@ -2659,20 +2650,13 @@ def symbol(self, s, loc, toks):
26592650

26602651
# Do not space commas between brackets
26612652
if c == ',':
2662-
prev_char, next_char = '', ''
2663-
for i in six.moves.xrange(1, loc + 1):
2664-
prev_char = s[loc - i]
2665-
if prev_char != ' ':
2666-
break
2667-
for i in six.moves.xrange(1, len(s) - loc):
2668-
next_char = s[loc + i]
2669-
if next_char != ' ':
2670-
break
2671-
if (prev_char == '{' and next_char == '}'):
2653+
prev_char = next((c for c in s[:loc][::-1] if c != ' '), '')
2654+
next_char = next((c for c in s[loc + 1:] if c != ' '), '')
2655+
if prev_char == '{' and next_char == '}':
26722656
return [char]
26732657

26742658
# Do not space dots as decimal separators
2675-
if (c == '.' and s[loc - 1].isdigit() and s[loc + 1].isdigit()):
2659+
if c == '.' and s[loc - 1].isdigit() and s[loc + 1].isdigit():
26762660
return [char]
26772661
else:
26782662
return [Hlist([char,
@@ -2857,7 +2841,7 @@ def subsuper(self, s, loc, toks):
28572841
napostrophes = 0
28582842
new_toks = []
28592843
for tok in toks[0]:
2860-
if isinstance(tok, six.string_types) and tok not in ('^', '_'):
2844+
if isinstance(tok, str) and tok not in ('^', '_'):
28612845
napostrophes += len(tok)
28622846
elif isinstance(tok, Char) and tok.c == "'":
28632847
napostrophes += 1
@@ -3249,7 +3233,7 @@ def __init__(self, output):
32493233
"""
32503234
self._output = output.lower()
32513235

3252-
@lru_cache(50)
3236+
@functools.lru_cache(50)
32533237
def parse(self, s, dpi = 72, prop = None):
32543238
"""
32553239
Parse the given math expression *s* at the given *dpi*. If

0 commit comments

Comments
 (0)
0