mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Updates from PyDev: workaround for debugger on IronPython
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import sys
|
||||
from _pydevd_bundle.pydevd_constants import STATE_RUN, PYTHON_SUSPEND, IS_JYTHON
|
||||
from _pydevd_bundle.pydevd_constants import STATE_RUN, PYTHON_SUSPEND, IS_JYTHON, IS_IRONPYTHON
|
||||
# IFDEF CYTHON
|
||||
# ELSE
|
||||
from _pydevd_bundle.pydevd_frame import PyDBFrame
|
||||
@@ -37,6 +37,14 @@ if not hasattr(sys, '_current_frames'):
|
||||
|
||||
ret[thread.getId()] = frame
|
||||
return ret
|
||||
|
||||
if IS_IRONPYTHON:
|
||||
_tid_to_last_frame = {}
|
||||
|
||||
# IronPython doesn't have it. Let's use our workaround...
|
||||
def _current_frames():
|
||||
return _tid_to_last_frame
|
||||
|
||||
else:
|
||||
raise RuntimeError('Unable to proceed (sys._current_frames not available in this Python implementation).')
|
||||
else:
|
||||
@@ -110,14 +118,6 @@ class PyDBAdditionalThreadInfo(object):
|
||||
return [v]
|
||||
return []
|
||||
|
||||
# IFDEF CYTHON
|
||||
# def create_db_frame(self, *args, **kwargs):
|
||||
# raise AssertionError('This method should not be called on cython (PyDbFrame should be used directly).')
|
||||
# ELSE
|
||||
# just create the db frame directly
|
||||
create_db_frame = PyDBFrame
|
||||
# ENDIF
|
||||
|
||||
def __str__(self):
|
||||
return 'State:%s Stop:%s Cmd: %s Kill:%s' % (
|
||||
self.pydev_state, self.pydev_step_stop, self.pydev_step_cmd, self.pydev_notify_kill)
|
||||
|
||||
@@ -38,6 +38,7 @@ import os
|
||||
from _pydevd_bundle import pydevd_vm_type
|
||||
|
||||
IS_JYTHON = pydevd_vm_type.get_vm_type() == pydevd_vm_type.PydevdVmType.JYTHON
|
||||
IS_IRONPYTHON = sys.platform == 'cli'
|
||||
|
||||
IS_JYTH_LESS25 = False
|
||||
if IS_JYTHON:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# DO NOT edit manually!
|
||||
# DO NOT edit manually!
|
||||
import sys
|
||||
from _pydevd_bundle.pydevd_constants import STATE_RUN, PYTHON_SUSPEND, IS_JYTHON
|
||||
from _pydevd_bundle.pydevd_constants import STATE_RUN, PYTHON_SUSPEND, IS_JYTHON, IS_IRONPYTHON
|
||||
# IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated)
|
||||
# ELSE
|
||||
# from _pydevd_bundle.pydevd_frame import PyDBFrame
|
||||
@@ -41,6 +41,14 @@ if not hasattr(sys, '_current_frames'):
|
||||
|
||||
ret[thread.getId()] = frame
|
||||
return ret
|
||||
|
||||
if IS_IRONPYTHON:
|
||||
_tid_to_last_frame = {}
|
||||
|
||||
# IronPython doesn't have it. Let's use our workaround...
|
||||
def _current_frames():
|
||||
return _tid_to_last_frame
|
||||
|
||||
else:
|
||||
raise RuntimeError('Unable to proceed (sys._current_frames not available in this Python implementation).')
|
||||
else:
|
||||
@@ -114,14 +122,6 @@ cdef class PyDBAdditionalThreadInfo:
|
||||
return [v]
|
||||
return []
|
||||
|
||||
# IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated)
|
||||
def create_db_frame(self, *args, **kwargs):
|
||||
raise AssertionError('This method should not be called on cython (PyDbFrame should be used directly).')
|
||||
# ELSE
|
||||
# # just create the db frame directly
|
||||
# create_db_frame = PyDBFrame
|
||||
# ENDIF
|
||||
|
||||
def __str__(self):
|
||||
return 'State:%s Stop:%s Cmd: %s Kill:%s' % (
|
||||
self.pydev_state, self.pydev_step_stop, self.pydev_step_cmd, self.pydev_notify_kill)
|
||||
@@ -898,7 +898,7 @@ import traceback
|
||||
|
||||
from _pydev_bundle.pydev_is_thread_alive import is_thread_alive
|
||||
from _pydev_imps._pydev_saved_modules import threading
|
||||
from _pydevd_bundle.pydevd_constants import get_thread_id
|
||||
from _pydevd_bundle.pydevd_constants import get_thread_id, IS_IRONPYTHON
|
||||
from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE
|
||||
from _pydevd_bundle.pydevd_kill_all_pydevd_threads import kill_all_pydev_threads
|
||||
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame, NORM_PATHS_AND_BASE_CONTAINER
|
||||
@@ -1093,3 +1093,23 @@ cdef class ThreadTracer:
|
||||
# (https://github.com/fabioz/PyDev.Debugger/issues/8)
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
if IS_IRONPYTHON:
|
||||
# This is far from ideal, as we'll leak frames (we'll always have the last created frame, not really
|
||||
# the last topmost frame saved -- this should be Ok for our usage, but it may leak frames and things
|
||||
# may live longer... as IronPython is garbage-collected, things should live longer anyways, so, it
|
||||
# shouldn't be an issue as big as it's in CPython -- it may still be annoying, but this should
|
||||
# be a reasonable workaround until IronPython itself is able to provide that functionality).
|
||||
#
|
||||
# See: https://github.com/IronLanguages/main/issues/1630
|
||||
from _pydevd_bundle.pydevd_additional_thread_info_regular import _tid_to_last_frame
|
||||
|
||||
_original_call = ThreadTracer.__call__
|
||||
|
||||
def __call__(self, frame, event, arg):
|
||||
_tid_to_last_frame[self._args[1].ident] = frame
|
||||
return _original_call(self, frame, event, arg)
|
||||
|
||||
ThreadTracer.__call__ = __call__
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import traceback
|
||||
|
||||
from _pydev_bundle.pydev_is_thread_alive import is_thread_alive
|
||||
from _pydev_imps._pydev_saved_modules import threading
|
||||
from _pydevd_bundle.pydevd_constants import get_thread_id
|
||||
from _pydevd_bundle.pydevd_constants import get_thread_id, IS_IRONPYTHON
|
||||
from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE
|
||||
from _pydevd_bundle.pydevd_kill_all_pydevd_threads import kill_all_pydev_threads
|
||||
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame, NORM_PATHS_AND_BASE_CONTAINER
|
||||
@@ -14,8 +14,15 @@ from _pydevd_bundle.pydevd_tracing import SetTrace
|
||||
# ELSE
|
||||
from _pydevd_bundle.pydevd_additional_thread_info import PyDBAdditionalThreadInfo
|
||||
from _pydevd_bundle.pydevd_frame import PyDBFrame
|
||||
|
||||
# ENDIF
|
||||
|
||||
try:
|
||||
from _pydevd_bundle.pydevd_signature import send_signature_call_trace
|
||||
except ImportError:
|
||||
def send_signature_call_trace(*args, **kwargs):
|
||||
pass
|
||||
|
||||
threadingCurrentThread = threading.currentThread
|
||||
get_file_type = DONT_TRACE.get
|
||||
|
||||
@@ -33,6 +40,7 @@ get_file_type = DONT_TRACE.get
|
||||
global_cache_skips = {}
|
||||
global_cache_frame_skips = {}
|
||||
|
||||
|
||||
def trace_dispatch(py_db, frame, event, arg):
|
||||
t = threadingCurrentThread()
|
||||
|
||||
@@ -47,13 +55,14 @@ def trace_dispatch(py_db, frame, event, arg):
|
||||
additional_info = t.additional_info = PyDBAdditionalThreadInfo()
|
||||
|
||||
thread_tracer = ThreadTracer((py_db, t, additional_info, global_cache_skips, global_cache_frame_skips))
|
||||
# IFDEF CYTHON
|
||||
# t._tracer = thread_tracer # Hack for cython to keep it alive while the thread is alive (just the method in the SetTrace is not enough).
|
||||
# ELSE
|
||||
# ENDIF
|
||||
# IFDEF CYTHON
|
||||
# t._tracer = thread_tracer # Hack for cython to keep it alive while the thread is alive (just the method in the SetTrace is not enough).
|
||||
# ELSE
|
||||
# ENDIF
|
||||
SetTrace(thread_tracer.__call__)
|
||||
return thread_tracer.__call__(frame, event, arg)
|
||||
|
||||
|
||||
# IFDEF CYTHON
|
||||
# cdef class SafeCallWrapper:
|
||||
# cdef method_object
|
||||
@@ -75,8 +84,8 @@ def trace_dispatch(py_db, frame, event, arg):
|
||||
class ThreadTracer:
|
||||
def __init__(self, args):
|
||||
self._args = args
|
||||
# ENDIF
|
||||
|
||||
# ENDIF
|
||||
|
||||
def __call__(self, frame, event, arg):
|
||||
''' This is the callback used when we enter some context in the debugger.
|
||||
@@ -109,7 +118,7 @@ class ThreadTracer:
|
||||
try:
|
||||
if py_db._finish_debugging_session:
|
||||
if not py_db._termination_event_set:
|
||||
#that was not working very well because jython gave some socket errors
|
||||
# that was not working very well because jython gave some socket errors
|
||||
try:
|
||||
if py_db.output_checker is None:
|
||||
kill_all_pydev_threads()
|
||||
@@ -143,10 +152,11 @@ class ThreadTracer:
|
||||
# print('skipped: trace_dispatch (cache hit)', cache_key, frame.f_lineno, event, frame.f_code.co_name)
|
||||
return None
|
||||
|
||||
file_type = get_file_type(abs_path_real_path_and_base[-1]) #we don't want to debug threading or anything related to pydevd
|
||||
file_type = get_file_type(
|
||||
abs_path_real_path_and_base[-1]) # we don't want to debug threading or anything related to pydevd
|
||||
|
||||
if file_type is not None:
|
||||
if file_type == 1: # inlining LIB_FILE = 1
|
||||
if file_type == 1: # inlining LIB_FILE = 1
|
||||
if py_db.not_in_scope(filename):
|
||||
# print('skipped: trace_dispatch (not in scope)', abs_path_real_path_and_base[-1], frame.f_lineno, event, frame.f_code.co_name, file_type)
|
||||
cache_skips[cache_key] = 1
|
||||
@@ -166,11 +176,13 @@ class ThreadTracer:
|
||||
|
||||
# print('trace_dispatch', base, frame.f_lineno, event, frame.f_code.co_name, file_type)
|
||||
if additional_info.is_tracing:
|
||||
return None #we don't wan't to trace code invoked from pydevd_frame.trace_dispatch
|
||||
return None # we don't wan't to trace code invoked from pydevd_frame.trace_dispatch
|
||||
|
||||
# Just create PyDBFrame directly (removed support for Python versions < 2.5, which required keeping a weak
|
||||
# reference to the frame).
|
||||
ret = PyDBFrame((py_db, filename, additional_info, t, frame_skips_cache, (frame.f_code.co_name, frame.f_code.co_firstlineno, filename))).trace_dispatch(frame, event, arg)
|
||||
ret = PyDBFrame((py_db, filename, additional_info, t, frame_skips_cache,
|
||||
(frame.f_code.co_name, frame.f_code.co_firstlineno, filename))).trace_dispatch(frame,
|
||||
event, arg)
|
||||
if ret is None:
|
||||
cache_skips[cache_key] = 1
|
||||
return None
|
||||
@@ -186,7 +198,7 @@ class ThreadTracer:
|
||||
|
||||
except Exception:
|
||||
if py_db._finish_debugging_session:
|
||||
return None # Don't log errors when we're shutting down.
|
||||
return None # Don't log errors when we're shutting down.
|
||||
# Log it
|
||||
try:
|
||||
if traceback is not None:
|
||||
@@ -197,3 +209,25 @@ class ThreadTracer:
|
||||
# (https://github.com/fabioz/PyDev.Debugger/issues/8)
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
if IS_IRONPYTHON:
|
||||
# This is far from ideal, as we'll leak frames (we'll always have the last created frame, not really
|
||||
# the last topmost frame saved -- this should be Ok for our usage, but it may leak frames and things
|
||||
# may live longer... as IronPython is garbage-collected, things should live longer anyways, so, it
|
||||
# shouldn't be an issue as big as it's in CPython -- it may still be annoying, but this should
|
||||
# be a reasonable workaround until IronPython itself is able to provide that functionality).
|
||||
#
|
||||
# See: https://github.com/IronLanguages/main/issues/1630
|
||||
from _pydevd_bundle.pydevd_additional_thread_info_regular import _tid_to_last_frame
|
||||
|
||||
_original_call = ThreadTracer.__call__
|
||||
|
||||
|
||||
def __call__(self, frame, event, arg):
|
||||
_tid_to_last_frame[self._args[1].ident] = frame
|
||||
return _original_call(self, frame, event, arg)
|
||||
|
||||
|
||||
ThreadTracer.__call__ = __call__
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ class C:
|
||||
return 'unchanged'
|
||||
"""
|
||||
|
||||
IS_JYTHON = sys.platform.find('java') != -1
|
||||
from _pydevd_bundle.pydevd_constants import IS_JYTHON, IS_IRONPYTHON
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON, reason='CPython related test')
|
||||
@pytest.mark.skipif(IS_JYTHON or IS_IRONPYTHON, reason='CPython related test')
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import sys
|
||||
import unittest
|
||||
|
||||
from _pydevd_bundle.pydevd_save_locals import save_locals
|
||||
from _pydevd_bundle.pydevd_constants import IS_JYTHON
|
||||
from _pydevd_bundle.pydevd_constants import IS_JYTHON, IS_IRONPYTHON
|
||||
import pytest
|
||||
|
||||
|
||||
@@ -31,18 +31,17 @@ def check_method(fn):
|
||||
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON or IS_IRONPYTHON, reason='CPython/pypy only')
|
||||
class TestSetLocals(unittest.TestCase):
|
||||
"""
|
||||
Test setting locals in one function from another function using several approaches.
|
||||
"""
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON, reason='CPython/pypy only')
|
||||
def test_set_locals_using_save_locals(self):
|
||||
x = check_method(use_save_locals)
|
||||
self.assertEqual(x, 2) # Expected to succeed
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON, reason='CPython/pypy only')
|
||||
def test_frame_simple_change(self):
|
||||
frame = sys._getframe()
|
||||
a = 20
|
||||
@@ -51,7 +50,6 @@ class TestSetLocals(unittest.TestCase):
|
||||
self.assertEquals(50, a)
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON, reason='CPython/pypy only')
|
||||
def test_frame_co_freevars(self):
|
||||
|
||||
outer_var = 20
|
||||
@@ -64,7 +62,6 @@ class TestSetLocals(unittest.TestCase):
|
||||
|
||||
func()
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON, reason='CPython/pypy only')
|
||||
def test_frame_co_cellvars(self):
|
||||
|
||||
def check_co_vars(a):
|
||||
@@ -81,7 +78,6 @@ class TestSetLocals(unittest.TestCase):
|
||||
check_co_vars(1)
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON, reason='CPython/pypy only')
|
||||
def test_frame_change_in_inner_frame(self):
|
||||
def change(f):
|
||||
self.assert_(f is not sys._getframe())
|
||||
|
||||
Reference in New Issue
Block a user