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>
178 lines
6.4 KiB
Python
178 lines
6.4 KiB
Python
'''
|
|
Helper to build pydevd.
|
|
|
|
It should:
|
|
* recreate our generated files
|
|
* compile cython deps (properly setting up the environment first).
|
|
|
|
Note that it's used in the CI to build the cython deps based on the PYDEVD_USE_CYTHON environment variable.
|
|
'''
|
|
from __future__ import print_function
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
from generate_code import remove_if_exists, root_dir, is_python_64bit, generate_dont_trace_files, generate_cython_module
|
|
|
|
|
|
def validate_pair(ob):
|
|
try:
|
|
if not (len(ob) == 2):
|
|
print("Unexpected result:", ob, file=sys.stderr)
|
|
raise ValueError
|
|
except:
|
|
return False
|
|
return True
|
|
|
|
|
|
def consume(it):
|
|
try:
|
|
while True:
|
|
next(it)
|
|
except StopIteration:
|
|
pass
|
|
|
|
|
|
def get_environment_from_batch_command(env_cmd, initial=None):
|
|
"""
|
|
Take a command (either a single command or list of arguments)
|
|
and return the environment created after running that command.
|
|
Note that if the command must be a batch file or .cmd file, or the
|
|
changes to the environment will not be captured.
|
|
|
|
If initial is supplied, it is used as the initial environment passed
|
|
to the child process.
|
|
"""
|
|
if not isinstance(env_cmd, (list, tuple)):
|
|
env_cmd = [env_cmd]
|
|
if not os.path.exists(env_cmd[0]):
|
|
raise RuntimeError('Error: %s does not exist' % (env_cmd[0],))
|
|
|
|
# construct the command that will alter the environment
|
|
env_cmd = subprocess.list2cmdline(env_cmd)
|
|
# create a tag so we can tell in the output when the proc is done
|
|
tag = 'Done running command'
|
|
# construct a cmd.exe command to do accomplish this
|
|
cmd = 'cmd.exe /s /c "{env_cmd} && echo "{tag}" && set"'.format(**vars())
|
|
# launch the process
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=initial)
|
|
# parse the output sent to stdout
|
|
lines = proc.stdout
|
|
# consume whatever output occurs until the tag is reached
|
|
for line in lines:
|
|
line = line.decode('utf-8')
|
|
if 'The specified configuration type is missing.' in line:
|
|
raise AssertionError('Error executing %s. View http://blog.ionelmc.ro/2014/12/21/compiling-python-extensions-on-windows/ for details.' % (env_cmd))
|
|
if tag in line:
|
|
break
|
|
if sys.version_info[0] > 2:
|
|
# define a way to handle each KEY=VALUE line
|
|
handle_line = lambda l: l.decode('utf-8').rstrip().split('=', 1)
|
|
else:
|
|
# define a way to handle each KEY=VALUE line
|
|
handle_line = lambda l: l.rstrip().split('=', 1)
|
|
# parse key/values into pairs
|
|
pairs = map(handle_line, lines)
|
|
# make sure the pairs are valid
|
|
valid_pairs = filter(validate_pair, pairs)
|
|
# construct a dictionary of the pairs
|
|
result = dict(valid_pairs)
|
|
# let the process finish
|
|
proc.communicate()
|
|
return result
|
|
|
|
|
|
def remove_binaries(suffixes):
|
|
for f in os.listdir(os.path.join(root_dir, '_pydevd_bundle')):
|
|
for suffix in suffixes:
|
|
if f.endswith(suffix):
|
|
remove_if_exists(os.path.join(root_dir, '_pydevd_bundle', f))
|
|
|
|
|
|
def build():
|
|
if '--no-remove-binaries' not in sys.argv:
|
|
remove_binaries(['.pyd', '.so'])
|
|
|
|
os.chdir(root_dir)
|
|
|
|
env = None
|
|
if sys.platform == 'win32':
|
|
# "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
|
|
# set MSSdk=1
|
|
# set DISTUTILS_USE_SDK=1
|
|
# set VS100COMNTOOLS=C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools
|
|
|
|
if 'GITHUB_ACTION' not in os.environ:
|
|
env = os.environ.copy()
|
|
if sys.version_info[:2] in ((3, 6), (3, 7), (3, 8), (3, 9), (3, 10), (3, 11)):
|
|
FORCE_PYDEVD_VC_VARS = os.environ.get('FORCE_PYDEVD_VC_VARS')
|
|
if FORCE_PYDEVD_VC_VARS:
|
|
env.update(get_environment_from_batch_command([FORCE_PYDEVD_VC_VARS], initial=os.environ.copy()))
|
|
else:
|
|
import setuptools # We have to import it first for the compiler to be found
|
|
from distutils import msvc9compiler
|
|
|
|
vcvarsall = msvc9compiler.find_vcvarsall(14.0)
|
|
if vcvarsall is None or not os.path.exists(vcvarsall):
|
|
msvc_version = msvc9compiler.get_build_version()
|
|
print('msvc_version', msvc_version)
|
|
vcvarsall = msvc9compiler.find_vcvarsall(msvc_version)
|
|
|
|
if vcvarsall is None or not os.path.exists(vcvarsall):
|
|
raise RuntimeError('Error finding vcvarsall.')
|
|
|
|
if is_python_64bit():
|
|
env.update(get_environment_from_batch_command(
|
|
[vcvarsall, 'amd64'],
|
|
initial=os.environ.copy()))
|
|
else:
|
|
env.update(get_environment_from_batch_command(
|
|
[vcvarsall, 'x86'],
|
|
initial=os.environ.copy()))
|
|
|
|
else:
|
|
raise AssertionError('Unable to setup environment for Python: %s' % (sys.version,))
|
|
|
|
env['MSSdk'] = '1'
|
|
env['DISTUTILS_USE_SDK'] = '1'
|
|
|
|
additional_args = []
|
|
for arg in sys.argv:
|
|
if arg.startswith('--target-pyd-name='):
|
|
additional_args.append(arg)
|
|
if arg.startswith('--target-pyd-frame-eval='):
|
|
additional_args.append(arg)
|
|
break
|
|
else:
|
|
additional_args.append('--force-cython') # Build always forces cython!
|
|
|
|
args = [
|
|
sys.executable, os.path.join(os.path.dirname(__file__), '..', 'setup_pydevd_cython.py'), 'build_ext', '--inplace',
|
|
] + additional_args
|
|
print('Calling args: %s' % (args,))
|
|
subprocess.check_call(args, env=env,)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
use_cython = os.getenv('PYDEVD_USE_CYTHON', '').lower()
|
|
# Note: don't import pydevd during build (so, accept just yes/no in this case).
|
|
if use_cython == 'yes':
|
|
print("Building")
|
|
build()
|
|
elif use_cython == 'no':
|
|
print("Removing binaries")
|
|
remove_binaries(['.pyd', '.so'])
|
|
elif not use_cython:
|
|
# Regular process
|
|
if '--no-regenerate-files' not in sys.argv:
|
|
print("Generating dont trace files")
|
|
generate_dont_trace_files()
|
|
print("Generating cython modules")
|
|
generate_cython_module()
|
|
print("Building")
|
|
build()
|
|
else:
|
|
raise RuntimeError('Unexpected value for PYDEVD_USE_CYTHON: %s (accepted: yes, no)' % (use_cython,))
|
|
|