ec5f52c7c6
Bundles debugpy 1.7.0 directly in python/ so "Maya: Attach (debugpy)" works with no per-machine pip install step. Installed via Maya 2022's own pip so it resolved a version actually compatible with Python 3.7 (Maya 2022's interpreter), then verified import + listen() succeeds under all three target Maya Python versions (3.7/3.9/3.10). Also fixes a latent __file__-under-exec() bug in start_debug_server.py (same pitfall as Maya's own plugin loader, never hit until this exercised it) and corrects the README's Maya Python version claim -- 2022 ships Python 3.7, not 3.9 as previously stated, which was never independently verified until now. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
150 lines
5.3 KiB
Python
150 lines
5.3 KiB
Python
|
|
import sys
|
|
from _pydev_bundle import pydev_log
|
|
|
|
backends = {'tk': 'TkAgg',
|
|
'gtk': 'GTKAgg',
|
|
'wx': 'WXAgg',
|
|
'qt': 'QtAgg', # Auto-choose qt4/5
|
|
'qt4': 'Qt4Agg',
|
|
'qt5': 'Qt5Agg',
|
|
'osx': 'MacOSX'}
|
|
|
|
# We also need a reverse backends2guis mapping that will properly choose which
|
|
# GUI support to activate based on the desired matplotlib backend. For the
|
|
# most part it's just a reverse of the above dict, but we also need to add a
|
|
# few others that map to the same GUI manually:
|
|
backend2gui = dict(zip(backends.values(), backends.keys()))
|
|
# In the reverse mapping, there are a few extra valid matplotlib backends that
|
|
# map to the same GUI support
|
|
backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
|
|
backend2gui['WX'] = 'wx'
|
|
backend2gui['CocoaAgg'] = 'osx'
|
|
|
|
|
|
def do_enable_gui(guiname):
|
|
from _pydev_bundle.pydev_versioncheck import versionok_for_gui
|
|
if versionok_for_gui():
|
|
try:
|
|
from pydev_ipython.inputhook import enable_gui
|
|
enable_gui(guiname)
|
|
except:
|
|
sys.stderr.write("Failed to enable GUI event loop integration for '%s'\n" % guiname)
|
|
pydev_log.exception()
|
|
elif guiname not in ['none', '', None]:
|
|
# Only print a warning if the guiname was going to do something
|
|
sys.stderr.write("Debug console: Python version does not support GUI event loop integration for '%s'\n" % guiname)
|
|
# Return value does not matter, so return back what was sent
|
|
return guiname
|
|
|
|
|
|
def find_gui_and_backend():
|
|
"""Return the gui and mpl backend."""
|
|
matplotlib = sys.modules['matplotlib']
|
|
# WARNING: this assumes matplotlib 1.1 or newer!!
|
|
backend = matplotlib.rcParams['backend']
|
|
# In this case, we need to find what the appropriate gui selection call
|
|
# should be for IPython, so we can activate inputhook accordingly
|
|
gui = backend2gui.get(backend, None)
|
|
return gui, backend
|
|
|
|
|
|
def is_interactive_backend(backend):
|
|
""" Check if backend is interactive """
|
|
matplotlib = sys.modules['matplotlib']
|
|
from matplotlib.rcsetup import interactive_bk, non_interactive_bk # @UnresolvedImport
|
|
if backend in interactive_bk:
|
|
return True
|
|
elif backend in non_interactive_bk:
|
|
return False
|
|
else:
|
|
return matplotlib.is_interactive()
|
|
|
|
|
|
def patch_use(enable_gui_function):
|
|
""" Patch matplotlib function 'use' """
|
|
matplotlib = sys.modules['matplotlib']
|
|
|
|
def patched_use(*args, **kwargs):
|
|
matplotlib.real_use(*args, **kwargs)
|
|
gui, backend = find_gui_and_backend()
|
|
enable_gui_function(gui)
|
|
|
|
matplotlib.real_use = matplotlib.use
|
|
matplotlib.use = patched_use
|
|
|
|
|
|
def patch_is_interactive():
|
|
""" Patch matplotlib function 'use' """
|
|
matplotlib = sys.modules['matplotlib']
|
|
|
|
def patched_is_interactive():
|
|
return matplotlib.rcParams['interactive']
|
|
|
|
matplotlib.real_is_interactive = matplotlib.is_interactive
|
|
matplotlib.is_interactive = patched_is_interactive
|
|
|
|
|
|
def activate_matplotlib(enable_gui_function):
|
|
"""Set interactive to True for interactive backends.
|
|
enable_gui_function - Function which enables gui, should be run in the main thread.
|
|
"""
|
|
matplotlib = sys.modules['matplotlib']
|
|
gui, backend = find_gui_and_backend()
|
|
is_interactive = is_interactive_backend(backend)
|
|
if is_interactive:
|
|
enable_gui_function(gui)
|
|
if not matplotlib.is_interactive():
|
|
sys.stdout.write("Backend %s is interactive backend. Turning interactive mode on.\n" % backend)
|
|
matplotlib.interactive(True)
|
|
else:
|
|
if matplotlib.is_interactive():
|
|
sys.stdout.write("Backend %s is non-interactive backend. Turning interactive mode off.\n" % backend)
|
|
matplotlib.interactive(False)
|
|
patch_use(enable_gui_function)
|
|
patch_is_interactive()
|
|
|
|
|
|
def flag_calls(func):
|
|
"""Wrap a function to detect and flag when it gets called.
|
|
|
|
This is a decorator which takes a function and wraps it in a function with
|
|
a 'called' attribute. wrapper.called is initialized to False.
|
|
|
|
The wrapper.called attribute is set to False right before each call to the
|
|
wrapped function, so if the call fails it remains False. After the call
|
|
completes, wrapper.called is set to True and the output is returned.
|
|
|
|
Testing for truth in wrapper.called allows you to determine if a call to
|
|
func() was attempted and succeeded."""
|
|
|
|
# don't wrap twice
|
|
if hasattr(func, 'called'):
|
|
return func
|
|
|
|
def wrapper(*args, **kw):
|
|
wrapper.called = False
|
|
out = func(*args, **kw)
|
|
wrapper.called = True
|
|
return out
|
|
|
|
wrapper.called = False
|
|
wrapper.__doc__ = func.__doc__
|
|
return wrapper
|
|
|
|
|
|
def activate_pylab():
|
|
pylab = sys.modules['pylab']
|
|
pylab.show._needmain = False
|
|
# We need to detect at runtime whether show() is called by the user.
|
|
# For this, we wrap it into a decorator which adds a 'called' flag.
|
|
pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
|
|
|
|
|
|
def activate_pyplot():
|
|
pyplot = sys.modules['matplotlib.pyplot']
|
|
pyplot.show._needmain = False
|
|
# We need to detect at runtime whether show() is called by the user.
|
|
# For this, we wrap it into a decorator which adds a 'called' flag.
|
|
pyplot.draw_if_interactive = flag_calls(pyplot.draw_if_interactive)
|