Provide pydevd.log_to() to change the file to log to. WIP #1030

This commit is contained in:
Fabio Zadrozny 2022-08-26 16:29:47 -03:00
parent ea423ae598
commit 3272dace18
15 changed files with 309 additions and 101 deletions

View file

@ -1,4 +1,5 @@
from _pydevd_bundle.pydevd_constants import DebugInfoHolder, SHOW_COMPILE_CYTHON_COMMAND_LINE, NULL, LOG_TIME
from _pydevd_bundle.pydevd_constants import DebugInfoHolder, SHOW_COMPILE_CYTHON_COMMAND_LINE, NULL, LOG_TIME, \
ForkSafeLock
from contextlib import contextmanager
import traceback
import os
@ -6,18 +7,19 @@ import sys
class _LoggingGlobals(object):
_warn_once_map = {}
_debug_stream_filename = None
_debug_stream = sys.stderr
_debug_stream = NULL
_debug_stream_initialized = False
_initialize_lock = ForkSafeLock()
def initialize_debug_stream(reinitialize=False):
'''
:param bool reinitialize:
Reinitialize is used to update the debug stream after a fork (thus, if it wasn't
initialized, we don't need to do anything).
initialized, we don't need to do anything, just wait for the first regular log call
to initialize).
'''
if reinitialize:
if not _LoggingGlobals._debug_stream_initialized:
@ -26,32 +28,69 @@ def initialize_debug_stream(reinitialize=False):
if _LoggingGlobals._debug_stream_initialized:
return
_LoggingGlobals._debug_stream_initialized = True
with _LoggingGlobals._initialize_lock:
# Initialization is done lazilly, so, it's possible that multiple threads try to initialize
# logging.
# Note: we cannot initialize with sys.stderr because when forking we may end up logging things in 'os' calls.
_LoggingGlobals._debug_stream = NULL
_LoggingGlobals._debug_stream_filename = None
# Check initial conditions again after obtaining the lock.
if reinitialize:
if not _LoggingGlobals._debug_stream_initialized:
return
else:
if _LoggingGlobals._debug_stream_initialized:
return
if not DebugInfoHolder.PYDEVD_DEBUG_FILE:
_LoggingGlobals._debug_stream = sys.stderr
else:
# Add pid to the filename.
try:
dirname = os.path.dirname(DebugInfoHolder.PYDEVD_DEBUG_FILE)
basename = os.path.basename(DebugInfoHolder.PYDEVD_DEBUG_FILE)
try:
os.makedirs(dirname)
except:
pass # Ignore error if it already exists.
_LoggingGlobals._debug_stream_initialized = True
name, ext = os.path.splitext(basename)
debug_file = os.path.join(dirname, name + '.' + str(os.getpid()) + ext)
_LoggingGlobals._debug_stream = open(debug_file, 'w')
_LoggingGlobals._debug_stream_filename = debug_file
except:
# Note: we cannot initialize with sys.stderr because when forking we may end up logging things in 'os' calls.
_LoggingGlobals._debug_stream = NULL
_LoggingGlobals._debug_stream_filename = None
if not DebugInfoHolder.PYDEVD_DEBUG_FILE:
_LoggingGlobals._debug_stream = sys.stderr
# Don't fail when trying to setup logging, just show the exception.
traceback.print_exc()
else:
# Add pid to the filename.
try:
target_file = DebugInfoHolder.PYDEVD_DEBUG_FILE
debug_file = _compute_filename_with_pid(target_file)
_LoggingGlobals._debug_stream = open(debug_file, 'w')
_LoggingGlobals._debug_stream_filename = debug_file
except Exception:
_LoggingGlobals._debug_stream = sys.stderr
# Don't fail when trying to setup logging, just show the exception.
traceback.print_exc()
def _compute_filename_with_pid(target_file, pid=None):
# Note: used in tests.
dirname = os.path.dirname(target_file)
basename = os.path.basename(target_file)
try:
os.makedirs(dirname)
except Exception:
pass # Ignore error if it already exists.
name, ext = os.path.splitext(basename)
if pid is None:
pid = os.getpid()
return os.path.join(dirname, '%s.%s%s' % (name, pid, ext))
def log_to(log_file:str, log_level:int=3) -> None:
with _LoggingGlobals._initialize_lock:
# Can be set directly.
DebugInfoHolder.DEBUG_TRACE_LEVEL = log_level
if DebugInfoHolder.PYDEVD_DEBUG_FILE != log_file:
# Note that we don't need to reset it unless it actually changed
# (would be the case where it's set as an env var in a new process
# and a subprocess initializes logging to the same value).
_LoggingGlobals._debug_stream = NULL
_LoggingGlobals._debug_stream_filename = None
DebugInfoHolder.PYDEVD_DEBUG_FILE = log_file
_LoggingGlobals._debug_stream_initialized = False
def list_log_files(pydevd_debug_file):
@ -71,28 +110,33 @@ def log_context(trace_level, stream):
'''
To be used to temporarily change the logging settings.
'''
original_trace_level = DebugInfoHolder.DEBUG_TRACE_LEVEL
original_debug_stream = _LoggingGlobals._debug_stream
original_pydevd_debug_file = DebugInfoHolder.PYDEVD_DEBUG_FILE
original_debug_stream_filename = _LoggingGlobals._debug_stream_filename
original_initialized = _LoggingGlobals._debug_stream_initialized
with _LoggingGlobals._initialize_lock:
original_trace_level = DebugInfoHolder.DEBUG_TRACE_LEVEL
original_debug_stream = _LoggingGlobals._debug_stream
original_pydevd_debug_file = DebugInfoHolder.PYDEVD_DEBUG_FILE
original_debug_stream_filename = _LoggingGlobals._debug_stream_filename
original_initialized = _LoggingGlobals._debug_stream_initialized
DebugInfoHolder.DEBUG_TRACE_LEVEL = trace_level
_LoggingGlobals._debug_stream = stream
_LoggingGlobals._debug_stream_initialized = True
DebugInfoHolder.DEBUG_TRACE_LEVEL = trace_level
_LoggingGlobals._debug_stream = stream
_LoggingGlobals._debug_stream_initialized = True
try:
yield
finally:
DebugInfoHolder.DEBUG_TRACE_LEVEL = original_trace_level
_LoggingGlobals._debug_stream = original_debug_stream
DebugInfoHolder.PYDEVD_DEBUG_FILE = original_pydevd_debug_file
_LoggingGlobals._debug_stream_filename = original_debug_stream_filename
_LoggingGlobals._debug_stream_initialized = original_initialized
with _LoggingGlobals._initialize_lock:
DebugInfoHolder.DEBUG_TRACE_LEVEL = original_trace_level
_LoggingGlobals._debug_stream = original_debug_stream
DebugInfoHolder.PYDEVD_DEBUG_FILE = original_pydevd_debug_file
_LoggingGlobals._debug_stream_filename = original_debug_stream_filename
_LoggingGlobals._debug_stream_initialized = original_initialized
import time
_last_log_time = time.time()
# Set to True to show pid in each logged message (usually the file has it, but sometimes it's handy).
_LOG_PID = False
def _pydevd_log(level, msg, *args):
'''
@ -120,6 +164,10 @@ def _pydevd_log(level, msg, *args):
msg = '%.2fs - %s\n' % (time_diff, msg,)
else:
msg = '%s\n' % (msg,)
if _LOG_PID:
msg = '<%s> - %s\n' % (os.getpid(), msg,)
try:
try:
initialize_debug_stream() # Do it as late as possible

View file

@ -4,7 +4,7 @@ import re
import sys
from _pydev_bundle._pydev_saved_modules import threading
from _pydevd_bundle.pydevd_constants import get_global_debugger, IS_WINDOWS, IS_JYTHON, get_current_thread_id, \
sorted_dict_repr, set_global_debugger
sorted_dict_repr, set_global_debugger, DebugInfoHolder
from _pydev_bundle import pydev_log
from contextlib import contextmanager
from _pydevd_bundle import pydevd_constants
@ -68,6 +68,13 @@ def _get_setup_updated_with_protocol_and_ppid(setup, is_exec=False):
else:
pydev_log.debug('Unexpected protocol: %s', protocol)
if DebugInfoHolder.PYDEVD_DEBUG_FILE:
setup['log-file'] = DebugInfoHolder.PYDEVD_DEBUG_FILE
if DebugInfoHolder.DEBUG_TRACE_LEVEL:
setup['log-level'] = DebugInfoHolder.DEBUG_TRACE_LEVEL
return setup

View file

@ -551,8 +551,7 @@ class PyDevdAPI(object):
if not supported_type:
raise NameError(breakpoint_type)
if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n', canonical_normalized_filename, line, func_name)
pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n', canonical_normalized_filename, line, func_name)
if canonical_normalized_filename in file_to_id_to_breakpoint:
id_to_pybreakpoint = file_to_id_to_breakpoint[canonical_normalized_filename]
@ -672,10 +671,10 @@ class PyDevdAPI(object):
else:
try:
id_to_pybreakpoint = file_to_id_to_breakpoint.get(canonical_normalized_filename, {})
if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1:
existing = id_to_pybreakpoint[breakpoint_id]
pydev_log.info('Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n' % (
canonical_normalized_filename, existing.line, existing.func_name.encode('utf-8'), breakpoint_id))
canonical_normalized_filename, existing.line, existing.func_name, breakpoint_id))
del id_to_pybreakpoint[breakpoint_id]
py_db.consolidate_breakpoints(canonical_normalized_filename, id_to_pybreakpoint, file_to_line_to_breakpoints)

View file

@ -274,13 +274,14 @@ class ReaderThread(PyDBDaemonThread):
if hasattr(line, 'decode'):
line = line.decode('utf-8')
if DebugInfoHolder.DEBUG_RECORD_SOCKET_READS:
pydev_log.critical(u'debugger: received >>%s<<\n' % (line,))
if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 3:
pydev_log.debug('debugger: received >>%s<<\n', line)
args = line.split(u'\t', 2)
args = line.split('\t', 2)
try:
cmd_id = int(args[0])
pydev_log.debug('Received command: %s %s\n' % (ID_TO_MEANING.get(str(cmd_id), '???'), line,))
if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 3:
pydev_log.debug('Received command: %s %s\n', ID_TO_MEANING.get(str(cmd_id), '???'), line)
self.process_command(cmd_id, int(args[1]), args[2])
except:
if sys is not None and pydev_log_exception is not None: # Could happen at interpreter shutdown
@ -1351,12 +1352,12 @@ def internal_get_completions(dbg, seq, thread_id, frame_id, act_tok, line=-1, co
try:
remove_path = None
try:
qualifier = u''
qualifier = ''
if column >= 0:
token_and_qualifier = extract_token_and_qualifier(act_tok, line, column)
act_tok = token_and_qualifier[0]
if act_tok:
act_tok += u'.'
act_tok += '.'
qualifier = token_and_qualifier[1]
frame = dbg.find_frame(thread_id, frame_id)

View file

@ -1,4 +1,5 @@
import os
import sys
class ArgHandlerWithParam:
@ -68,8 +69,11 @@ ACCEPTED_ARG_HANDLERS = [
ArgHandlerWithParam('access-token'),
ArgHandlerWithParam('client-access-token'),
# Logging
ArgHandlerWithParam('log-file'),
ArgHandlerWithParam('log-level', int, 0),
ArgHandlerBool('server'),
ArgHandlerBool('DEBUG_RECORD_SOCKET_READS'),
ArgHandlerBool('multiproc'), # Used by PyCharm (reuses connection: ssh tunneling)
ArgHandlerBool('multiprocess'), # Used by PyDev (creates new connection to ide)
ArgHandlerBool('save-signatures'),
@ -132,6 +136,8 @@ def process_command_line(argv):
setup['file'] = ''
setup['qt-support'] = ''
initial_argv = tuple(argv)
i = 0
del argv[0]
while i < len(argv):
@ -169,10 +175,9 @@ def process_command_line(argv):
i = len(argv) # pop out, file is our last argument
elif argv[i] == '--DEBUG':
from pydevd import set_debug
del argv[i]
set_debug(setup)
sys.stderr.write('pydevd: --DEBUG parameter deprecated. Use `--debug-level=3` instead.\n')
else:
raise ValueError("Unexpected option: " + argv[i])
raise ValueError("Unexpected option: %s when processing: %s" % (argv[i], initial_argv))
return setup

View file

@ -39,10 +39,6 @@ class DebugInfoHolder:
# General information
DEBUG_TRACE_LEVEL = 0 # 0 = critical, 1 = info, 2 = debug, 3 = verbose
# Flags to debug specific points of the code.
DEBUG_RECORD_SOCKET_READS = False
DEBUG_TRACE_BREAKPOINTS = -1
PYDEVD_DEBUG_FILE = None
@ -292,7 +288,6 @@ DEFAULT_VALUE = "__pydevd_value_async"
ASYNC_EVAL_TIMEOUT_SEC = 60
NEXT_VALUE_SEPARATOR = "__pydev_val__"
BUILTINS_MODULE_NAME = 'builtins'
SHOW_DEBUG_INFO_ENV = is_true_in_env(('PYCHARM_DEBUG', 'PYDEV_DEBUG', 'PYDEVD_DEBUG'))
# Pandas customization.
PANDAS_MAX_ROWS = as_int_in_env('PYDEVD_PANDAS_MAX_ROWS', 60)
@ -335,11 +330,11 @@ EXCEPTION_TYPE_UNHANDLED = 'UNHANDLED'
EXCEPTION_TYPE_USER_UNHANDLED = 'USER_UNHANDLED'
EXCEPTION_TYPE_HANDLED = 'HANDLED'
SHOW_DEBUG_INFO_ENV = is_true_in_env(('PYCHARM_DEBUG', 'PYDEV_DEBUG', 'PYDEVD_DEBUG'))
if SHOW_DEBUG_INFO_ENV:
# show debug info before the debugger start
DebugInfoHolder.DEBUG_RECORD_SOCKET_READS = True
DebugInfoHolder.DEBUG_TRACE_LEVEL = 3
DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS = 1
DebugInfoHolder.PYDEVD_DEBUG_FILE = os.getenv('PYDEVD_DEBUG_FILE')

View file

@ -163,7 +163,7 @@ class PyDevJsonCommandProcessor(object):
return NetCommand(CMD_RETURN, 0, error_response, is_json=True)
else:
if DebugInfoHolder.DEBUG_RECORD_SOCKET_READS and DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1:
if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1:
pydev_log.info('Process %s: %s\n' % (
request.__class__.__name__, json.dumps(request.to_dict(update_ids_to_dap=True), indent=4, sort_keys=True),))

View file

@ -64,11 +64,11 @@ from _pydevd_bundle.pydevd_extension_api import DebuggerEventHandler
from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame, remove_exception_from_frame
from _pydevd_bundle.pydevd_net_command_factory_xml import NetCommandFactory
from _pydevd_bundle.pydevd_trace_dispatch import (
trace_dispatch as _trace_dispatch, global_cache_skips, global_cache_frame_skips, fix_top_level_trace_and_get_trace_func)
trace_dispatch as _trace_dispatch, global_cache_skips, global_cache_frame_skips, fix_top_level_trace_and_get_trace_func, USING_CYTHON)
from _pydevd_bundle.pydevd_utils import save_main_module, is_current_thread_main_thread, \
import_attr_from_module
from _pydevd_frame_eval.pydevd_frame_eval_main import (
frame_eval_func, dummy_trace_dispatch)
frame_eval_func, dummy_trace_dispatch, USING_FRAME_EVAL)
import pydev_ipython # @UnusedImport
from _pydevd_bundle.pydevd_source_mapping import SourceMapping
from _pydevd_bundle.pydevd_concurrency_analyser.pydevd_concurrency_logger import ThreadingLogger, AsyncioLogger, send_concurrency_message, cur_time
@ -1814,22 +1814,19 @@ class PyDB(object):
if eb.notify_on_unhandled_exceptions:
cp = self.break_on_uncaught_exceptions.copy()
cp[exception] = eb
if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
pydev_log.critical("Exceptions to hook on terminate: %s.", cp)
pydev_log.info("Exceptions to hook on terminate: %s.", cp)
self.break_on_uncaught_exceptions = cp
if eb.notify_on_handled_exceptions:
cp = self.break_on_caught_exceptions.copy()
cp[exception] = eb
if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
pydev_log.critical("Exceptions to hook always: %s.", cp)
pydev_log.info("Exceptions to hook always: %s.", cp)
self.break_on_caught_exceptions = cp
if eb.notify_on_user_unhandled_exceptions:
cp = self.break_on_user_uncaught_exceptions.copy()
cp[exception] = eb
if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
pydev_log.critical("Exceptions to hook on user uncaught code: %s.", cp)
pydev_log.info("Exceptions to hook on user uncaught code: %s.", cp)
self.break_on_user_uncaught_exceptions = cp
return eb
@ -2600,12 +2597,6 @@ def send_json_message(msg):
return True
def set_debug(setup):
setup['DEBUG_RECORD_SOCKET_READS'] = True
setup['DEBUG_TRACE_BREAKPOINTS'] = 1
setup['DEBUG_TRACE_LEVEL'] = 3
def enable_qt_support(qt_support_mode):
from _pydev_bundle import pydev_monkey_qt
pydev_monkey_qt.patch_qt(qt_support_mode)
@ -3239,14 +3230,40 @@ for handler in pydevd_extension_utils.extensions_of_type(DebuggerEventHandler):
handler.on_debugger_modules_loaded(debugger_version=__version__)
def log_to(log_file:str, log_level=3) -> None:
'''
In pydevd it's possible to log by setting the following environment variables:
PYDEVD_DEBUG=1 (sets the default log level to 3 along with other default options)
PYDEVD_DEBUG_FILE=</path/to/file.log>
Note that the file will have the pid of the process added to it (so, logging to
/path/to/file.log would actually start logging to /path/to/file.<pid>.log -- if subprocesses are
logged, each new subprocess will have the logging set to its own pid).
Usually setting the environment variable is preferred as it'd log information while
pydevd is still doing its imports and not just after this method is called, but on
cases where this is hard to do this function may be called to set the tracing after
pydevd itself is already imported.
'''
pydev_log.log_to(log_file, log_level)
def _log_initial_info():
pydev_log.debug("Initial arguments: %s", (sys.argv,))
pydev_log.debug("Current pid: %s", os.getpid())
pydev_log.debug("Using cython: %s", USING_CYTHON)
pydev_log.debug("Using frame eval: %s", USING_FRAME_EVAL)
pydev_log.debug("Using gevent mode: %s / imported gevent module support: %s", SUPPORT_GEVENT, bool(pydevd_gevent_integration))
#=======================================================================================================================
# main
#=======================================================================================================================
def main():
# parse the command line. --file is our last argument that is required
pydev_log.debug("Initial arguments: %s", (sys.argv,))
pydev_log.debug("Current pid: %s", os.getpid())
_log_initial_info()
try:
from _pydevd_bundle.pydevd_command_line_handling import process_command_line
setup = process_command_line(sys.argv)
@ -3255,6 +3272,24 @@ def main():
pydev_log.exception()
usage(1)
log_trace_level = setup.get('log-level')
# Note: the logging info could've been changed (this would happen if this is a
# subprocess and the value in the environment variable does not match the value in the
# argument because the user used `pydevd.log_to` instead of supplying the environment
# variable). If this is the case, update the logging info and re-log some information
# in the new target.
new_debug_file = setup.get('log-file')
if new_debug_file and DebugInfoHolder.PYDEVD_DEBUG_FILE != new_debug_file:
# The debug file can't be set directly, we need to use log_to() so that the a
# new stream is actually created for the new file.
log_to(new_debug_file, log_trace_level if log_trace_level is not None else 3)
_log_initial_info() # The redirection info just changed, log it again.
elif log_trace_level is not None:
# The log file was not specified
DebugInfoHolder.DEBUG_TRACE_LEVEL = log_trace_level
if setup['print-in-debugger-startup']:
try:
pid = ' (pid: %s)' % os.getpid()
@ -3267,13 +3302,6 @@ def main():
pydevd_vm_type.setup_type(setup.get('vm_type', None))
if SHOW_DEBUG_INFO_ENV:
set_debug(setup)
DebugInfoHolder.DEBUG_RECORD_SOCKET_READS = setup.get('DEBUG_RECORD_SOCKET_READS', DebugInfoHolder.DEBUG_RECORD_SOCKET_READS)
DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS = setup.get('DEBUG_TRACE_BREAKPOINTS', DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS)
DebugInfoHolder.DEBUG_TRACE_LEVEL = setup.get('DEBUG_TRACE_LEVEL', DebugInfoHolder.DEBUG_TRACE_LEVEL)
port = setup['port']
host = setup['client']
f = setup['file']

View file

@ -168,8 +168,6 @@ def attach(port, host, protocol=''):
if py_db is not None:
py_db.dispose_and_kill_all_pydevd_threads(wait=False)
# pydevd.DebugInfoHolder.DEBUG_RECORD_SOCKET_READS = True
# pydevd.DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS = 3
# pydevd.DebugInfoHolder.DEBUG_TRACE_LEVEL = 3
pydevd.settrace(
port=port,

View file

@ -418,7 +418,7 @@ def case_setup_multiprocessing(debugger_runner_simple):
def update_command_line_args(writer, args):
ret = debugger_unittest.AbstractWriterThread.update_command_line_args(writer, args)
ret.insert(ret.index('--DEBUG_RECORD_SOCKET_READS'), '--multiprocess')
ret.insert(ret.index('--client'), '--multiprocess')
return ret
WriterThread.update_command_line_args = update_command_line_args

View file

@ -397,7 +397,6 @@ class DebuggerRunner(object):
localhost = pydev_localhost.get_localhost()
ret = [
writer.get_pydevd_file(),
'--DEBUG_RECORD_SOCKET_READS',
]
if not IS_PY36_OR_GREATER or not IS_CPYTHON or not TEST_CYTHON:

View file

@ -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')

View file

@ -3836,10 +3836,12 @@ def test_step_over_my_code_global_setting_and_explicit_include(case_setup):
def test_access_token(case_setup):
def update_command_line_args(self, args):
args.insert(2, '--access-token')
args.insert(3, 'bar123')
args.insert(2, '--client-access-token')
args.insert(3, 'foo234')
i = args.index('--client')
assert i > 0
args.insert(i, '--access-token')
args.insert(i + 1, 'bar123')
args.insert(i, '--client-access-token')
args.insert(i + 1, 'foo234')
return args
with case_setup.test_file('_debugger_case_print.py', update_command_line_args=update_command_line_args) as writer:

View file

@ -4130,8 +4130,8 @@ def test_ppid(case_setup, pyfile):
def update_command_line_args(writer, args):
ret = debugger_unittest.AbstractWriterThread.update_command_line_args(writer, args)
ret.insert(ret.index('--DEBUG_RECORD_SOCKET_READS'), '--ppid')
ret.insert(ret.index('--DEBUG_RECORD_SOCKET_READS'), '22')
ret.insert(ret.index('--client'), '--ppid')
ret.insert(ret.index('--client'), '22')
return ret
with case_setup.test_file(
@ -4937,7 +4937,7 @@ def test_no_subprocess_patching(case_setup_multiprocessing, apply_multiprocessin
def update_command_line_args(writer, args):
ret = debugger_unittest.AbstractWriterThread.update_command_line_args(writer, args)
ret.insert(ret.index('--DEBUG_RECORD_SOCKET_READS'), '--multiprocess')
ret.insert(ret.index('--client'), '--multiprocess')
if apply_multiprocessing_patch:
ret.append('apply-multiprocessing-patch')
return ret
@ -6304,6 +6304,72 @@ def test_ipython_stepping_step_in(case_setup):
writer.finished_ok = True
def test_logging_api(case_setup_multiprocessing, tmpdir):
import threading
from tests_python.debugger_unittest import AbstractWriterThread
log_file = str(tmpdir.join('pydevd_in_test_logging.log'))
def get_environ(self):
env = os.environ.copy()
env["TARGET_LOG_FILE"] = log_file
return env
with case_setup_multiprocessing.test_file(
'_debugger_case_logging.py',
get_environ=get_environ
) as writer:
json_facade = JsonFacade(writer)
json_facade.write_launch()
break1_line = writer.get_line_index_with_content("break on 2nd process")
json_facade.write_set_breakpoints([break1_line])
server_socket = writer.server_socket
secondary_finished_ok = [False]
class SecondaryProcessWriterThread(AbstractWriterThread):
TEST_FILE = writer.get_main_filename()
_sequence = -1
class SecondaryProcessThreadCommunication(threading.Thread):
def run(self):
from tests_python.debugger_unittest import ReaderThread
server_socket.listen(1)
self.server_socket = server_socket
new_sock, addr = server_socket.accept()
reader_thread = ReaderThread(new_sock)
reader_thread.name = ' *** Multiprocess Reader Thread'
reader_thread.start()
writer2 = SecondaryProcessWriterThread()
writer2.reader_thread = reader_thread
writer2.sock = new_sock
json_facade2 = JsonFacade(writer2)
json_facade2.write_set_breakpoints([break1_line, ])
json_facade2.write_make_initial_run()
json_facade2.wait_for_thread_stopped()
json_facade2.write_continue()
secondary_finished_ok[0] = True
secondary_process_thread_communication = SecondaryProcessThreadCommunication()
secondary_process_thread_communication.start()
time.sleep(.1)
json_facade.write_make_initial_run()
secondary_process_thread_communication.join(10)
if secondary_process_thread_communication.is_alive():
raise AssertionError('The SecondaryProcessThreadCommunication did not finish')
assert secondary_finished_ok[0]
writer.finished_ok = True
if __name__ == '__main__':
pytest.main(['-k', 'test_replace_process', '-s'])

View file

@ -255,10 +255,7 @@ def _check_tracing_other_threads():
import pydevd_tracing
import time
from tests_python.debugger_unittest import wait_for_condition
try:
import _thread
except ImportError:
import thread as _thread
import _thread
# This method is called in a subprocess, so, make sure we exit properly even if we somehow
# deadlock somewhere else.