hook-matplotlib.backends.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #-----------------------------------------------------------------------------
  2. # Copyright (c) 2013-2021, PyInstaller Development Team.
  3. #
  4. # Distributed under the terms of the GNU General Public License (version 2
  5. # or later) with exception for distributing the bootloader.
  6. #
  7. # The full license is in the file COPYING.txt, distributed with this software.
  8. #
  9. # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
  10. #-----------------------------------------------------------------------------
  11. from PyInstaller.compat import is_darwin
  12. from PyInstaller.utils.hooks import (
  13. eval_statement, exec_statement, logger)
  14. def get_matplotlib_backend_module_names():
  15. """
  16. List the names of all matplotlib backend modules importable under the
  17. current Python installation.
  18. Returns
  19. ----------
  20. list
  21. List of the fully-qualified names of all such modules.
  22. """
  23. # Statement safely importing a single backend module.
  24. import_statement = """
  25. import os, sys
  26. # Preserve stdout.
  27. sys_stdout = sys.stdout
  28. try:
  29. # Redirect output printed by this importation to "/dev/null", preventing
  30. # such output from being erroneously interpreted as an error.
  31. with open(os.devnull, 'w') as dev_null:
  32. sys.stdout = dev_null
  33. __import__('%s')
  34. # If this is an ImportError, print this exception's message without a traceback.
  35. # ImportError messages are human-readable and require no additional context.
  36. except ImportError as exc:
  37. sys.stdout = sys_stdout
  38. print(exc)
  39. # Else, print this exception preceded by a traceback. traceback.print_exc()
  40. # prints to stderr rather than stdout and must not be called here!
  41. except Exception:
  42. sys.stdout = sys_stdout
  43. import traceback
  44. print(traceback.format_exc())
  45. """
  46. # List of the human-readable names of all available backends.
  47. backend_names = eval_statement(
  48. 'import matplotlib; print(matplotlib.rcsetup.all_backends)')
  49. # List of the fully-qualified names of all importable backend modules.
  50. module_names = []
  51. # If the current system is not OS X and the "CocoaAgg" backend is available,
  52. # remove this backend from consideration. Attempting to import this backend
  53. # on non-OS X systems halts the current subprocess without printing output
  54. # or raising exceptions, preventing its reliable detection.
  55. if not is_darwin and 'CocoaAgg' in backend_names:
  56. backend_names.remove('CocoaAgg')
  57. # For safety, attempt to import each backend in a unique subprocess.
  58. for backend_name in backend_names:
  59. module_name = 'matplotlib.backends.backend_%s' % backend_name.lower()
  60. stdout = exec_statement(import_statement % module_name)
  61. # If no output was printed, this backend is importable.
  62. if not stdout:
  63. module_names.append(module_name)
  64. logger.info(' Matplotlib backend "%s": added' % backend_name)
  65. else:
  66. logger.info(' Matplotlib backend "%s": ignored\n %s' % (backend_name, stdout))
  67. return module_names
  68. # Freeze all importable backends, as PyInstaller is unable to determine exactly
  69. # which backends are required by the current program.
  70. hiddenimports = get_matplotlib_backend_module_names()