Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 099644c

Browse files
committed
Raise an exception when find_tex_file fails to find a file.
The exception message is clearer for end users than downstream callers failing to `open()` a file named `""`. Also update the function's docstring. _tfmfile now never returns None (an exception would have been raised earlier by find_tex_file), so remove the corresponding branch.
1 parent 97ba9d4 commit 099644c

File tree

6 files changed

+86
-48
lines changed

6 files changed

+86
-48
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
In the future, ``dviread.find_tex_file`` will raise a ``FileNotFoundError`` for missing files
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
Previously, it would return an empty string in such cases. Raising an
4+
exception allows attaching a user-friendly message instead. During the
5+
transition period, a warning is raised.

lib/matplotlib/backends/backend_pdf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ def dviFontName(self, dvifont):
887887
if dvi_info is not None:
888888
return dvi_info.pdfname
889889

890-
tex_font_map = dviread.PsfontsMap(dviread.find_tex_file('pdftex.map'))
890+
tex_font_map = dviread.PsfontsMap(dviread._find_tex_file('pdftex.map'))
891891
psfont = tex_font_map[dvifont.texname]
892892
if psfont.filename is None:
893893
raise ValueError(

lib/matplotlib/dviread.py

Lines changed: 73 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -470,8 +470,6 @@ def _fnt_def_real(self, k, c, s, d, a, l):
470470
n = self.file.read(a + l)
471471
fontname = n[-l:].decode('ascii')
472472
tfm = _tfmfile(fontname)
473-
if tfm is None:
474-
raise FileNotFoundError("missing font metrics file: %s" % fontname)
475473
if c != 0 and tfm.checksum != 0 and c != tfm.checksum:
476474
raise ValueError('tfm checksum mismatch: %s' % n)
477475

@@ -938,9 +936,9 @@ def _parse_and_cache_line(self, line):
938936
if basename is None:
939937
basename = tfmname
940938
if encodingfile is not None:
941-
encodingfile = find_tex_file(encodingfile)
939+
encodingfile = _find_tex_file(encodingfile)
942940
if fontfile is not None:
943-
fontfile = find_tex_file(fontfile)
941+
fontfile = _find_tex_file(fontfile)
944942
self._parsed[tfmname] = PsFont(
945943
texname=tfmname, psname=basename, effects=effects,
946944
encoding=encodingfile, filename=fontfile)
@@ -992,21 +990,20 @@ def search(self, filename):
992990
self._proc.stdin.write(os.fsencode(filename) + b"\n")
993991
self._proc.stdin.flush()
994992
out = self._proc.stdout.readline().rstrip()
995-
return "" if out == b"nil" else os.fsdecode(out)
993+
return None if out == b"nil" else os.fsdecode(out)
996994

997995

998996
@lru_cache()
999997
@_api.delete_parameter("3.5", "format")
1000-
def find_tex_file(filename, format=None):
998+
def _find_tex_file(filename, format=None):
1001999
"""
1002-
Find a file in the texmf tree.
1000+
Find a file in the texmf tree using kpathsea_.
10031001
1004-
Calls :program:`kpsewhich` which is an interface to the kpathsea
1005-
library [1]_. Most existing TeX distributions on Unix-like systems use
1006-
kpathsea. It is also available as part of MikTeX, a popular
1007-
distribution on Windows.
1002+
The kpathsea library, provided by most existing TeX distributions, both
1003+
on Unix-like systems and on Windows (MikTeX), is invoked via a long-lived
1004+
luatex process if luatex is installed, or via kpsewhich otherwise.
10081005
1009-
*If the file is not found, an empty string is returned*.
1006+
.. _kpathsea: http://www.tug.org/kpathsea/
10101007
10111008
Parameters
10121009
----------
@@ -1016,10 +1013,10 @@ def find_tex_file(filename, format=None):
10161013
Could be e.g. 'tfm' or 'vf' to limit the search to that type of files.
10171014
Deprecated.
10181015
1019-
References
1020-
----------
1021-
.. [1] `Kpathsea documentation <http://www.tug.org/kpathsea/>`_
1022-
The library that :program:`kpsewhich` is part of.
1016+
Raises
1017+
------
1018+
FileNotFoundError
1019+
If the file is not found.
10231020
"""
10241021

10251022
# we expect these to always be ascii encoded, but use utf-8
@@ -1029,39 +1026,71 @@ def find_tex_file(filename, format=None):
10291026
if isinstance(format, bytes):
10301027
format = format.decode('utf-8', errors='replace')
10311028

1032-
if format is None:
1029+
try:
1030+
lk = _LuatexKpsewhich()
1031+
except FileNotFoundError:
1032+
lk = None # Fallback to directly calling kpsewhich, as below.
1033+
1034+
if lk and format is None:
1035+
path = lk.search(filename)
1036+
1037+
else:
1038+
if os.name == 'nt':
1039+
# On Windows only, kpathsea can use utf-8 for cmd args and output.
1040+
# The `command_line_encoding` environment variable is set to force
1041+
# it to always use utf-8 encoding. See Matplotlib issue #11848.
1042+
kwargs = {'env': {**os.environ, 'command_line_encoding': 'utf-8'},
1043+
'encoding': 'utf-8'}
1044+
else: # On POSIX, run through the equivalent of os.fsdecode().
1045+
kwargs = {'encoding': sys.getfilesystemencoding(),
1046+
'errors': 'surrogatescape'}
1047+
1048+
cmd = ['kpsewhich']
1049+
if format is not None:
1050+
cmd += ['--format=' + format]
1051+
cmd += [filename]
10331052
try:
1034-
lk = _LuatexKpsewhich()
1035-
except FileNotFoundError:
1036-
pass # Fallback to directly calling kpsewhich, as below.
1037-
else:
1038-
return lk.search(filename)
1039-
1040-
if os.name == 'nt':
1041-
# On Windows only, kpathsea can use utf-8 for cmd args and output.
1042-
# The `command_line_encoding` environment variable is set to force it
1043-
# to always use utf-8 encoding. See Matplotlib issue #11848.
1044-
kwargs = {'env': {**os.environ, 'command_line_encoding': 'utf-8'},
1045-
'encoding': 'utf-8'}
1046-
else: # On POSIX, run through the equivalent of os.fsdecode().
1047-
kwargs = {'encoding': sys.getfilesystemencoding(),
1048-
'errors': 'surrogatescape'}
1049-
1050-
cmd = ['kpsewhich']
1051-
if format is not None:
1052-
cmd += ['--format=' + format]
1053-
cmd += [filename]
1053+
path = (cbook._check_and_log_subprocess(cmd, _log, **kwargs)
1054+
.rstrip('\n'))
1055+
except (FileNotFoundError, RuntimeError):
1056+
path = None
1057+
1058+
if path:
1059+
return path
1060+
else:
1061+
frame = sys._getframe(1)
1062+
while frame.f_globals.get("__name__") == "matplotlib._api.deprecation":
1063+
frame = frame.f_back
1064+
raise FileNotFoundError(
1065+
f"Matplotlib's TeX implementation searched for a file named "
1066+
f"{filename!r} in your texmf tree, but could not find it")
1067+
1068+
1069+
# After the deprecation period elapses, delete this shim and rename
1070+
# _find_tex_file to find_tex_file everywhere.
1071+
@_api.delete_parameter("3.5", "format")
1072+
def find_tex_file(filename, format=None):
10541073
try:
1055-
result = cbook._check_and_log_subprocess(cmd, _log, **kwargs)
1056-
except (FileNotFoundError, RuntimeError):
1057-
return ''
1058-
return result.rstrip('\n')
1074+
return (_find_tex_file(filename, format) if format is not None else
1075+
_find_tex_file(filename))
1076+
except FileNotFoundError as exc:
1077+
_api.warn_deprecated(
1078+
"3.6", message=f"{exc.args[0]}; in the future, this will raise a "
1079+
f"FileNotFoundError.")
1080+
return ""
1081+
1082+
1083+
find_tex_file.__doc__ = _find_tex_file.__doc__
10591084

10601085

10611086
@lru_cache()
10621087
def _fontfile(cls, suffix, texname):
1063-
filename = find_tex_file(texname + suffix)
1064-
return cls(filename) if filename else None
1088+
try:
1089+
filename = _find_tex_file(texname + suffix)
1090+
except FileNotFoundError:
1091+
return None
1092+
else:
1093+
return cls(filename)
10651094

10661095

10671096
_tfmfile = partial(_fontfile, Tfm, ".tfm")
@@ -1077,7 +1106,7 @@ def _fontfile(cls, suffix, texname):
10771106
parser.add_argument("dpi", nargs="?", type=float, default=None)
10781107
args = parser.parse_args()
10791108
with Dvi(args.filename, args.dpi) as dvi:
1080-
fontmap = PsfontsMap(find_tex_file('pdftex.map'))
1109+
fontmap = PsfontsMap(_find_tex_file('pdftex.map'))
10811110
for page in dvi:
10821111
print(f"=== new page === "
10831112
f"(w: {page.width}, h: {page.height}, d: {page.descent})")

lib/matplotlib/testing/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,8 @@ def _check_for_pgf(texsystem):
7878

7979

8080
def _has_tex_package(package):
81-
return bool(mpl.dviread.find_tex_file(f"{package}.sty"))
81+
try:
82+
mpl.dviread._find_tex_file(f"{package}.sty")
83+
return True
84+
except FileNotFoundError:
85+
return False

lib/matplotlib/tests/test_dviread.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88

99
def test_PsfontsMap(monkeypatch):
10-
monkeypatch.setattr(dr, 'find_tex_file', lambda x: x)
10+
monkeypatch.setattr(dr, '_find_tex_file', lambda x: x)
1111

1212
filename = str(Path(__file__).parent / 'baseline_images/dviread/test.map')
1313
fontmap = dr.PsfontsMap(filename)

lib/matplotlib/textpath.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ def get_glyphs_tex(self, prop, s, glyph_map=None,
279279
@staticmethod
280280
@functools.lru_cache(50)
281281
def _get_ps_font_and_encoding(texname):
282-
tex_font_map = dviread.PsfontsMap(dviread.find_tex_file('pdftex.map'))
282+
tex_font_map = dviread.PsfontsMap(dviread._find_tex_file('pdftex.map'))
283283
psfont = tex_font_map[texname]
284284
if psfont.filename is None:
285285
raise ValueError(

0 commit comments

Comments
 (0)