diff --git a/doc/api/next_api_changes/deprecations/21356-AL.rst b/doc/api/next_api_changes/deprecations/21356-AL.rst new file mode 100644 index 000000000000..de6cb79dd908 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/21356-AL.rst @@ -0,0 +1,5 @@ +In the future, ``dviread.find_tex_file`` will raise a ``FileNotFoundError`` for missing files +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, it would return an empty string in such cases. Raising an +exception allows attaching a user-friendly message instead. During the +transition period, a warning is raised. diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index bd0c370f1cba..29838c35316c 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -887,7 +887,7 @@ def dviFontName(self, dvifont): if dvi_info is not None: return dvi_info.pdfname - tex_font_map = dviread.PsfontsMap(dviread.find_tex_file('pdftex.map')) + tex_font_map = dviread.PsfontsMap(dviread._find_tex_file('pdftex.map')) psfont = tex_font_map[dvifont.texname] if psfont.filename is None: raise ValueError( diff --git a/lib/matplotlib/dviread.py b/lib/matplotlib/dviread.py index 3207a01de8be..7f90a13f1086 100644 --- a/lib/matplotlib/dviread.py +++ b/lib/matplotlib/dviread.py @@ -470,13 +470,12 @@ def _fnt_def_real(self, k, c, s, d, a, l): n = self.file.read(a + l) fontname = n[-l:].decode('ascii') tfm = _tfmfile(fontname) - if tfm is None: - raise FileNotFoundError("missing font metrics file: %s" % fontname) if c != 0 and tfm.checksum != 0 and c != tfm.checksum: raise ValueError('tfm checksum mismatch: %s' % n) - - vf = _vffile(fontname) - + try: + vf = _vffile(fontname) + except FileNotFoundError: + vf = None self.fonts[k] = DviFont(scale=s, tfm=tfm, texname=n, vf=vf) @_dispatch(247, state=_dvistate.pre, args=('u1', 'u4', 'u4', 'u4', 'u1')) @@ -938,9 +937,9 @@ def _parse_and_cache_line(self, line): if basename is None: basename = tfmname if encodingfile is not None: - encodingfile = find_tex_file(encodingfile) + encodingfile = _find_tex_file(encodingfile) if fontfile is not None: - fontfile = find_tex_file(fontfile) + fontfile = _find_tex_file(fontfile) self._parsed[tfmname] = PsFont( texname=tfmname, psname=basename, effects=effects, encoding=encodingfile, filename=fontfile) @@ -992,21 +991,20 @@ def search(self, filename): self._proc.stdin.write(os.fsencode(filename) + b"\n") self._proc.stdin.flush() out = self._proc.stdout.readline().rstrip() - return "" if out == b"nil" else os.fsdecode(out) + return None if out == b"nil" else os.fsdecode(out) @lru_cache() @_api.delete_parameter("3.5", "format") -def find_tex_file(filename, format=None): +def _find_tex_file(filename, format=None): """ - Find a file in the texmf tree. + Find a file in the texmf tree using kpathsea_. - Calls :program:`kpsewhich` which is an interface to the kpathsea - library [1]_. Most existing TeX distributions on Unix-like systems use - kpathsea. It is also available as part of MikTeX, a popular - distribution on Windows. + The kpathsea library, provided by most existing TeX distributions, both + on Unix-like systems and on Windows (MikTeX), is invoked via a long-lived + luatex process if luatex is installed, or via kpsewhich otherwise. - *If the file is not found, an empty string is returned*. + .. _kpathsea: https://www.tug.org/kpathsea/ Parameters ---------- @@ -1016,10 +1014,10 @@ def find_tex_file(filename, format=None): Could be e.g. 'tfm' or 'vf' to limit the search to that type of files. Deprecated. - References - ---------- - .. [1] `Kpathsea documentation `_ - The library that :program:`kpsewhich` is part of. + Raises + ------ + FileNotFoundError + If the file is not found. """ # we expect these to always be ascii encoded, but use utf-8 @@ -1029,39 +1027,63 @@ def find_tex_file(filename, format=None): if isinstance(format, bytes): format = format.decode('utf-8', errors='replace') - if format is None: + try: + lk = _LuatexKpsewhich() + except FileNotFoundError: + lk = None # Fallback to directly calling kpsewhich, as below. + + if lk and format is None: + path = lk.search(filename) + + else: + if os.name == 'nt': + # On Windows only, kpathsea can use utf-8 for cmd args and output. + # The `command_line_encoding` environment variable is set to force + # it to always use utf-8 encoding. See Matplotlib issue #11848. + kwargs = {'env': {**os.environ, 'command_line_encoding': 'utf-8'}, + 'encoding': 'utf-8'} + else: # On POSIX, run through the equivalent of os.fsdecode(). + kwargs = {'encoding': sys.getfilesystemencoding(), + 'errors': 'surrogateescape'} + + cmd = ['kpsewhich'] + if format is not None: + cmd += ['--format=' + format] + cmd += [filename] try: - lk = _LuatexKpsewhich() - except FileNotFoundError: - pass # Fallback to directly calling kpsewhich, as below. - else: - return lk.search(filename) - - if os.name == 'nt': - # On Windows only, kpathsea can use utf-8 for cmd args and output. - # The `command_line_encoding` environment variable is set to force it - # to always use utf-8 encoding. See Matplotlib issue #11848. - kwargs = {'env': {**os.environ, 'command_line_encoding': 'utf-8'}, - 'encoding': 'utf-8'} - else: # On POSIX, run through the equivalent of os.fsdecode(). - kwargs = {'encoding': sys.getfilesystemencoding(), - 'errors': 'surrogatescape'} - - cmd = ['kpsewhich'] - if format is not None: - cmd += ['--format=' + format] - cmd += [filename] + path = (cbook._check_and_log_subprocess(cmd, _log, **kwargs) + .rstrip('\n')) + except (FileNotFoundError, RuntimeError): + path = None + + if path: + return path + else: + raise FileNotFoundError( + f"Matplotlib's TeX implementation searched for a file named " + f"{filename!r} in your texmf tree, but could not find it") + + +# After the deprecation period elapses, delete this shim and rename +# _find_tex_file to find_tex_file everywhere. +@_api.delete_parameter("3.5", "format") +def find_tex_file(filename, format=None): try: - result = cbook._check_and_log_subprocess(cmd, _log, **kwargs) - except (FileNotFoundError, RuntimeError): - return '' - return result.rstrip('\n') + return (_find_tex_file(filename, format) if format is not None else + _find_tex_file(filename)) + except FileNotFoundError as exc: + _api.warn_deprecated( + "3.6", message=f"{exc.args[0]}; in the future, this will raise a " + f"FileNotFoundError.") + return "" + + +find_tex_file.__doc__ = _find_tex_file.__doc__ @lru_cache() def _fontfile(cls, suffix, texname): - filename = find_tex_file(texname + suffix) - return cls(filename) if filename else None + return cls(_find_tex_file(texname + suffix)) _tfmfile = partial(_fontfile, Tfm, ".tfm") @@ -1077,7 +1099,7 @@ def _fontfile(cls, suffix, texname): parser.add_argument("dpi", nargs="?", type=float, default=None) args = parser.parse_args() with Dvi(args.filename, args.dpi) as dvi: - fontmap = PsfontsMap(find_tex_file('pdftex.map')) + fontmap = PsfontsMap(_find_tex_file('pdftex.map')) for page in dvi: print(f"=== new page === " f"(w: {page.width}, h: {page.height}, d: {page.descent})") diff --git a/lib/matplotlib/testing/__init__.py b/lib/matplotlib/testing/__init__.py index f9c547ce00aa..754277c41f43 100644 --- a/lib/matplotlib/testing/__init__.py +++ b/lib/matplotlib/testing/__init__.py @@ -78,4 +78,8 @@ def _check_for_pgf(texsystem): def _has_tex_package(package): - return bool(mpl.dviread.find_tex_file(f"{package}.sty")) + try: + mpl.dviread._find_tex_file(f"{package}.sty") + return True + except FileNotFoundError: + return False diff --git a/lib/matplotlib/tests/test_dviread.py b/lib/matplotlib/tests/test_dviread.py index a40151fd555f..7e10975f44d5 100644 --- a/lib/matplotlib/tests/test_dviread.py +++ b/lib/matplotlib/tests/test_dviread.py @@ -7,7 +7,7 @@ def test_PsfontsMap(monkeypatch): - monkeypatch.setattr(dr, 'find_tex_file', lambda x: x) + monkeypatch.setattr(dr, '_find_tex_file', lambda x: x) filename = str(Path(__file__).parent / 'baseline_images/dviread/test.map') fontmap = dr.PsfontsMap(filename) diff --git a/lib/matplotlib/textpath.py b/lib/matplotlib/textpath.py index 9b14e79ec2d2..5ef56e4be885 100644 --- a/lib/matplotlib/textpath.py +++ b/lib/matplotlib/textpath.py @@ -279,7 +279,7 @@ def get_glyphs_tex(self, prop, s, glyph_map=None, @staticmethod @functools.lru_cache(50) def _get_ps_font_and_encoding(texname): - tex_font_map = dviread.PsfontsMap(dviread.find_tex_file('pdftex.map')) + tex_font_map = dviread.PsfontsMap(dviread._find_tex_file('pdftex.map')) psfont = tex_font_map[texname] if psfont.filename is None: raise ValueError( pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy