Skip to content

Commit 935c118

Browse files
fabiozint19h
authored andcommitted
Fix inconsistencies in handling files. Fixes microsoft/ptvsd#1636
1 parent 30931d5 commit 935c118

9 files changed

Lines changed: 134 additions & 10 deletions

File tree

src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_dont_trace_files.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@
88
LIB_FILE = 1
99
PYDEV_FILE = 2
1010

11+
DONT_TRACE_DIRS = {
12+
'_pydev_bundle': PYDEV_FILE,
13+
'_pydev_imps': PYDEV_FILE,
14+
'_pydev_runfiles': PYDEV_FILE,
15+
'_pydevd_bundle': PYDEV_FILE,
16+
'_pydevd_frame_eval': PYDEV_FILE,
17+
'pydev_ipython': PYDEV_FILE,
18+
'pydev_sitecustomize': PYDEV_FILE,
19+
'pydevd_attach_to_process': PYDEV_FILE,
20+
'pydevd_concurrency_analyser': PYDEV_FILE,
21+
'pydevd_plugins': PYDEV_FILE,
22+
'test_pydevd_reload': PYDEV_FILE,
23+
}
24+
1125
DONT_TRACE = {
1226
# commonly used things from the stdlib that we don't want to trace
1327
'Queue.py':LIB_FILE,
@@ -55,6 +69,14 @@
5569
'pydev_monkey_qt.py': PYDEV_FILE,
5670
'pydev_override.py': PYDEV_FILE,
5771
'pydev_run_in_console.py': PYDEV_FILE,
72+
'pydev_runfiles.py': PYDEV_FILE,
73+
'pydev_runfiles_coverage.py': PYDEV_FILE,
74+
'pydev_runfiles_nose.py': PYDEV_FILE,
75+
'pydev_runfiles_parallel.py': PYDEV_FILE,
76+
'pydev_runfiles_parallel_client.py': PYDEV_FILE,
77+
'pydev_runfiles_pytest2.py': PYDEV_FILE,
78+
'pydev_runfiles_unittest.py': PYDEV_FILE,
79+
'pydev_runfiles_xml_rpc.py': PYDEV_FILE,
5880
'pydev_umd.py': PYDEV_FILE,
5981
'pydev_versioncheck.py': PYDEV_FILE,
6082
'pydevconsole.py': PYDEV_FILE,

src/debugpy/_vendored/pydevd/build_tools/generate_code.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ def generate_dont_trace_files():
108108
LIB_FILE = 1
109109
PYDEV_FILE = 2
110110
111+
DONT_TRACE_DIRS = {
112+
%(pydev_dirs)s
113+
}
114+
111115
DONT_TRACE = {
112116
# commonly used things from the stdlib that we don't want to trace
113117
'Queue.py':LIB_FILE,
@@ -135,8 +139,13 @@ def generate_dont_trace_files():
135139
'''
136140

137141
pydev_files = []
142+
pydev_dirs = []
138143

139144
for root, dirs, files in os.walk(root_dir):
145+
for d in dirs:
146+
if 'pydev' in d:
147+
pydev_dirs.append(" '%s': PYDEV_FILE," % (d,))
148+
140149
for d in [
141150
'.git',
142151
'.settings',
@@ -154,7 +163,6 @@ def generate_dont_trace_files():
154163
'test_pydevd_reload',
155164
'third_party',
156165
'__pycache__',
157-
'_pydev_runfiles',
158166
'pydev_ipython',
159167
]:
160168
try:
@@ -176,7 +184,10 @@ def generate_dont_trace_files():
176184
):
177185
pydev_files.append(" '%s': PYDEV_FILE," % (f,))
178186

179-
contents = template % (dict(pydev_files='\n'.join(sorted(pydev_files))))
187+
contents = template % (dict(
188+
pydev_files='\n'.join(sorted(pydev_files)),
189+
pydev_dirs='\n'.join(sorted(pydev_dirs)),
190+
))
180191
assert 'pydevd.py' in contents
181192
assert 'pydevd_dont_trace.py' in contents
182193
with open(os.path.join(root_dir, '_pydevd_bundle', 'pydevd_dont_trace_files.py'), 'w') as stream:

src/debugpy/_vendored/pydevd/pydevd.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
ForkSafeLock)
4444
from _pydevd_bundle.pydevd_defaults import PydevdCustomization # Note: import alias used on pydev_monkey.
4545
from _pydevd_bundle.pydevd_custom_frames import CustomFramesContainer, custom_frames_container_init
46-
from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE, PYDEV_FILE, LIB_FILE
46+
from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE, PYDEV_FILE, LIB_FILE, DONT_TRACE_DIRS
4747
from _pydevd_bundle.pydevd_extension_api import DebuggerEventHandler
4848
from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, remove_exception_from_frame
4949
from _pydevd_bundle.pydevd_net_command_factory_xml import NetCommandFactory
@@ -605,6 +605,7 @@ def new_trace_dispatch(frame, event, arg):
605605
self.collect_return_info = collect_return_info
606606
self.get_exception_breakpoint = get_exception_breakpoint
607607
self._dont_trace_get_file_type = DONT_TRACE.get
608+
self._dont_trace_dirs_get_file_type = DONT_TRACE_DIRS.get
608609
self.PYDEV_FILE = PYDEV_FILE
609610
self.LIB_FILE = LIB_FILE
610611

@@ -750,7 +751,25 @@ def _internal_get_file_type(self, abs_real_path_and_basename):
750751
if abs_real_path_and_basename[0].startswith(('<builtin', '<attrs')):
751752
# In PyPy "<builtin> ..." can appear and should be ignored for the user.
752753
return self.PYDEV_FILE
753-
return self._dont_trace_get_file_type(basename)
754+
file_type = self._dont_trace_get_file_type(basename)
755+
if file_type is not None:
756+
return file_type
757+
758+
if basename.startswith('__init__.py'):
759+
# i.e.: ignore the __init__ files inside pydevd (the other
760+
# files are ignored just by their name).
761+
abs_path = abs_real_path_and_basename[0]
762+
i = max(abs_path.rfind('/'), abs_path.rfind('\\'))
763+
if i:
764+
abs_path = abs_path[0:i]
765+
i = max(abs_path.rfind('/'), abs_path.rfind('\\'))
766+
if i:
767+
dirname = abs_path[i + 1:]
768+
# At this point, something as:
769+
# "my_path\_pydev_runfiles\__init__.py"
770+
# is now "_pydev_runfiles".
771+
return self._dont_trace_dirs_get_file_type(dirname)
772+
return None
754773

755774
def dont_trace_external_files(self, abs_path):
756775
'''
@@ -837,6 +856,7 @@ def get_file_type(self, frame, abs_real_path_and_basename=None, _cache_file_type
837856
if file_type is None:
838857
if self.dont_trace_external_files(abs_real_path_and_basename[0]):
839858
file_type = PYDEV_FILE
859+
840860
_cache_file_type[cache_key] = file_type
841861
return file_type
842862

src/debugpy/_vendored/pydevd/pydevd_file_utils.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -747,10 +747,15 @@ def _norm_file_to_client(filename, cache=norm_filename_to_client_container):
747747

748748
# For given file f returns tuple of its absolute path, real path and base name
749749
def get_abs_path_real_path_and_base_from_file(
750-
f, NORM_PATHS_AND_BASE_CONTAINER=NORM_PATHS_AND_BASE_CONTAINER):
750+
filename, NORM_PATHS_AND_BASE_CONTAINER=NORM_PATHS_AND_BASE_CONTAINER):
751751
try:
752-
return NORM_PATHS_AND_BASE_CONTAINER[f]
752+
return NORM_PATHS_AND_BASE_CONTAINER[filename]
753753
except:
754+
f = filename
755+
if not f:
756+
# i.e.: it's possible that the user compiled code with an empty string (consider
757+
# it as <string> in this case).
758+
f = '<string>'
754759
if _NormPaths is None: # Interpreter shutdown
755760
i = max(f.rfind('/'), f.rfind('\\'))
756761
return (f, f, f[i + 1:])
@@ -770,7 +775,7 @@ def get_abs_path_real_path_and_base_from_file(
770775
i = max(f.rfind('/'), f.rfind('\\'))
771776
base = f[i + 1:]
772777
ret = abs_path, real_path, base
773-
NORM_PATHS_AND_BASE_CONTAINER[f] = ret
778+
NORM_PATHS_AND_BASE_CONTAINER[filename] = ret
774779
return ret
775780

776781

@@ -784,8 +789,14 @@ def get_abs_path_real_path_and_base_from_frame(frame):
784789
# files from eggs in Python 2.7 have paths like build/bdist.linux-x86_64/egg/<path-inside-egg>
785790
f = frame.f_globals['__file__']
786791

787-
if get_abs_path_real_path_and_base_from_file is None: # Interpreter shutdown
788-
return f
792+
if get_abs_path_real_path_and_base_from_file is None:
793+
# Interpreter shutdown
794+
if not f:
795+
# i.e.: it's possible that the user compiled code with an empty string (consider
796+
# it as <string> in this case).
797+
f = '<string>'
798+
i = max(f.rfind('/'), f.rfind('\\'))
799+
return f, f, f[i + 1:]
789800

790801
ret = get_abs_path_real_path_and_base_from_file(f)
791802
# Also cache based on the frame.f_code.co_filename (if we had it inside build/bdist it can make a difference).
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
print('my code on entry')

src/debugpy/_vendored/pydevd/tests_python/resources/not_my_code/empty_file.py

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
if __name__ == '__main__':
2+
import sys
3+
import os
4+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
5+
6+
from my_code import my_code_on_entry
7+
print('TEST SUCEEDED')
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
if __name__ == '__main__':
2+
import sys
3+
import os
4+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
5+
6+
import empty_file
7+
print('TEST SUCEEDED')

src/debugpy/_vendored/pydevd/tests_python/test_debugger_json.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ def wait_for_thread_stopped(self, reason='breakpoint', line=None, file=None, nam
134134
if isinstance(path, bytes):
135135
path = path.decode('utf-8')
136136

137-
assert path.endswith(file)
137+
if not path.endswith(file):
138+
raise AssertionError('Expected path: %s to end with: %s' % (path, file))
138139
if name is not None:
139140
assert json_hit.stack_trace_response.body.stackFrames[0]['name'] == name
140141
if line is not None:
@@ -3758,6 +3759,50 @@ def update_command_line_args(self, args):
37583759
writer.finished_ok = True
37593760

37603761

3762+
def test_stop_on_entry(case_setup):
3763+
with case_setup.test_file('not_my_code/main_on_entry.py') as writer:
3764+
json_facade = JsonFacade(writer)
3765+
json_facade.write_launch(
3766+
justMyCode=False,
3767+
stopOnEntry=True,
3768+
rules=[
3769+
{'path': '**/not_my_code/**', 'include':False},
3770+
]
3771+
)
3772+
3773+
json_facade.write_make_initial_run()
3774+
json_facade.wait_for_thread_stopped(
3775+
'entry',
3776+
file=(
3777+
# We need to match the end with the proper slash.
3778+
'my_code/__init__.py',
3779+
'my_code\\__init__.py'
3780+
)
3781+
)
3782+
json_facade.write_continue()
3783+
writer.finished_ok = True
3784+
3785+
3786+
def test_stop_on_entry2(case_setup):
3787+
with case_setup.test_file('not_my_code/main_on_entry2.py') as writer:
3788+
json_facade = JsonFacade(writer)
3789+
json_facade.write_launch(
3790+
justMyCode=False,
3791+
stopOnEntry=True,
3792+
rules=[
3793+
{'path': '**/main_on_entry2.py', 'include':False},
3794+
]
3795+
)
3796+
3797+
json_facade.write_make_initial_run()
3798+
json_facade.wait_for_thread_stopped(
3799+
'entry',
3800+
file='empty_file.py'
3801+
)
3802+
json_facade.write_continue()
3803+
writer.finished_ok = True
3804+
3805+
37613806
@pytest.mark.parametrize('val', [True, False])
37623807
def test_debug_options(case_setup, val):
37633808
with case_setup.test_file('_debugger_case_debug_options.py') as writer:

0 commit comments

Comments
 (0)