Vendor debugpy for VS Code attach debugging

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>
This commit is contained in:
2026-07-14 09:01:16 +08:00
parent e2f2e6668a
commit ec5f52c7c6
623 changed files with 236815 additions and 12 deletions
@@ -0,0 +1,331 @@
def foo():
a=1
b=2
c=3
d=4
e=5
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
if a == 1:
if b == 2:
if c == 3:
if d == 999:
x = 20
elif d == 998:
x = 40
elif d == 4:
if e != 5:
x = 20
else:
x = 50
assert x
@@ -0,0 +1,126 @@
from contextlib import contextmanager
def method1():
_a = 0
while _a < 2: # break while
_a += 1
def method2():
try:
raise AssertionError()
except: # break except
pass
@contextmanager
def ctx():
yield ''
def method3():
with ctx() as a: # break with
return a
def method4():
_a = 0
for i in range(2): # break for
_a = i
def method5():
try: # break try 1
_a = 10
finally:
_b = 10
def method6():
try:
_a = 10 # break try 2
finally:
_b = 10
def method7():
try:
_a = 10
finally:
_b = 10 # break finally 1
def method8():
try:
raise AssertionError()
except: # break except 2
_b = 10
finally:
_c = 20
def method9():
# As a note, Python 3.10 is eager to optimize this case and it duplicates the _c = 20
# in a codepath where the exception is raised and another where it's not raised.
# The frame eval mode must modify the bytecode so that both paths have the
# programmatic breakpoint added!
try:
_a = 10
except:
_b = 10
finally:_c = 20 # break finally 2
def method9a():
# Same as method9, but with exception raised (but handled).
try:
raise AssertionError()
except:
_b = 10
finally:_c = 20 # break finally 3
def method9b():
# Same as method9, but with exception raised (unhandled).
try:
try:
raise RuntimeError()
except AssertionError:
_b = 10
finally:_c = 20 # break finally 4
except:
pass
def method10():
_a = {
0: 0,
1: 1, # break in dict
2: 2,
}
def method11():
a = 11
if a == 10:
a = 20
else: a = 30 # break else
if __name__ == '__main__':
method1()
method2()
method3()
method4()
method5()
method6()
method7()
method8()
method9()
method9a()
method9b()
method10()
method11()
print('TEST SUCEEDED')
@@ -0,0 +1,268 @@
def foo():
a0 = 1
a1 = 1
a2 = 1
a3 = 1
a4 = 1
a5 = 1
a6 = 1
a7 = 1
a8 = 1
a9 = 1
a10 = 1
a11 = 1
a12 = 1
a13 = 1
a14 = 1
a15 = 1
a16 = 1
a17 = 1
a18 = 1
a19 = 1
a20 = 1
a21 = 1
a22 = 1
a23 = 1
a24 = 1
a25 = 1
a26 = 1
a27 = 1
a28 = 1
a29 = 1
a30 = 1
a31 = 1
a32 = 1
a33 = 1
a34 = 1
a35 = 1
a36 = 1
a37 = 1
a38 = 1
a39 = 1
a40 = 1
a41 = 1
a42 = 1
a43 = 1
a44 = 1
a45 = 1
a46 = 1
a47 = 1
a48 = 1
a49 = 1
a50 = 1
a51 = 1
a52 = 1
a53 = 1
a54 = 1
a55 = 1
a56 = 1
a57 = 1
a58 = 1
a59 = 1
a60 = 1
a61 = 1
a62 = 1
a63 = 1
a64 = 1
a65 = 1
a66 = 1
a67 = 1
a68 = 1
a69 = 1
a70 = 1
a71 = 1
a72 = 1
a73 = 1
a74 = 1
a75 = 1
a76 = 1
a77 = 1
a78 = 1
a79 = 1
a80 = 1
a81 = 1
a82 = 1
a83 = 1
a84 = 1
a85 = 1
a86 = 1
a87 = 1
a88 = 1
a89 = 1
a90 = 1
a91 = 1
a92 = 1
a93 = 1
a94 = 1
a95 = 1
a96 = 1
a97 = 1
a98 = 1
a99 = 1
a100 = 1
a101 = 1
a102 = 1
a103 = 1
a104 = 1
a105 = 1
a106 = 1
a107 = 1
a108 = 1
a109 = 1
a110 = 1
a111 = 1
a112 = 1
a113 = 1
a114 = 1
a115 = 1
a116 = 1
a117 = 1
a118 = 1
a119 = 1
a120 = 1
a121 = 1
a122 = 1
a123 = 1
a124 = 1
a125 = 1
a126 = 1
a127 = 1
a128 = 1
a129 = 1
a130 = 1
a131 = 1
a132 = 1
a133 = 1
a134 = 1
a135 = 1
a136 = 1
a137 = 1
a138 = 1
a139 = 1
a140 = 1
a141 = 1
a142 = 1
a143 = 1
a144 = 1
a145 = 1
a146 = 1
a147 = 1
a148 = 1
a149 = 1
a150 = 1
a151 = 1
a152 = 1
a153 = 1
a154 = 1
a155 = 1
a156 = 1
a157 = 1
a158 = 1
a159 = 1
a160 = 1
a161 = 1
a162 = 1
a163 = 1
a164 = 1
a165 = 1
a166 = 1
a167 = 1
a168 = 1
a169 = 1
a170 = 1
a171 = 1
a172 = 1
a173 = 1
a174 = 1
a175 = 1
a176 = 1
a177 = 1
a178 = 1
a179 = 1
a180 = 1
a181 = 1
a182 = 1
a183 = 1
a184 = 1
a185 = 1
a186 = 1
a187 = 1
a188 = 1
a189 = 1
a190 = 1
a191 = 1
a192 = 1
a193 = 1
a194 = 1
a195 = 1
a196 = 1
a197 = 1
a198 = 1
a199 = 1
a200 = 1
a201 = 1
a202 = 1
a203 = 1
a204 = 1
a205 = 1
a206 = 1
a207 = 1
a208 = 1
a209 = 1
a210 = 1
a211 = 1
a212 = 1
a213 = 1
a214 = 1
a215 = 1
a216 = 1
a217 = 1
a218 = 1
a219 = 1
a220 = 1
a221 = 1
a222 = 1
a223 = 1
a224 = 1
a225 = 1
a226 = 1
a227 = 1
a228 = 1
a229 = 1
a230 = 1
a231 = 1
a232 = 1
a233 = 1
a234 = 1
a235 = 1
a236 = 1
a237 = 1
a238 = 1
a239 = 1
a240 = 1
a241 = 1
a242 = 1
a243 = 1
a244 = 1
a245 = 1
a246 = 1
a247 = 1
a248 = 1
a249 = 1
a250 = 1
a251 = 1
a252 = 1
a253 = 1
a254 = 1
a255 = 1
a256 = 1
a257 = 1
a258 = 1
a259 = 1
b = a1 + a2
a260 = 1
a261 = 1
return b
@@ -0,0 +1,89 @@
def check_backtrack(x): # line 1
if not (x == 'a' # line 2
or x == 'c'): # line 3
pass # line 4
import re
import sys
en_lang_symbols = r'[^\w!@#$%\^-_+=|\}{][\"\';:?\/><.,&)(*\s`\u2019]'
en_words_basic = []
en_words = []
class Dummy:
non_en_words_limit = 3
@staticmethod
def fun(text):
words = tuple(w[0].lower() for w in re.finditer(r'[a-zA-Z]+', text))
non_en_pass = []
for i, word in enumerate(words):
non_en = []
if not (word in en_words_basic
or (word.endswith('s') and word[:-1] in en_words_basic)
or (word.endswith('ed') and word[:-2] in en_words_basic)
or (word.endswith('ing') and word[:-3] in en_words_basic)
or word in en_words
or (word.endswith('s') and word[:-1] in en_words)
or (word.endswith('ed') and word[:-2] in en_words)
or (word.endswith('ing') and word[:-3] in en_words)
):
non_en.append(word)
non_en_pass.append(word)
for j in range(1, Dummy.non_en_words_limit):
if i + j >= len(words):
break
word = words[i + j]
if (word in en_words_basic
or (word.endswith('s') and word[:-1] in en_words_basic)
or (word.endswith('ed') and word[:-2] in en_words_basic)
or (word.endswith('ing') and word[:-3] in en_words_basic)
or word in en_words
or (word.endswith('s') and word[:-1] in en_words)
or (word.endswith('ed') and word[:-2] in en_words)
or (word.endswith('ing') and word[:-3] in en_words)
):
break
else:
non_en.append(word)
non_en_pass.append(word)
def offset_overflow(stream=sys.stdout):
a = 1
b = 2
c = 3
a1 = 1 if a > 1 else 2
a2 = 1 if a > 1 else 2
a3 = 1 if a > 1 else 2
a4 = 1 if a > 1 else 2
a5 = 1 if a > 1 else 2
a6 = 1 if a > 1 else 2
a7 = 1 if a > 1 else 2
a8 = 1 if a > 1 else 2
a9 = 1 if a > 1 else 2
a10 = 1 if a > 1 else 2
a11 = 1 if a > 1 else 2
a12 = 1 if a > 1 else 2
a13 = 1 if a > 1 else 2
for i in range(1):
if a > 0:
stream.write("111\n")
# a = 1
else:
stream.write("222\n")
return b
def long_lines():
a = 1
b = 1 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23
c = 1 if b > 1 else 2 if b > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23
d = 1 if c > 1 else 2 if c > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23 if a > 1 else 2 if a > 0 else 3 if a > 4 else 23
e = d + 1
return e
@@ -0,0 +1,22 @@
class A(object):
def __init__(self):
self.a = 10
class B(A):
def __init__(self):
super().__init__() # break here
assert self.a == 10
def method():
self.b = self.a
method()
assert self.b == 10
if __name__ == '__main__':
B()
print('TEST SUCEEDED')
@@ -0,0 +1,61 @@
import sys
import weakref
def set_up():
observable = Observable()
observer = Observer()
observable.add_observer(observer)
return observable
class Observable(object):
def __init__(self):
self.observers = []
def add_observer(self, observer):
sys.stdout.write( 'observer %s\n' % (observer,))
ref = weakref.ref(observer)
self.observers.append(ref)
sys.stdout.write('weakref: %s\n' % (ref(),))
def Notify(self):
for o in self.observers:
o = o()
try:
import gc
except ImportError:
o = None #some jython does not have gc, so, there's no sense testing this in it
else:
try:
gc.get_referrers(o)
except:
o = None #jython and ironpython do not have get_referrers
if o is not None:
sys.stdout.write('still observing %s\n' % (o,))
sys.stdout.write('number of referrers: %s\n' % len(gc.get_referrers(o)))
frame = gc.get_referrers(o)[0]
frame_referrers = gc.get_referrers(frame)
sys.stdout.write('frame referrer %s\n' % (frame_referrers,))
referrers1 = gc.get_referrers(frame_referrers[1])
sys.stdout.write('%s\n' % (referrers1,))
sys.stderr.write('TEST FAILED: The observer should have died, even when running in debug\n')
else:
sys.stdout.write('TEST SUCEEDED: observer died\n')
sys.stdout.flush()
sys.stderr.flush()
class Observer(object):
pass
def main():
observable = set_up()
observable.Notify()
if __name__ == '__main__':
main()
@@ -0,0 +1,43 @@
class TestProperty(object):
def __init__(self, name = "Default"):
self._x = None
self.name = name
def get_name(self):
return self.__name
def set_name(self, value):
self.__name = value
def del_name(self):
del self.__name
name = property(get_name, set_name, del_name, "name's docstring")
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
def main():
"""
"""
testObj = TestProperty()
testObj.x = 10
val = testObj.x
testObj.name = "Pydev"
debugType = testObj.name
print('TEST SUCEEDED!')
if __name__ == '__main__':
main()
@@ -0,0 +1,29 @@
class Car(object):
"""A car class"""
def __init__(self, model, make, color):
self.model = model
self.make = make
self.color = color
self.price = None
def get_price(self):
return self.price
def set_price(self, value):
self.price = value
availableCars = []
def main():
global availableCars
#Create a new car obj
carObj = Car("Maruti SX4", "2011", "Black")
carObj.set_price(950000) # Set price
# Add this to available cars
availableCars.append(carObj)
print('TEST SUCEEDED')
if __name__ == '__main__':
main()
@@ -0,0 +1,29 @@
class Car(object):
"""A car class"""
def __init__(self, model, make, color):
self.model = model
self.make = make
self.color = color
self.price = None
def get_price(self):
return self.price
def set_price(self, value):
self.price = value
availableCars = []
def main():
global availableCars
#Create a new car obj
carObj = Car("Maruti SX4", "2011", "Black")
carObj.set_price(950000) # Set price
# Add this to available cars
availableCars.append(carObj)
print('TEST SUCEEDED')
if __name__ == '__main__':
main()
@@ -0,0 +1 @@
f=lambda x: 'val=%s' % x
@@ -0,0 +1,12 @@
# this test requires numpy to be installed
import numpy
def main():
smallarray = numpy.arange(100) * 1 + 1j
bigarray = numpy.arange(100000).reshape((10,10000)) # 100 thousand
hugearray = numpy.arange(10000000) # 10 million
pass # location of breakpoint after all arrays defined
main()
print('TEST SUCEEDED')
@@ -0,0 +1,44 @@
def get_here():
a = 10
def foo(func):
return func
def m1(): # @DontTrace
get_here()
# @DontTrace
def m2():
get_here()
# @DontTrace
@foo
def m3():
get_here()
@foo
@foo
def m4(): # @DontTrace
get_here()
def main():
m1() # break1
m2() # break2
m3() # break3
m4() # break4
if __name__ == '__main__':
main()
print('TEST SUCEEDED')
@@ -0,0 +1,18 @@
def m1():
_a = 'm1' # break 1 here
def m2(): # @DontTrace
m1()
_a = 'm2'
def m3():
m2()
_a = 'm3' # break 2 here
if __name__ == '__main__':
m3()
print('TEST SUCEEDED')
@@ -0,0 +1,23 @@
import sys
def m2(a):
a = 10
b = 20 #Break here and set a = 40
c = 30
def function2():
print(a)
return a
def m1(a):
return m2(a)
if __name__ == '__main__':
found = m1(10)
if found == 40:
print('TEST SUCEEDED')
else:
raise AssertionError('Expected variable to be changed to 40. Found: %s' % (found,))
@@ -0,0 +1,10 @@
class A:
def __init__(self):
self.__var = 10
if __name__ == '__main__':
a = A()
print(a._A__var)
# Evaluate 'a.__var' should give a._A__var_
print('TEST SUCEEDED')
@@ -0,0 +1,24 @@
def Call4():
print('Start Call4')
print('End Call4')
def Call3():
print('Start Call3')
Call4()
print('End Call3')
def Call2():
print('Start Call2')
Call3()
print('End Call2 - a')
print('End Call2 - b')
def Call1():
print('Start Call1')
Call2()
print('End Call1')
if __name__ == '__main__':
Call1()
print('TEST SUCEEDED!')
@@ -0,0 +1,38 @@
import pydevd
import threading
original = pydevd.PyDB.notify_thread_created
found = set()
def new_notify_thread_created(self, thread_id, thread, *args, **kwargs):
found.add(thread)
return original(self, thread_id, thread, *args, **kwargs)
pydevd.PyDB.notify_thread_created = new_notify_thread_created
ok = []
class MyThread(threading.Thread):
def run(self):
if self not in found:
ok.append(False)
else:
ok.append(True)
if __name__ == '__main__':
threads = []
for i in range(15):
t = MyThread()
t.start()
threads.append(t)
for t in threads:
t.join()
assert len(ok) == len(threads)
assert all(ok), 'Expected all threads to be notified of their creation before starting to run. Found: %s' % (ok,)
found.clear()
print('TEST SUCEEDED')
@@ -0,0 +1,8 @@
import time
if __name__ == '__main__':
for i in range(15):
print('here')
time.sleep(.1)
print('TEST SUCEEDED')
@@ -0,0 +1,22 @@
import time
class ProceedContainer:
proceed = False
def exit_while_loop():
ProceedContainer.proceed = True
return 'ok'
def sleep():
while not ProceedContainer.proceed: # The debugger should change the proceed to True to exit the loop.
time.sleep(.1)
if __name__ == '__main__':
sleep()
print('TEST SUCEEDED')
@@ -0,0 +1,9 @@
def Call2():
print('Call2')
def Call1(a):
print('Call1')
if __name__ == '__main__':
Call1(Call2())
print('TEST SUCEEDED!')
@@ -0,0 +1,16 @@
def Method1():
print('m1')
def Method2():
print('m2 before')
Method1()
print('m2 after')
def Method3():
print('m3 before')
Method2()
print('m3 after')
if __name__ == '__main__':
Method3()
print('TEST SUCEEDED!')
@@ -0,0 +1,11 @@
def Call():
b = True
while b: # expected
# requested
pass # Note: until 3.10 a pass didn't generate a line event, but starting at 3.10, it does...
break
if __name__ == '__main__':
Call()
print('TEST SUCEEDED!')
@@ -0,0 +1,21 @@
import asyncio
import sys
async def gen():
f = sys._getframe()
for i in range(10):
await asyncio.sleep(.01)
assert f is sys._getframe()
yield i
async def run():
async for p in gen():
print(p)
if __name__ == "__main__":
loop = asyncio.get_event_loop_policy().get_event_loop()
loop.run_until_complete(run())
print('TEST SUCEEDED')
@@ -0,0 +1,37 @@
import asyncio
async def count():
print('enter count')
await asyncio.sleep(.001) # break count 1
await asyncio.sleep(.001) # break count 2
async def count2():
print('enter count 2')
await asyncio.sleep(.001)
await asyncio.sleep(.001)
async def count3():
print('enter count 3')
await asyncio.sleep(.001)
await asyncio.sleep(.001)
async def main():
await count() # break main
await count2() # step main
await count3()
if __name__ == "__main__":
if hasattr(asyncio, 'run'):
print('using asyncio.run')
asyncio.run(main())
else:
print('using loop.run_until_complete')
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
print('TEST SUCEEDED!')
@@ -0,0 +1,47 @@
import time
import sys
try:
import _thread
except:
import thread as _thread
if __name__ == '__main__':
lock = _thread.allocate_lock()
initialized = [False]
print('Main thread ident should be: %s' % (_thread.get_ident()))
def new_thread_function():
sys.secondary_id = _thread.get_ident()
print('Secondary thread ident should be: %s' % (_thread.get_ident()))
wait = True
with lock:
initialized[0] = True
while wait:
time.sleep(.1) # break thread here
_thread.start_new_thread(new_thread_function, ())
wait = True
while not initialized[0]:
time.sleep(.1)
with lock: # It'll be here until the secondary thread finishes (i.e.: releases the lock).
pass
import threading # Note: only import after the attach.
curr_thread_ident = threading.current_thread().ident
if hasattr(threading, 'main_thread'):
main_thread_ident = threading.main_thread().ident
else:
# Python 2 does not have main_thread, but we can still get the reference.
main_thread_ident = threading._shutdown.im_self.ident
if curr_thread_ident != main_thread_ident:
raise AssertionError('Expected current thread ident (%s) to be the main thread ident (%s)' % (
curr_thread_ident, main_thread_ident))
print('TEST SUCEEDED')
@@ -0,0 +1,17 @@
import time
if __name__ == '__main__':
wait = True
while wait:
time.sleep(1) # break here
# Ok, if it got here things are looking good, let's just make
# sure that the threading module main thread has the correct ident.
import threading # Note: only import after the attach.
if hasattr(threading, 'main_thread'):
assert threading.current_thread().ident == threading.main_thread().ident
else:
# Python 2 does not have main_thread, but we can still get the reference.
assert threading.current_thread().ident == threading._shutdown.im_self.ident
print('TEST SUCEEDED')
@@ -0,0 +1,7 @@
def break_in_method():
breakpoint() # Builtin on Py3, but we provide a backport on Py2.
break_in_method()
print('TEST SUCEEDED')
@@ -0,0 +1,7 @@
import sys
def break_in_method():
sys.__breakpointhook__() # Builtin on Py3, but we provide a backport on Py2.
break_in_method()
print('TEST SUCEEDED')
@@ -0,0 +1,8 @@
def Call():
for i in range(10): # break here
last_i = i
if __name__ == '__main__':
Call()
print('TEST SUCEEDED!')
@@ -0,0 +1,15 @@
if __name__ == '__main__':
import os
import sys
port = int(sys.argv[1])
root_dirname = os.path.dirname(os.path.dirname(__file__))
if root_dirname not in sys.path:
sys.path.append(root_dirname)
import pydevd
print('before pydevd.settrace')
breakpoint(port=port)
print('after pydevd.settrace')
print('TEST SUCEEDED!')
@@ -0,0 +1,14 @@
if __name__ == '__main__':
import os
import sys
port = int(sys.argv[1])
root_dirname = os.path.dirname(os.path.dirname(__file__))
if root_dirname not in sys.path:
sys.path.append(root_dirname)
print('before pydevd.settrace')
breakpoint(port=port) # Set up through custom sitecustomize.py
print('after pydevd.settrace')
print('TEST SUCEEDED!')
@@ -0,0 +1,12 @@
def method():
_a = 1 # break 1
_a = 2
_a = 3 # break 2
if __name__ == '__main__':
for i in range(2):
method()
print('TEST SUCEEDED') # break 3
@@ -0,0 +1,100 @@
import threading, atexit, sys
from collections import namedtuple
import os.path
if sys.version_info[0] >= 3:
from _thread import start_new_thread
else:
from thread import start_new_thread
FrameInfo = namedtuple('FrameInfo', 'filename, name, f_trace')
def _atexit():
sys.stderr.flush()
sys.stdout.flush()
# Register the TEST SUCEEDED msg to the exit of the process.
atexit.register(_atexit)
def _iter_frame_info(frame):
while frame is not None:
yield FrameInfo(
os.path.basename(frame.f_code.co_filename),
frame.f_code.co_name,
frame.f_trace.__name__ if frame.f_trace is not None else "None"
)
frame = frame.f_back
def check_frame_info(expected):
found = list(_iter_frame_info(sys._getframe().f_back))
def fail():
raise AssertionError('Expected:\n%s\n\nFound:\n%s\n' % (
'\n'.join(str(x) for x in expected),
'\n'.join(str(x) for x in found)))
for found_info, expected_info in zip(found, expected):
if found_info.filename != expected_info.filename or found_info.name != expected_info.name:
fail()
for f_trace in expected_info.f_trace.split('|'):
if f_trace == found_info.f_trace:
break
else:
fail()
def thread_func():
check_frame_info([
FrameInfo(filename='_debugger_case_check_tracer.py', name='thread_func', f_trace='trace_exception'),
FrameInfo(filename='threading.py', name='run', f_trace='None'),
FrameInfo(filename='threading.py', name='_bootstrap_inner', f_trace='trace_unhandled_exceptions'),
FrameInfo(filename='threading.py', name='_bootstrap', f_trace='None'),
FrameInfo(filename='pydev_monkey.py', name='__call__', f_trace='None')
])
th = threading.Thread(target=thread_func)
th.daemon = True
th.start()
event = threading.Event()
def thread_func2():
try:
check_frame_info([
FrameInfo(filename='_debugger_case_check_tracer.py', name='thread_func2', f_trace='trace_exception'),
FrameInfo(filename='pydev_monkey.py', name='__call__', f_trace='trace_unhandled_exceptions')
])
finally:
event.set()
start_new_thread(thread_func2, ())
event.wait()
th.join()
# This is a bit tricky: although we waited on the event, there's a slight chance
# that we didn't get the notification because the thread could've stopped executing,
# so, sleep a bit so that the test does not become flaky.
import time
time.sleep(.3)
check_frame_info([
FrameInfo(filename='_debugger_case_check_tracer.py', name='<module>', f_trace='trace_exception'),
FrameInfo(filename='pydevd_runpy.py', name='_run_code', f_trace='None'),
FrameInfo(filename='pydevd_runpy.py', name='_run_module_code', f_trace='None'),
FrameInfo(filename='pydevd_runpy.py', name='run_path', f_trace='None'),
FrameInfo(filename='pydevd.py', name='_exec', f_trace='trace_unhandled_exceptions'),
FrameInfo(filename='pydevd.py', name='run', f_trace='trace_dispatch|None'),
FrameInfo(filename='pydevd.py', name='main', f_trace='trace_dispatch|None'),
FrameInfo(filename='pydevd.py', name='<module>', f_trace='trace_dispatch|None')
])
print('TEST SUCEEDED')
@@ -0,0 +1,23 @@
def method1():
yield
print('here') # Break here
if __name__ == '__main__':
# i.e.: make sure we create 2 frames with different frameIds.
it1 = iter(method1())
it2 = iter(method1())
next(it1) # resume first
next(it2) # resume second
try:
next(it1) # finish first
except StopIteration:
pass
try:
next(it2) # finish second
except StopIteration:
pass
print('TEST SUCEEDED')
@@ -0,0 +1,23 @@
import sys
from _pydevd_bundle.pydevd_custom_frames import add_custom_frame
import threading
def call1():
add_custom_frame(sys._getframe(), 'call1', threading.current_thread().ident)
def call2():
add_custom_frame(sys._getframe(), 'call2', threading.current_thread().ident)
def call3():
add_custom_frame(sys._getframe(), 'call3', threading.current_thread().ident)
if __name__ == '__main__':
call1() # break here
call2()
call3()
print('TEST SUCEEDED')
@@ -0,0 +1,14 @@
import pydevd
from _pydevd_bundle._debug_adapter import pydevd_schema
body = pydevd_schema.OutputEventBody('some output', 'my_category')
event = pydevd_schema.OutputEvent(body)
pydevd.send_json_message(event)
pydevd.send_json_message({
"type": "event",
"event": "output",
"body": {"output": "some output 2", "category": "my_category2"}
})
print('TEST SUCEEDED')
@@ -0,0 +1,72 @@
'''
The idea here is that a secondary thread does the processing of instructions,
so, when all threads are stopped, doing an evaluation for:
processor.process('xxx')
would be locked until secondary threads start running.
See: https://github.com/microsoft/debugpy/issues/157
'''
import threading
try:
from queue import Queue
except:
from Queue import Queue
class EchoThread(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self._queue = queue
self.started = threading.Event()
def run(self):
self.started.set()
while True:
obj = self._queue.get()
if obj == 'finish':
break
print('processed', obj.value)
obj.event.set() # Break here 2
class NotificationObject(object):
def __init__(self, value):
self.value = value
self.event = threading.Event()
class Processor(object):
def __init__(self, queue):
self._queue = queue
def process(self, i):
obj = NotificationObject(i)
self._queue.put(obj)
assert obj.event.wait()
def finish(self):
self._queue.put('finish')
def main():
queue = Queue()
echo_thread = EchoThread(queue)
processor = Processor(queue)
echo_thread.start()
echo_thread.started.wait()
processor.process(1) # Break here 1
processor.process(2)
processor.process(3)
processor.finish()
if __name__ == '__main__':
main()
print('TEST SUCEEDED!')
@@ -0,0 +1,11 @@
import pydevd
# Some hackery to get the PyDevJsonCommandProcessor which is not exposed.
try:
json_command_processor = pydevd.get_global_debugger().reader.process_net_command_json.__self__
except:
json_command_processor = pydevd.get_global_debugger().reader.process_net_command_json.im_self
print(json_command_processor._options.to_json())
print('TEST SUCEEDED!')
@@ -0,0 +1,16 @@
def method1(n):
if n <= 0:
return 0 # Break here
method2(n - 1)
def method2(n):
method1(n - 1)
if __name__ == '__main__':
try:
method1(100)
except:
pass # Don't let it print the exception (just deal with caught exceptions).
print('TEST SUCEEDED!')
@@ -0,0 +1,13 @@
class A():
def __init__(self):
self.var1 = 10
self.attr = {} # Break here
def __dir__(self):
return list(self.attr)
if __name__ == '__main__':
a = A()
print('TEST SUCEEDED!')
@@ -0,0 +1,3 @@
def call_me_back(callback):
if callable(callback):
callback()
@@ -0,0 +1,18 @@
import sys
import os
try:
from _debugger_case_dont_trace import call_me_back
except ImportError:
sys.path.append(os.path.dirname(__file__))
from _debugger_case_dont_trace import call_me_back
def my_callback():
print('trace me') # Break here
if __name__ == '__main__':
call_me_back(my_callback)
call_me_back(my_callback)
print('TEST SUCEEDED!')
@@ -0,0 +1,8 @@
def Call():
var_1 = 5
var_all = 1 # Break here
if __name__ == '__main__':
Call()
print('TEST SUCEEDED!')
@@ -0,0 +1 @@
# File empty. Output is in the extension itself
@@ -0,0 +1,22 @@
import sys
def method3():
raise IndexError('foo') # raise indexerror line
def method2():
return method3() # reraise on method2
def method1():
try:
method2() # handle on method1
except:
pass # Ok, handled
assert '__exception__' not in sys._getframe().f_locals
if __name__ == '__main__':
method1()
print('TEST SUCEEDED!')
@@ -0,0 +1,70 @@
'''
Things this test checks:
- frame.f_trace is None when there are only regular breakpoints.
- The no-op tracing function is set by default (otherwise when set tracing functions have no effect).
- When stepping in, frame.f_trace must be set by the frame eval.
- When stepping over/return, the frame.f_trace must not be set on intermediate callers.
TODO:
- When frame.f_trace is set to the default tracing function, it'll become None again in frame
eval mode if not stepping (if breakpoints weren't changed).
- The tracing function in the frames that deal with unhandled exceptions must be set when dealing
with unhandled exceptions.
- The tracing function in the frames that deal with unhandled exceptions must NOT be set when
NOT dealing with unhandled exceptions.
- If handled exceptions should be dealt with, the proper tracing should be set in frame.f_trace.
'''
import sys
from _pydevd_frame_eval import pydevd_frame_tracing
def check_with_no_trace():
if False:
print('break on check_with_trace')
frame = sys._getframe()
if frame.f_trace is not None:
raise AssertionError('Expected %s to be None' % (frame.f_trace,))
if sys.gettrace() is not pydevd_frame_tracing.dummy_tracing_holder.dummy_trace_func:
raise AssertionError('Expected %s to be dummy_trace_func' % (sys.gettrace(),))
def check_step_in_then_step_return():
frame = sys._getframe()
f_trace = frame.f_trace
if f_trace.__class__.__name__ != 'SafeCallWrapper':
raise AssertionError('Expected %s to be SafeCallWrapper' % (f_trace.__class__.__name__,))
check_with_no_trace()
def check_revert_to_dummy():
check_with_no_trace()
if __name__ == '__main__':
# Check how frame eval works.
if sys.version_info[0:2] < (3, 6):
raise AssertionError('Only available for Python 3.6 onwards. Found: %s' % (sys.version_info[0:1],))
check_with_no_trace() # break on global (step over)
check_step_in_then_step_return()
import pydevd_tracing
import pydevd
# This is what a remote attach would do (should revert to the frame eval mode).
pydevd_tracing.SetTrace(pydevd.get_global_debugger().trace_dispatch)
check_revert_to_dummy()
print('TEST SUCEEDED!')
@@ -0,0 +1,18 @@
def generator2():
for i in range(5):
yield i
def generator():
print('start') # break here
yield from generator2() # step 1
print('end') # step 2
if __name__ == '__main__':
for i in generator(): # generator return
print(i)
print('TEST SUCEEDED!') # step 3
@@ -0,0 +1,17 @@
def get_return():
return 10
def generator():
print('start') # break here
yield 10 # step 1
return \
get_return() # step 2
if __name__ == '__main__':
for i in generator(): # generator return
print(i)
print('TEST SUCEEDED!') # step 3
@@ -0,0 +1,13 @@
def generator():
print('start') # break here
yield 10 # step 1
print('end') # step 2
if __name__ == '__main__':
for i in generator(): # generator return
print(i)
print('TEST SUCEEDED!') # step 3
@@ -0,0 +1,16 @@
def generator2():
for i in range(4):
yield i
def generator():
a = 42 # break here
for x in generator2():
yield x
sum = 0
for i in generator():
sum += i
print('TEST SUCEEDED!')
@@ -0,0 +1,14 @@
def generator2():
yield from range(4)
def generator():
a = 42 # break here
yield from generator2()
sum = 0
for i in generator():
sum += i
print('TEST SUCEEDED!')
@@ -0,0 +1,13 @@
def generator():
yield 1 # stop 1
yield 2 # stop 4
def main():
for i in generator(): # stop 3
print(i) # stop 2
if __name__ == '__main__':
main()
print('TEST SUCEEDED!')
@@ -0,0 +1,26 @@
def method():
a = 1
print('call %s' % (a,))
def method2():
print('call %s' % (a,))
while a < 10:
a += 1
print('call %s' % (a,))
try:
if a < 0:
print('call %s' % (a,))
raise ValueError
else:
method2()
except ValueError:
pass
print('call %s' % (a,))
if __name__ == '__main__':
method()
print('TEST SUCEEDED!')
@@ -0,0 +1,21 @@
import threading
event_set = False
inner_started = False
def method():
global inner_started
inner_started = True
while not event_set:
import time
time.sleep(.1)
t = threading.Thread(target=method)
t.start()
while not inner_started:
import time
time.sleep(.1)
print('break here')
event_set = True
t.join()
print('TEST SUCEEDED!')
@@ -0,0 +1,60 @@
#!/usr/bin/env python
from gevent import monkey, sleep, threading as gevent_threading
import sys
if 'remote' in sys.argv:
import pydevd
if '--use-dap-mode' in sys.argv:
pydevd.config('http_json', 'debugpy-dap')
port = int(sys.argv[1])
print('before pydevd.settrace')
pydevd.settrace(host=('' if 'as-server' in sys.argv else '127.0.0.1'), port=port, suspend=False)
print('after pydevd.settrace')
monkey.patch_all()
import threading
called = []
class MyGreenThread2(threading.Thread):
def run(self):
for _i in range(3):
sleep()
class MyGreenletThread(threading.Thread):
def run(self):
for _i in range(5):
called.append(self.name) # break here
t1 = MyGreenThread2()
t1.start()
sleep()
if __name__ == '__main__':
t1 = MyGreenletThread()
t1.name = 't1'
t2 = MyGreenletThread()
t2.name = 't2'
if hasattr(gevent_threading, 'Thread'):
# Only available in newer versions of gevent.
assert isinstance(t1, gevent_threading.Thread)
assert isinstance(t2, gevent_threading.Thread)
t1.start()
t2.start()
for t1 in (t1, t2):
t1.join()
# With gevent it's always the same (gevent coroutine support makes thread
# switching serial).
expected = ['t1', 't2', 't1', 't2', 't1', 't2', 't1', 't2', 't1', 't2']
if called != expected:
raise AssertionError("Expected:\n%s\nFound:\n%s" % (expected, called))
print('TEST SUCEEDED')
@@ -0,0 +1,21 @@
import gevent
def foo():
print('Running in foo')
gevent.sleep(0)
print('Explicit context switch to foo again')
def bar():
print('Explicit context to bar')
gevent.sleep(0) # break here
print('Implicit context switch back to bar')
if __name__ == '__main__':
gevent.joinall([
gevent.spawn(foo),
gevent.spawn(bar),
])
print('TEST SUCEEDED')
@@ -0,0 +1,16 @@
from gevent import monkey
monkey.patch_all()
import subprocess
import sys
import os
if __name__ == "__main__":
if '-foo' in sys.argv:
print('foo called')
else:
if os.environ.get('CALL_PYTHON_SUB') == '1':
assert 'foo called' in subprocess.check_output([sys.executable, __file__, '-foo']).decode('utf-8')
else:
subprocess.check_output("tput -T xterm-256color bold".split())
print('TEST SUCEEDED')
@@ -0,0 +1,12 @@
in_global_scope = 'in_global_scope_value'
class SomeClass(object):
def method(self):
print('breakpoint here')
if __name__ == '__main__':
SomeClass().method()
print('TEST SUCEEDED')
@@ -0,0 +1,26 @@
class LoopHolder:
@staticmethod
def gui_loop():
print('gui_loop() called')
def call_method():
from _pydevd_bundle.pydevd_constants import get_global_debugger
py_db = get_global_debugger()
# Check state prior to breaking
assert not py_db.gui_in_use
assert py_db._installed_gui_support
assert py_db._gui_event_loop == '__main__.LoopHolder.gui_loop'
print('break here')
assert py_db.gui_in_use
assert py_db._installed_gui_support
assert py_db._gui_event_loop == '__main__.LoopHolder.gui_loop'
if __name__ == '__main__':
call_method()
print('TEST SUCEEDED!')
@@ -0,0 +1,51 @@
def call_method():
from _pydevd_bundle.pydevd_constants import get_global_debugger
py_db = get_global_debugger()
# Check state prior to breaking
assert not py_db.gui_in_use
assert py_db._installed_gui_support
assert py_db._gui_event_loop == 'qt5'
import os
import PySide2
from PySide2.QtCore import QTimer
dirname = os.path.dirname(PySide2.__file__)
plugin_path = os.path.join(dirname, 'plugins', 'platforms')
if os.path.exists(plugin_path):
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
from PySide2 import QtWidgets
app = QtWidgets.QApplication([])
def on_timeout():
print('on_timeout() called')
print_timer = QTimer()
print_timer.timeout.connect(on_timeout)
print_timer.setInterval(100)
print_timer.start()
def on_break():
print('break here')
app.quit()
break_on_timer = QTimer()
break_on_timer.timeout.connect(on_break)
break_on_timer.setSingleShot(True)
break_on_timer.setInterval(50)
break_on_timer.start()
app.exec_() # Run forever until app.quit()
assert py_db.gui_in_use
assert py_db._installed_gui_support
assert py_db._gui_event_loop == 'qt5'
if __name__ == '__main__':
call_method()
print('TEST SUCEEDED!')
@@ -0,0 +1,10 @@
class MyClass(object):
def __getattribute__(self, attr):
raise RuntimeError()
obj = MyClass()
if __name__ == '__main__':
print('TEST SUCEEDED') # break here
@@ -0,0 +1,6 @@
if __name__ == '__main__':
x = 0 # before loop line
for i in range(10): # for line
print(i) # print line
print('TEST SUCEEDED!')
@@ -0,0 +1,25 @@
import sys
if __name__ == '__main__':
a = [1, 2, 3, 4]
b = [2, 7]
assert any(x in a for x in b)
def gen():
yield 1
for i in gen():
pass
def gen2():
yield 2
if sys.version_info[:2] < (3, 7):
# On Python 3.7 onwards this will generate an unhandled exception, which
# is not what we want.
raise StopIteration()
for i in gen2():
pass
print('TEST SUCEEDED!')
@@ -0,0 +1,2 @@
print('text 1')
print('text 2')
@@ -0,0 +1,3 @@
import _debugger_case_import_imported # break here
print('TEST SUCEEDED')
@@ -0,0 +1,8 @@
call = lambda b:(
b,
1, # Break here
)
call(1)
call(2)
print('TEST SUCEEDED')
@@ -0,0 +1,5 @@
call = lambda b:b # Break here will hit once at creation time and then at each call.
call(1)
call(2)
print('TEST SUCEEDED')
@@ -0,0 +1,16 @@
def method1(n):
if n <= 0:
raise IndexError('foo')
method2(n - 1)
def method2(n):
method1(n - 1)
if __name__ == '__main__':
try:
method1(100)
except:
pass # Don't let it print the exception (just deal with caught exceptions).
print('TEST SUCEEDED!')
@@ -0,0 +1,26 @@
import linecache
unique_filename = "<foo bar>"
def foo():
print("on foo") # breakpoint
script = """
def somemethod():
foo()
somemethod()
[x for x in range(10)]
"""
linecache.cache[unique_filename] = (
len(script),
None,
script.splitlines(True),
unique_filename,
)
obj = compile(script, unique_filename, "exec")
exec(obj)
print('TEST SUCEEDED')
@@ -0,0 +1,12 @@
import linecache
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
import _debugger_case_stepping
linecache.updatecache(_debugger_case_stepping.__file__)
assert linecache.getline(_debugger_case_stepping.__file__, 1)
_debugger_case_stepping.Call()
print('TEST SUCEEDED')
@@ -0,0 +1,59 @@
import time
def check_output_command(messages_sent):
for _i in range(50):
for msg in messages_sent:
if msg.get('type') == 'event' and msg.get('event') == 'output' and 'Something' in msg['body']['output']:
return True
time.sleep(.1)
return False
def check_continue_request(messages_received):
for _i in range(50):
for msg in messages_received:
if msg.get('type') == 'request' and msg.get('command') == 'continue':
return True
time.sleep(.1)
return False
def main():
'''
In this test we'll check that pydevd sends an output event and receives a continue request in
the dap messages listener.
'''
messages_sent = []
messages_received = []
import pydevd
class Listener(pydevd.IDAPMessagesListener):
def before_send(self, message_as_dict):
messages_sent.append(message_as_dict)
def after_receive(self, message_as_dict):
messages_received.append(message_as_dict)
pydevd.add_dap_messages_listener(Listener())
print('Something') # Break here
# Note that the message is only received in a thread, so, we have to
# wait for it to be received.
if not check_output_command(messages_sent):
print('Output not received!')
return False
if not check_continue_request(messages_received):
print('Continue not received!')
return False
print('TEST SUCEEDED!')
return True
if __name__ == '__main__':
assert main()
@@ -0,0 +1,14 @@
def Call():
variable_for_test_1 = 10 # Break here
variable_for_test_2 = 20
variable_for_test_3 = {'a':30, 'b':20}
locals()[u'\u16A0'] = u'\u16A1' # unicode variable (would be syntax error on py2).
all_vars_set = True # Break 2 here
if __name__ == '__main__':
Call()
print('TEST SUCEEDED!')
@@ -0,0 +1,12 @@
def Call():
variable_for_test_1 = ['a', 'b']
variable_for_test_2 = set(['a'])
all_vars_set = True # Break here
if __name__ == '__main__':
Call()
print('TEST SUCEEDED!')
@@ -0,0 +1,82 @@
class MyDictSubclass(dict):
def __init__(self):
dict.__init__(self)
self.var1 = 10
self['in_dct'] = 20
def __str__(self):
ret = []
for key, val in sorted(self.items()):
ret.append('%s: %s' % (key, val))
ret.append('self.var1: %s' % (self.var1,))
return '{' + '; '.join(ret) + '}'
__repr__ = __str__
class MyListSubclass(list):
def __init__(self):
list.__init__(self)
self.var1 = 11
self.append('a')
self.append('b')
def __str__(self):
ret = []
for obj in self:
ret.append(repr(obj))
ret.append('self.var1: %s' % (self.var1,))
return '[' + ', '.join(ret) + ']'
__repr__ = __str__
class MySetSubclass(set):
def __init__(self):
set.__init__(self)
self.var1 = 12
self.add('a')
def __str__(self):
ret = []
for obj in sorted(self):
ret.append(repr(obj))
ret.append('self.var1: %s' % (self.var1,))
return 'set([' + ', '.join(ret) + '])'
__repr__ = __str__
class MyTupleSubclass(tuple):
def __new__ (cls):
return super(MyTupleSubclass, cls).__new__(cls, tuple(['a', 1]))
def __init__(self):
self.var1 = 13
def __str__(self):
ret = []
for obj in self:
ret.append(repr(obj))
ret.append('self.var1: %s' % (self.var1,))
return 'tuple(' + ', '.join(ret) + ')'
__repr__ = __str__
def Call():
variable_for_test_1 = MyListSubclass()
variable_for_test_2 = MySetSubclass()
variable_for_test_3 = MyDictSubclass()
variable_for_test_4 = MyTupleSubclass()
all_vars_set = True # Break here
if __name__ == '__main__':
Call()
print('TEST SUCEEDED!')
@@ -0,0 +1,12 @@
def Call():
variables_for_test_1 = 100
variables_for_test_2 = [1, 10, 100]
variables_for_test_3 = {10: 10, 100: 100, 1000: 1000}
variables_for_test_4 = {(1, 10, 100): (10000, 100000, 100000)}
all_vars_set = True # Break here
if __name__ == '__main__':
Call()
print('TEST SUCEEDED!')
@@ -0,0 +1,63 @@
import subprocess
import sys
import json
from _pydev_bundle import pydev_log
import os
import io
def gen_debug_info():
from _pydevd_bundle.pydevd_constants import DebugInfoHolder
dct = {}
for name in (
'PYDEVD_DEBUG_FILE',
'DEBUG_TRACE_LEVEL',
):
dct[name] = getattr(DebugInfoHolder, name)
return dct
if __name__ == "__main__":
if '-print-debug' in sys.argv:
info = gen_debug_info() # break on 2nd process
pydev_log.info('Something in print-debug')
print('>>> print-debug pid: %s' % os.getpid())
print(json.dumps(info))
else:
# Note: when running tests we usually have logging setup,
# so, we create a context so that our changes are restored
# when it finishes (as the `log_to` function will just reset
# whatever is there).
s = io.StringIO()
with pydev_log.log_context(trace_level=3, stream=s):
target_log_file = os.getenv('TARGET_LOG_FILE')
pydev_log.log_to(target_log_file, 1)
new_debug_info = gen_debug_info()
subprocess_pid = None
with subprocess.Popen(
[sys.executable, __file__, '-print-debug'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
) as process:
subprocess_pid = process.pid
stdout, stderr = process.communicate(input)
output = stdout.decode('utf-8')
pydev_log.info('Something in initial')
log_contents = open(pydev_log._compute_filename_with_pid(target_log_file)).read()
assert 'Something in initial' in log_contents, 'Did not find "Something in initial" in %s' % (log_contents,)
log_contents = open(pydev_log._compute_filename_with_pid(target_log_file, pid=subprocess_pid)).read()
assert 'Something in print-debug' in log_contents, 'Did not find "Something in print-debug" in %s' % (log_contents,)
output = ''.join(output.splitlines(keepends=True)[1:]) # Remove the first line
loaded_debug_info = json.loads(output)
assert loaded_debug_info == new_debug_info, 'Expected %s. Found: %s' % (new_debug_info, loaded_debug_info)
print('>>> Initial pid: %s' % os.getpid())
print(output)
print('TEST SUCEEDED')
@@ -0,0 +1,3 @@
from . import _debugger_case_m_switch_2
print(_debugger_case_m_switch_2.ClassToBeImported)
print('TEST SUCEEDED!')
@@ -0,0 +1,2 @@
class ClassToBeImported(object):
pass
@@ -0,0 +1,23 @@
from concurrent.futures import ThreadPoolExecutor
import matplotlib
import matplotlib.pyplot as plt
processed = []
def double(nmbr):
doubled = nmbr * 2 # break here
processed.append(1)
return doubled
with ThreadPoolExecutor(max_workers=2) as pool:
futures = []
for number in range(3):
future = pool.submit(double, number)
futures.append(future)
pool.shutdown()
assert len(processed) == 3
print('TEST SUCEEDED!')
@@ -0,0 +1,5 @@
def call(b): return b # Break here will hit once at creation time and then at each call.
call(1)
call(2)
print('TEST SUCEEDED')
@@ -0,0 +1,17 @@
class MyVersion(object):
pass
class MyPackage(object):
pass
class MyName(object):
pass
__version__ = MyVersion()
__package__ = MyPackage()
__name__ = MyName()
print('TEST SUCEEDED') # Break here
@@ -0,0 +1,2 @@
def main():
print('TEST SUCEEDED!')
@@ -0,0 +1,55 @@
'''
After breaking on the thread 1, thread 2 should pause waiting for the event1 to be set,
so, when we step return on thread 1, the program should finish if all threads are resumed
or should keep waiting for the thread 2 to run if only thread 1 is resumed.
'''
import threading
event0 = threading.Event()
event1 = threading.Event()
event2 = threading.Event()
event3 = threading.Event()
def _thread1():
_event1_set = False
_event2_set = False
while not event0.is_set():
event0.wait(timeout=.001)
event1.set() # Break thread 1
_event1_set = True
while not event2.is_set():
event2.wait(timeout=.001)
_event2_set = True # Note: we can only get here if thread 2 is also released.
event3.set()
def _thread2():
event0.set()
while not event1.is_set():
event1.wait(timeout=.001)
event2.set()
while not event3.is_set():
event3.wait(timeout=.001)
if __name__ == '__main__':
threads = [
threading.Thread(target=_thread1, name='thread1'),
threading.Thread(target=_thread2, name='thread2'),
]
for t in threads:
t.start()
for t in threads:
t.join()
print('TEST SUCEEDED!')
@@ -0,0 +1,32 @@
import threading
class KeepInLoop(object):
keep_in_loop = True # Debugger should change to False to break.
def stop_loop():
KeepInLoop.keep_in_loop = False
return 'stopped_loop'
def double_number(number):
while KeepInLoop.keep_in_loop:
doubled = number * 2
print(doubled)
import time
time.sleep(.5)
return doubled
if __name__ == '__main__':
threads = []
for num in range(2):
thread = threading.Thread(target=double_number, args=(num,))
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
print('TEST SUCEEDED!')
@@ -0,0 +1,15 @@
import multiprocessing
import sys
def run(name):
print("argument: ", name) # break 1 here
if __name__ == '__main__':
if sys.version_info[0] >= 3 and sys.platform != 'win32':
multiprocessing.set_start_method('fork')
p = multiprocessing.Process(target=run, args=("argument to run method",))
p.start()
print('TEST SUCEEDED!') # break 2 here
p.join()
@@ -0,0 +1,20 @@
from multiprocessing import Process, Queue
class Foo:
def __init__(self, value):
self.value = value # break 2 here
def f(q):
q.put(Foo(1))
if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print(q.get().value) # break 1 here
print('TEST SUCEEDED!')
p.join()
@@ -0,0 +1,17 @@
from __future__ import print_function
from multiprocessing import Pool
from time import sleep
def call(arg):
if arg == '2':
print("called") # break 1 here
if __name__ == '__main__':
pool = Pool(1)
pool.map(call, ['1', '2', '3'])
pool.close()
pool.join()
sleep(1)
print('TEST SUCEEDED!') # break 2 here
@@ -0,0 +1,32 @@
import time
import multiprocessing
import threading
import sys
import os
event = threading.Event()
class MyThread(threading.Thread):
def run(self):
_a = 10
_b = 20 # break in thread here
event.set()
_c = 20
def run_in_multiprocess():
_a = 30
_b = 40 # break in process here
if __name__ == '__main__':
MyThread().start()
event.wait()
if sys.version_info[0] >= 3 and sys.platform != 'win32':
multiprocessing.set_start_method('fork')
p = multiprocessing.Process(target=run_in_multiprocess, args=())
p.start()
print('TEST SUCEEDED!') # break in main here
p.join()
@@ -0,0 +1,6 @@
from collections import namedtuple
MyTup = namedtuple('MyTup', 'a, b, c')
tup = MyTup(1, 2, 3) # break here
assert tup.a == 1
assert tup.b == 2
print('TEST SUCEEDED!')
@@ -0,0 +1,35 @@
import subprocess
import sys
import os
from contextlib import contextmanager
env = os.environ.copy()
pythonpath = env.get('PYTHONPATH', '')
env['PYTHONPATH'] = os.path.dirname(__file__)
def call():
print("called") # break 1 here
@contextmanager
def dummy_context_manager():
yield
if __name__ == '__main__':
if 'apply-multiprocessing-patch' in sys.argv:
context_manager = dummy_context_manager # It's applied by default.
else:
import pydevd
context_manager = pydevd.skip_subprocess_arg_patch
with context_manager():
p = subprocess.Popen(
[sys.executable, '-c', 'import _debugger_case_no_subprocess_patching;_debugger_case_no_subprocess_patching.call()'],
stdout=subprocess.PIPE,
env=env,
)
stdout, stderr = p.communicate()
assert b'called' in stdout, 'Did not find b"called" in: %s' % (stdout,)
print('TEST SUCEEDED!') # break 2 here
@@ -0,0 +1,14 @@
def check():
from collections import OrderedDict
import sys
# On 3.6 onwards, use a regular dict.
odict = OrderedDict() if sys.version_info[:2] < (3, 6) else {}
odict[4] = 'first'
odict[3] = 'second'
odict[2] = 'last'
print('break here')
if __name__ == '__main__':
check()
print('TEST SUCEEDED')
@@ -0,0 +1,14 @@
from tests_python.resource_path_translation import other
def call_this():
print('break here')
def main():
other.call_me_back1(call_this)
print('TEST SUCEEDED!')
if __name__ == '__main__':
main()
@@ -0,0 +1,13 @@
import time
def Call():
loop = True # Break here
count = 0
while(loop and (count < 200)):
time.sleep(0.1)
count += 1 # Pause here and change loop to False
if __name__ == '__main__':
Call()
print('TEST SUCEEDED!')
@@ -0,0 +1 @@
print('TEST SUCEEDED') # Break here should only hit once.
@@ -0,0 +1,62 @@
import sys
import os
def main():
env = os.environ.copy()
pythonpath = env.get('PYTHONPATH', '')
env['PYTHONPATH'] = os.path.dirname(__file__) + os.pathsep + \
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
import pydevd
if '--use-dap-mode' in sys.argv:
pydevd.config('http_json', 'debugpy-dap')
from _pydev_bundle import pydev_log
pydev_log.debug('Argv received: %s', sys.argv)
port = int(sys.argv[1])
print('before pydevd.settrace')
pydevd.settrace(port=port, patch_multiprocessing=True, suspend=True)
print('after pydevd.settrace')
import subprocess
if '--use-c-switch' in sys.argv:
child_process = subprocess.Popen(
[sys.executable, '-u', '-c', 'import _debugger_case_pydevd_customization;_debugger_case_pydevd_customization.call()'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env,
)
elif '--posix-spawn' in sys.argv:
env = os.environ.copy()
args = ['-u', '_debugger_case_pydevd_customization.py', '--simple-call']
pid = os.posix_spawn(sys.executable, args, env)
os.waitpid(pid, 0)
child_process = None # We don't really have a subprocess.Popen instance in this case.
else:
child_process = subprocess.Popen(
[sys.executable, '-u', '_debugger_case_pydevd_customization.py', '--simple-call'],
cwd=os.path.dirname(__file__),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env,
)
if child_process:
stdout, stderr = child_process.communicate()
assert b'called' in stdout, 'Did not find b"called" in stdout:\n>>%s<<\nstderr:\n>>%s<<\n' % (stdout, stderr)
print('TEST SUCEEDED!') # break 2 here
def call():
import pydevd
from _pydevd_bundle.pydevd_api import PyDevdAPI
assert pydevd.get_global_debugger().get_arg_ppid() == PyDevdAPI().get_ppid()
print("called") # break 1 here
if __name__ == '__main__':
if '--simple-call' in sys.argv:
call()
else:
main()
@@ -0,0 +1,21 @@
import subprocess
import sys
import os
env = os.environ.copy()
pythonpath = env.get('PYTHONPATH', '')
env['PYTHONPATH'] = os.path.dirname(__file__)
def call():
print("called") # break 1 here
if __name__ == '__main__':
p = subprocess.Popen(
[sys.executable, '-c', 'import _debugger_case_python_c;_debugger_case_python_c.call()'],
stdout=subprocess.PIPE,
env=env,
)
stdout, stderr = p.communicate()
assert b'called' in stdout, 'Did not find b"called" in: %s' % (stdout,)
print('TEST SUCEEDED!') # break 2 here
@@ -0,0 +1,31 @@
import time
import sys
try:
try:
from PySide import QtCore # @UnresolvedImport
except:
from PySide2 import QtCore # @UnresolvedImport
except:
try:
from PyQt4 import QtCore
except:
from PyQt5 import QtCore
# Subclassing QThread
# http://doc.qt.nokia.com/latest/qthread.html
class AThread(QtCore.QThread):
def run(self):
count = 0
while count < 5:
print("Increasing", count) # break here
sys.stdout.flush()
count += 1
app = QtCore.QCoreApplication([])
thread = AThread()
thread.finished.connect(app.exit)
thread.start()
app.exec_()
print('TEST SUCEEDED!')
@@ -0,0 +1,40 @@
import time
import sys
try:
try:
from PySide import QtCore # @UnresolvedImport
except:
from PySide2 import QtCore # @UnresolvedImport
except:
try:
from PyQt4 import QtCore
except:
from PyQt5 import QtCore
# Subclassing QObject and using moveToThread
# http://labs.qt.nokia.com/2007/07/05/qthreads-no-longer-abstract/
class SomeObject(QtCore.QObject):
try:
finished = QtCore.Signal() # @UndefinedVariable
except:
finished = QtCore.pyqtSignal() # @UndefinedVariable
def long_running(self):
count = 0
while count < 5:
print("Increasing") # break here
count += 1
self.finished.emit()
app = QtCore.QCoreApplication([])
objThread = QtCore.QThread()
obj = SomeObject()
obj.moveToThread(objThread)
obj.finished.connect(objThread.quit)
objThread.started.connect(obj.long_running)
objThread.finished.connect(app.exit)
objThread.start()
app.exec_()
print('TEST SUCEEDED!')
@@ -0,0 +1,35 @@
import time
import sys
try:
try:
from PySide import QtCore # @UnresolvedImport
except:
from PySide2 import QtCore # @UnresolvedImport
except:
try:
from PyQt4 import QtCore
except:
from PyQt5 import QtCore
# Using a QRunnable
# http://doc.qt.nokia.com/latest/qthreadpool.html
# Note that a QRunnable isn't a subclass of QObject and therefore does
# not provide signals and slots.
class Runnable(QtCore.QRunnable):
def run(self):
count = 0
app = QtCore.QCoreApplication.instance()
while count < 5:
print("Increasing") # break here
count += 1
app.quit()
app = QtCore.QCoreApplication([])
runnable = Runnable()
QtCore.QThreadPool.globalInstance().start(runnable)
app.exec_()
QtCore.QThreadPool.globalInstance().waitForDone()
print('TEST SUCEEDED!')

Some files were not shown because too many files have changed in this diff Show More