Get the version of some executable that Matplotlib optionally depends on. .. warning:: The list of executables that this function supports is set according to Matplotlib's internal needs, and may change without notice. Parameters ---------- name : str The
(name)
| 363 | |
| 364 | @functools.cache |
| 365 | def _get_executable_info(name): |
| 366 | """ |
| 367 | Get the version of some executable that Matplotlib optionally depends on. |
| 368 | |
| 369 | .. warning:: |
| 370 | The list of executables that this function supports is set according to |
| 371 | Matplotlib's internal needs, and may change without notice. |
| 372 | |
| 373 | Parameters |
| 374 | ---------- |
| 375 | name : str |
| 376 | The executable to query. The following values are currently supported: |
| 377 | "dvipng", "gs", "inkscape", "magick", "pdftocairo", "pdftops". This |
| 378 | list is subject to change without notice. |
| 379 | |
| 380 | Returns |
| 381 | ------- |
| 382 | tuple |
| 383 | A namedtuple with fields ``executable`` (`str`) and ``version`` |
| 384 | (`packaging.Version`, or ``None`` if the version cannot be determined). |
| 385 | |
| 386 | Raises |
| 387 | ------ |
| 388 | ExecutableNotFoundError |
| 389 | If the executable is not found or older than the oldest version |
| 390 | supported by Matplotlib. For debugging purposes, it is also |
| 391 | possible to "hide" an executable from Matplotlib by adding it to the |
| 392 | :envvar:`_MPLHIDEEXECUTABLES` environment variable (a comma-separated |
| 393 | list), which must be set prior to any calls to this function. |
| 394 | ValueError |
| 395 | If the executable is not one that we know how to query. |
| 396 | """ |
| 397 | |
| 398 | def impl(args, regex, min_ver=None, ignore_exit_code=False): |
| 399 | # Execute the subprocess specified by args; capture stdout and stderr. |
| 400 | # Search for a regex match in the output; if the match succeeds, the |
| 401 | # first group of the match is the version. |
| 402 | # Return an _ExecInfo if the executable exists, and has a version of |
| 403 | # at least min_ver (if set); else, raise ExecutableNotFoundError. |
| 404 | try: |
| 405 | output = subprocess.check_output( |
| 406 | args, stderr=subprocess.STDOUT, |
| 407 | text=True, errors="replace", timeout=30) |
| 408 | except subprocess.CalledProcessError as _cpe: |
| 409 | if ignore_exit_code: |
| 410 | output = _cpe.output |
| 411 | else: |
| 412 | raise ExecutableNotFoundError(str(_cpe)) from _cpe |
| 413 | except subprocess.TimeoutExpired as _te: |
| 414 | msg = f"Timed out running {cbook._pformat_subprocess(args)}" |
| 415 | raise ExecutableNotFoundError(msg) from _te |
| 416 | except OSError as _ose: |
| 417 | raise ExecutableNotFoundError(str(_ose)) from _ose |
| 418 | match = re.search(regex, output) |
| 419 | if match: |
| 420 | raw_version = match.group(1) |
| 421 | version = parse_version(raw_version) |
| 422 | if min_ver is not None and version < parse_version(min_ver): |
no test coverage detected
searching dependent graphs…