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:
@@ -0,0 +1,38 @@
|
||||
import sys
|
||||
import threading
|
||||
from _pydev_bundle import pydev_log
|
||||
|
||||
|
||||
def check():
|
||||
with pydev_log.log_context(3, sys.stderr):
|
||||
assert hasattr(sys, 'gettotalrefcount')
|
||||
import pydevd_tracing
|
||||
|
||||
proceed1 = threading.Event()
|
||||
proceed2 = threading.Event()
|
||||
|
||||
class SomeThread(threading.Thread):
|
||||
|
||||
def run(self):
|
||||
proceed1.set()
|
||||
proceed2.wait()
|
||||
|
||||
t = SomeThread()
|
||||
t.start()
|
||||
proceed1.wait()
|
||||
try:
|
||||
|
||||
def some_func(frame, event, arg):
|
||||
return some_func
|
||||
|
||||
pydevd_tracing.set_trace_to_threads(some_func)
|
||||
finally:
|
||||
proceed2.set()
|
||||
|
||||
lib = pydevd_tracing._load_python_helper_lib()
|
||||
assert lib is None
|
||||
print('Finished OK')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
check()
|
||||
@@ -0,0 +1,45 @@
|
||||
import os
|
||||
import sys
|
||||
import platform
|
||||
|
||||
TEST_CYTHON = os.getenv('PYDEVD_USE_CYTHON', None) == 'YES'
|
||||
PYDEVD_TEST_VM = os.getenv('PYDEVD_TEST_VM', None)
|
||||
|
||||
IS_PY36_OR_GREATER = sys.version_info[0:2] >= (3, 6)
|
||||
IS_PY311_OR_GREATER = sys.version_info[0:2] >= (3, 11)
|
||||
IS_CPYTHON = platform.python_implementation() == 'CPython'
|
||||
|
||||
TODO_PY311 = IS_PY311_OR_GREATER # Code which needs to be fixed in 3.11 should use this constant.
|
||||
|
||||
IS_PY36 = False
|
||||
if sys.version_info[0] == 3 and sys.version_info[1] == 6:
|
||||
IS_PY36 = True
|
||||
|
||||
TEST_DJANGO = False
|
||||
TEST_FLASK = False
|
||||
TEST_CHERRYPY = False
|
||||
TEST_GEVENT = False
|
||||
|
||||
try:
|
||||
import django
|
||||
TEST_DJANGO = True
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
import flask
|
||||
TEST_FLASK = True
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
import cherrypy
|
||||
TEST_CHERRYPY = True
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
import gevent
|
||||
TEST_GEVENT = True
|
||||
except:
|
||||
pass
|
||||
@@ -0,0 +1,575 @@
|
||||
# coding: utf-8
|
||||
from contextlib import contextmanager
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from tests_python import debugger_unittest
|
||||
from tests_python.debugger_unittest import (get_free_port, overrides, IS_CPYTHON, IS_JYTHON, IS_IRONPYTHON,
|
||||
CMD_ADD_DJANGO_EXCEPTION_BREAK, CMD_REMOVE_DJANGO_EXCEPTION_BREAK,
|
||||
CMD_ADD_EXCEPTION_BREAK, wait_for_condition, IS_PYPY)
|
||||
from _pydevd_bundle.pydevd_comm_constants import file_system_encoding
|
||||
|
||||
import sys
|
||||
from _pydevd_bundle.pydevd_constants import IS_WINDOWS
|
||||
|
||||
|
||||
def get_java_location():
|
||||
from java.lang import System # @UnresolvedImport
|
||||
jre_dir = System.getProperty("java.home")
|
||||
for f in [os.path.join(jre_dir, 'bin', 'java.exe'), os.path.join(jre_dir, 'bin', 'java')]:
|
||||
if os.path.exists(f):
|
||||
return f
|
||||
raise RuntimeError('Unable to find java executable')
|
||||
|
||||
|
||||
def get_jython_jar():
|
||||
from java.lang import ClassLoader # @UnresolvedImport
|
||||
cl = ClassLoader.getSystemClassLoader()
|
||||
paths = map(lambda url: url.getFile(), cl.getURLs())
|
||||
for p in paths:
|
||||
if 'jython.jar' in p:
|
||||
return p
|
||||
raise RuntimeError('Unable to find jython.jar')
|
||||
|
||||
|
||||
class _WriterThreadCaseMSwitch(debugger_unittest.AbstractWriterThread):
|
||||
|
||||
TEST_FILE = 'tests_python.resources._debugger_case_m_switch'
|
||||
IS_MODULE = True
|
||||
|
||||
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
|
||||
def get_environ(self):
|
||||
env = os.environ.copy()
|
||||
curr_pythonpath = env.get('PYTHONPATH', '')
|
||||
|
||||
root_dirname = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
curr_pythonpath += root_dirname + os.pathsep
|
||||
env['PYTHONPATH'] = curr_pythonpath
|
||||
return env
|
||||
|
||||
@overrides(debugger_unittest.AbstractWriterThread.get_main_filename)
|
||||
def get_main_filename(self):
|
||||
return debugger_unittest._get_debugger_test_file('_debugger_case_m_switch.py')
|
||||
|
||||
|
||||
class _WriterThreadCaseModuleWithEntryPoint(_WriterThreadCaseMSwitch):
|
||||
|
||||
TEST_FILE = 'tests_python.resources._debugger_case_module_entry_point:main'
|
||||
IS_MODULE = True
|
||||
|
||||
@overrides(_WriterThreadCaseMSwitch.get_main_filename)
|
||||
def get_main_filename(self):
|
||||
return debugger_unittest._get_debugger_test_file('_debugger_case_module_entry_point.py')
|
||||
|
||||
|
||||
class AbstractWriterThreadCaseFlask(debugger_unittest.AbstractWriterThread):
|
||||
|
||||
FORCE_KILL_PROCESS_WHEN_FINISHED_OK = True
|
||||
FLASK_FOLDER = None
|
||||
|
||||
TEST_FILE = 'flask'
|
||||
IS_MODULE = True
|
||||
|
||||
def write_add_breakpoint_jinja2(self, line, func, template):
|
||||
'''
|
||||
@param line: starts at 1
|
||||
'''
|
||||
assert self.FLASK_FOLDER is not None
|
||||
breakpoint_id = self.next_breakpoint_id()
|
||||
template_file = debugger_unittest._get_debugger_test_file(os.path.join(self.FLASK_FOLDER, 'templates', template))
|
||||
self.write("111\t%s\t%s\t%s\t%s\t%s\t%s\tNone\tNone" % (self.next_seq(), breakpoint_id, 'jinja2-line', template_file, line, func))
|
||||
self.log.append('write_add_breakpoint_jinja: %s line: %s func: %s' % (breakpoint_id, line, func))
|
||||
return breakpoint_id
|
||||
|
||||
def write_add_exception_breakpoint_jinja2(self, exception='jinja2-Exception'):
|
||||
self.write('%s\t%s\t%s\t%s\t%s\t%s' % (CMD_ADD_EXCEPTION_BREAK, self.next_seq(), exception, 2, 0, 0))
|
||||
|
||||
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
|
||||
def get_environ(self):
|
||||
import platform
|
||||
|
||||
env = os.environ.copy()
|
||||
env['FLASK_APP'] = 'app.py'
|
||||
env['FLASK_ENV'] = 'development'
|
||||
env['FLASK_DEBUG'] = '0'
|
||||
if platform.system() != 'Windows':
|
||||
locale = 'en_US.utf8' if platform.system() == 'Linux' else 'en_US.UTF-8'
|
||||
env.update({
|
||||
'LC_ALL': locale,
|
||||
'LANG': locale,
|
||||
})
|
||||
return env
|
||||
|
||||
def get_cwd(self):
|
||||
return debugger_unittest._get_debugger_test_file(self.FLASK_FOLDER)
|
||||
|
||||
def get_command_line_args(self):
|
||||
assert self.FLASK_FOLDER is not None
|
||||
free_port = get_free_port()
|
||||
self.flask_port = free_port
|
||||
return [
|
||||
'flask',
|
||||
'run',
|
||||
'--no-debugger',
|
||||
'--no-reload',
|
||||
'--with-threads',
|
||||
'--port',
|
||||
str(free_port),
|
||||
]
|
||||
|
||||
def _ignore_stderr_line(self, line):
|
||||
if debugger_unittest.AbstractWriterThread._ignore_stderr_line(self, line):
|
||||
return True
|
||||
|
||||
if 'Running on http:' in line:
|
||||
return True
|
||||
|
||||
if 'GET / HTTP/' in line:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def create_request_thread(self, url=''):
|
||||
return debugger_unittest.AbstractWriterThread.create_request_thread(
|
||||
self, 'http://127.0.0.1:%s%s' % (self.flask_port, url))
|
||||
|
||||
|
||||
class AbstractWriterThreadCaseDjango(debugger_unittest.AbstractWriterThread):
|
||||
|
||||
FORCE_KILL_PROCESS_WHEN_FINISHED_OK = True
|
||||
DJANGO_FOLDER = None
|
||||
|
||||
def _ignore_stderr_line(self, line):
|
||||
if debugger_unittest.AbstractWriterThread._ignore_stderr_line(self, line):
|
||||
return True
|
||||
|
||||
if 'GET /my_app' in line:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_command_line_args(self):
|
||||
assert self.DJANGO_FOLDER is not None
|
||||
free_port = get_free_port()
|
||||
self.django_port = free_port
|
||||
return [
|
||||
debugger_unittest._get_debugger_test_file(os.path.join(self.DJANGO_FOLDER, 'manage.py')),
|
||||
'runserver',
|
||||
'--noreload',
|
||||
'--nothreading',
|
||||
str(free_port),
|
||||
]
|
||||
|
||||
def write_add_breakpoint_django(self, line, func, template):
|
||||
'''
|
||||
@param line: starts at 1
|
||||
'''
|
||||
assert self.DJANGO_FOLDER is not None
|
||||
breakpoint_id = self.next_breakpoint_id()
|
||||
template_file = debugger_unittest._get_debugger_test_file(os.path.join(self.DJANGO_FOLDER, 'my_app', 'templates', 'my_app', template))
|
||||
self.write("111\t%s\t%s\t%s\t%s\t%s\t%s\tNone\tNone" % (self.next_seq(), breakpoint_id, 'django-line', template_file, line, func))
|
||||
self.log.append('write_add_django_breakpoint: %s line: %s func: %s' % (breakpoint_id, line, func))
|
||||
return breakpoint_id
|
||||
|
||||
def write_add_exception_breakpoint_django(self, exception='Exception'):
|
||||
self.write('%s\t%s\t%s' % (CMD_ADD_DJANGO_EXCEPTION_BREAK, self.next_seq(), exception))
|
||||
|
||||
def write_remove_exception_breakpoint_django(self, exception='Exception'):
|
||||
self.write('%s\t%s\t%s' % (CMD_REMOVE_DJANGO_EXCEPTION_BREAK, self.next_seq(), exception))
|
||||
|
||||
def create_request_thread(self, url=''):
|
||||
return debugger_unittest.AbstractWriterThread.create_request_thread(
|
||||
self, 'http://127.0.0.1:%s/%s' % (self.django_port, url))
|
||||
|
||||
|
||||
class DebuggerRunnerSimple(debugger_unittest.DebuggerRunner):
|
||||
|
||||
def get_command_line(self):
|
||||
if IS_JYTHON:
|
||||
if sys.executable is not None:
|
||||
# i.e.: we're running with the provided jython.exe
|
||||
return [sys.executable]
|
||||
else:
|
||||
|
||||
return [
|
||||
get_java_location(),
|
||||
'-classpath',
|
||||
get_jython_jar(),
|
||||
'org.python.util.jython'
|
||||
]
|
||||
|
||||
if IS_CPYTHON or IS_PYPY:
|
||||
return [sys.executable, '-u']
|
||||
|
||||
if IS_IRONPYTHON:
|
||||
return [
|
||||
sys.executable,
|
||||
'-X:Frames'
|
||||
]
|
||||
|
||||
raise RuntimeError('Unable to provide command line')
|
||||
|
||||
|
||||
class DebuggerRunnerRemote(debugger_unittest.DebuggerRunner):
|
||||
|
||||
def get_command_line(self):
|
||||
return [sys.executable, '-u']
|
||||
|
||||
def add_command_line_args(self, args, dap=False):
|
||||
writer = self.writer
|
||||
|
||||
ret = args + [self.writer.TEST_FILE]
|
||||
ret = writer.update_command_line_args(ret) # Provide a hook for the writer
|
||||
return ret
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def debugger_runner_simple(tmpdir):
|
||||
return DebuggerRunnerSimple(tmpdir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def debugger_runner_remote(tmpdir):
|
||||
return DebuggerRunnerRemote(tmpdir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup(tmpdir, debugger_runner_simple):
|
||||
runner = debugger_runner_simple
|
||||
|
||||
class WriterThread(debugger_unittest.AbstractWriterThread):
|
||||
pass
|
||||
|
||||
class CaseSetup(object):
|
||||
|
||||
check_non_ascii = False
|
||||
NON_ASCII_CHARS = u'áéíóú汉字'
|
||||
dap = False
|
||||
|
||||
@contextmanager
|
||||
def test_file(
|
||||
self,
|
||||
filename,
|
||||
wait_for_port=True,
|
||||
wait_for_initialization=True,
|
||||
**kwargs
|
||||
):
|
||||
import shutil
|
||||
filename = debugger_unittest._get_debugger_test_file(filename)
|
||||
if self.check_non_ascii:
|
||||
basedir = str(tmpdir)
|
||||
if isinstance(basedir, bytes):
|
||||
basedir = basedir.decode('utf-8')
|
||||
if isinstance(filename, bytes):
|
||||
filename = filename.decode('utf-8')
|
||||
|
||||
new_dir = os.path.join(basedir, self.NON_ASCII_CHARS)
|
||||
os.makedirs(new_dir)
|
||||
|
||||
new_filename = os.path.join(new_dir, self.NON_ASCII_CHARS + os.path.basename(filename))
|
||||
shutil.copyfile(filename, new_filename)
|
||||
filename = new_filename
|
||||
|
||||
WriterThread.TEST_FILE = filename
|
||||
for key, value in kwargs.items():
|
||||
assert hasattr(WriterThread, key)
|
||||
setattr(WriterThread, key, value)
|
||||
|
||||
with runner.check_case(
|
||||
WriterThread,
|
||||
wait_for_port=wait_for_port,
|
||||
wait_for_initialization=wait_for_initialization,
|
||||
dap=self.dap
|
||||
) as writer:
|
||||
yield writer
|
||||
|
||||
return CaseSetup()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_dap(case_setup):
|
||||
case_setup.dap = True
|
||||
return case_setup
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_unhandled_exceptions(case_setup):
|
||||
|
||||
original = case_setup.test_file
|
||||
|
||||
def check_test_suceeded_msg(writer, stdout, stderr):
|
||||
return 'TEST SUCEEDED' in ''.join(stderr)
|
||||
|
||||
def additional_output_checks(writer, stdout, stderr):
|
||||
# Don't call super as we have an expected exception
|
||||
if 'ValueError: TEST SUCEEDED' not in stderr:
|
||||
raise AssertionError('"ValueError: TEST SUCEEDED" not in stderr.\nstdout:\n%s\n\nstderr:\n%s' % (
|
||||
stdout, stderr))
|
||||
|
||||
def test_file(*args, **kwargs):
|
||||
kwargs.setdefault('check_test_suceeded_msg', check_test_suceeded_msg)
|
||||
kwargs.setdefault('additional_output_checks', additional_output_checks)
|
||||
return original(*args, **kwargs)
|
||||
|
||||
case_setup.test_file = test_file
|
||||
|
||||
return case_setup
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_remote(debugger_runner_remote):
|
||||
|
||||
class WriterThread(debugger_unittest.AbstractWriterThread):
|
||||
pass
|
||||
|
||||
class CaseSetup(object):
|
||||
|
||||
dap = False
|
||||
|
||||
@contextmanager
|
||||
def test_file(
|
||||
self,
|
||||
filename,
|
||||
wait_for_port=True,
|
||||
access_token=None,
|
||||
client_access_token=None,
|
||||
append_command_line_args=(),
|
||||
**kwargs
|
||||
):
|
||||
|
||||
def update_command_line_args(writer, args):
|
||||
ret = debugger_unittest.AbstractWriterThread.update_command_line_args(writer, args)
|
||||
wait_for_condition(lambda: hasattr(writer, 'port'))
|
||||
ret.append(str(writer.port))
|
||||
|
||||
if access_token is not None:
|
||||
ret.append('--access-token')
|
||||
ret.append(access_token)
|
||||
if client_access_token is not None:
|
||||
ret.append('--client-access-token')
|
||||
ret.append(client_access_token)
|
||||
|
||||
if self.dap:
|
||||
ret.append('--use-dap-mode')
|
||||
|
||||
ret.extend(append_command_line_args)
|
||||
return ret
|
||||
|
||||
WriterThread.TEST_FILE = debugger_unittest._get_debugger_test_file(filename)
|
||||
WriterThread.update_command_line_args = update_command_line_args
|
||||
for key, value in kwargs.items():
|
||||
assert hasattr(WriterThread, key)
|
||||
setattr(WriterThread, key, value)
|
||||
|
||||
with debugger_runner_remote.check_case(WriterThread, wait_for_port=wait_for_port) as writer:
|
||||
yield writer
|
||||
|
||||
return CaseSetup()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_remote_dap(case_setup_remote):
|
||||
case_setup_remote.dap = True
|
||||
return case_setup_remote
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_remote_attach_to_dap(debugger_runner_remote):
|
||||
'''
|
||||
The difference from this to case_setup_remote is that this one will connect to a server
|
||||
socket started by the debugger and case_setup_remote will create the server socket and wait
|
||||
for a connection from the debugger.
|
||||
'''
|
||||
|
||||
class WriterThread(debugger_unittest.AbstractWriterThread):
|
||||
|
||||
@overrides(debugger_unittest.AbstractWriterThread.run)
|
||||
def run(self):
|
||||
# I.e.: don't start socket on start(), rather, the test should call
|
||||
# start_socket_client() when needed.
|
||||
pass
|
||||
|
||||
class CaseSetup(object):
|
||||
|
||||
dap = True
|
||||
|
||||
@contextmanager
|
||||
def test_file(
|
||||
self,
|
||||
filename,
|
||||
port,
|
||||
**kwargs
|
||||
):
|
||||
additional_args = kwargs.pop('additional_args', [])
|
||||
|
||||
def update_command_line_args(writer, args):
|
||||
ret = debugger_unittest.AbstractWriterThread.update_command_line_args(writer, args)
|
||||
ret.append(str(port))
|
||||
if self.dap:
|
||||
ret.append('--use-dap-mode')
|
||||
ret.extend(additional_args)
|
||||
return ret
|
||||
|
||||
WriterThread.TEST_FILE = debugger_unittest._get_debugger_test_file(filename)
|
||||
WriterThread.update_command_line_args = update_command_line_args
|
||||
for key, value in kwargs.items():
|
||||
assert hasattr(WriterThread, key)
|
||||
setattr(WriterThread, key, value)
|
||||
|
||||
with debugger_runner_remote.check_case(WriterThread, wait_for_port=False) as writer:
|
||||
yield writer
|
||||
|
||||
return CaseSetup()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_multiprocessing(debugger_runner_simple):
|
||||
|
||||
class WriterThread(debugger_unittest.AbstractWriterThread):
|
||||
pass
|
||||
|
||||
class CaseSetup(object):
|
||||
|
||||
dap = False
|
||||
|
||||
@contextmanager
|
||||
def test_file(
|
||||
self,
|
||||
filename,
|
||||
**kwargs
|
||||
):
|
||||
|
||||
def update_command_line_args(writer, args):
|
||||
ret = debugger_unittest.AbstractWriterThread.update_command_line_args(writer, args)
|
||||
ret.insert(ret.index('--client'), '--multiprocess')
|
||||
if self.dap:
|
||||
ret.insert(ret.index('--client'), '--debug-mode')
|
||||
ret.insert(ret.index('--client'), 'debugpy-dap')
|
||||
ret.insert(ret.index('--client'), '--json-dap-http')
|
||||
return ret
|
||||
|
||||
WriterThread.update_command_line_args = update_command_line_args
|
||||
WriterThread.TEST_FILE = debugger_unittest._get_debugger_test_file(filename)
|
||||
for key, value in kwargs.items():
|
||||
assert hasattr(WriterThread, key)
|
||||
setattr(WriterThread, key, value)
|
||||
|
||||
with debugger_runner_simple.check_case(WriterThread) as writer:
|
||||
yield writer
|
||||
|
||||
return CaseSetup()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_multiprocessing_dap(case_setup_multiprocessing):
|
||||
case_setup_multiprocessing.dap = True
|
||||
return case_setup_multiprocessing
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_m_switch(debugger_runner_simple):
|
||||
|
||||
class WriterThread(_WriterThreadCaseMSwitch):
|
||||
pass
|
||||
|
||||
class CaseSetup(object):
|
||||
|
||||
@contextmanager
|
||||
def test_file(self, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
assert hasattr(WriterThread, key)
|
||||
setattr(WriterThread, key, value)
|
||||
with debugger_runner_simple.check_case(WriterThread) as writer:
|
||||
yield writer
|
||||
|
||||
return CaseSetup()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_m_switch_entry_point(debugger_runner_simple):
|
||||
|
||||
runner = debugger_runner_simple
|
||||
|
||||
class WriterThread(_WriterThreadCaseModuleWithEntryPoint):
|
||||
pass
|
||||
|
||||
class CaseSetup(object):
|
||||
|
||||
@contextmanager
|
||||
def test_file(self, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
assert hasattr(WriterThread, key)
|
||||
setattr(WriterThread, key, value)
|
||||
with runner.check_case(WriterThread) as writer:
|
||||
yield writer
|
||||
|
||||
return CaseSetup()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_django(debugger_runner_simple):
|
||||
|
||||
class WriterThread(AbstractWriterThreadCaseDjango):
|
||||
pass
|
||||
|
||||
class CaseSetup(object):
|
||||
|
||||
dap = False
|
||||
|
||||
@contextmanager
|
||||
def test_file(self, **kwargs):
|
||||
import django
|
||||
version = [int(x) for x in django.get_version().split('.')][:2]
|
||||
if version == [1, 7]:
|
||||
django_folder = 'my_django_proj_17'
|
||||
elif version in ([2, 1], [2, 2], [3, 0], [3, 1], [3, 2], [4, 0], [4, 1]):
|
||||
django_folder = 'my_django_proj_21'
|
||||
else:
|
||||
raise AssertionError('Can only check django 1.7 -> 4.1 right now. Found: %s' % (version,))
|
||||
|
||||
WriterThread.DJANGO_FOLDER = django_folder
|
||||
for key, value in kwargs.items():
|
||||
assert hasattr(WriterThread, key)
|
||||
setattr(WriterThread, key, value)
|
||||
|
||||
with debugger_runner_simple.check_case(WriterThread, dap=self.dap) as writer:
|
||||
yield writer
|
||||
|
||||
return CaseSetup()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_django_dap(case_setup_django):
|
||||
case_setup_django.dap = True
|
||||
return case_setup_django
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_flask(debugger_runner_simple):
|
||||
|
||||
class WriterThread(AbstractWriterThreadCaseFlask):
|
||||
pass
|
||||
|
||||
class CaseSetup(object):
|
||||
|
||||
dap = False
|
||||
|
||||
@contextmanager
|
||||
def test_file(self, **kwargs):
|
||||
WriterThread.FLASK_FOLDER = 'flask1'
|
||||
for key, value in kwargs.items():
|
||||
assert hasattr(WriterThread, key)
|
||||
setattr(WriterThread, key, value)
|
||||
|
||||
with debugger_runner_simple.check_case(WriterThread, dap=self.dap) as writer:
|
||||
yield writer
|
||||
|
||||
return CaseSetup()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def case_setup_flask_dap(case_setup_flask):
|
||||
case_setup_flask.dap = True
|
||||
return case_setup_flask
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,60 @@
|
||||
from flask import Flask
|
||||
from flask import render_template
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def home():
|
||||
content = 'Flask-Jinja-Test'
|
||||
return render_template(
|
||||
"hello.html",
|
||||
title='Hello',
|
||||
content=content
|
||||
)
|
||||
|
||||
|
||||
@app.route("/handled")
|
||||
def bad_route_handled():
|
||||
try:
|
||||
raise ArithmeticError('Hello')
|
||||
except Exception:
|
||||
pass
|
||||
return render_template(
|
||||
"hello.html",
|
||||
title='Hello',
|
||||
content='Flask-Jinja-Test'
|
||||
)
|
||||
|
||||
|
||||
@app.route("/unhandled")
|
||||
def bad_route_unhandled():
|
||||
raise ArithmeticError('Hello')
|
||||
return render_template(
|
||||
"hello.html",
|
||||
title='Hello',
|
||||
content='Flask-Jinja-Test'
|
||||
)
|
||||
|
||||
|
||||
@app.route("/bad_template")
|
||||
def bad_template():
|
||||
return render_template(
|
||||
"bad.html",
|
||||
title='Bad',
|
||||
content='Flask-Jinja-Test'
|
||||
)
|
||||
|
||||
|
||||
@app.route("/exit")
|
||||
def exit_app():
|
||||
from flask import request
|
||||
func = request.environ.get('werkzeug.server.shutdown')
|
||||
if func is None:
|
||||
raise RuntimeError('No shutdown')
|
||||
func()
|
||||
return 'Done'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_django_proj_17.settings")
|
||||
|
||||
from django.core.management import execute_from_command_line
|
||||
|
||||
execute_from_command_line(sys.argv)
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
@@ -0,0 +1,4 @@
|
||||
from django import forms
|
||||
|
||||
class NameForm(forms.Form):
|
||||
your_name = forms.CharField(label='Your name', max_length=100)
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@@ -0,0 +1,12 @@
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.index, name='index'),
|
||||
url(r'^name$', views.get_name, name='name'),
|
||||
url(r'^template_error$', views.template_error, name='template_error'),
|
||||
url(r'^template_error2$', views.template_error2, name='template_error2'),
|
||||
url(r'^inherits$', views.inherits, name='inherits'),
|
||||
url(r'^no_var_error$', views.no_var_error, name='no_var_error'),
|
||||
]
|
||||
@@ -0,0 +1,73 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
import sys
|
||||
from .forms import NameForm
|
||||
|
||||
|
||||
class Entry(object):
|
||||
|
||||
def __init__(self, key, val):
|
||||
self.key = key
|
||||
self.val = val
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s:%s' % (self.key, self.val)
|
||||
|
||||
def __str__(self):
|
||||
return u'%s:%s' % (self.key, self.val)
|
||||
|
||||
|
||||
def index(request):
|
||||
context = {
|
||||
'entries': [Entry('v1', 'v1'), Entry('v2', 'v2')]
|
||||
}
|
||||
ret = render(request, 'my_app/index.html', context)
|
||||
return ret
|
||||
|
||||
|
||||
def get_name(request):
|
||||
# if this is a POST request we need to process the form data
|
||||
if request.method == 'POST':
|
||||
# create a form instance and populate it with data from the request:
|
||||
form = NameForm(request.POST)
|
||||
# check whether it's valid:
|
||||
if form.is_valid():
|
||||
# process the data in form.cleaned_data as required
|
||||
# ...
|
||||
# redirect to a new URL:
|
||||
return HttpResponseRedirect('/thanks/')
|
||||
|
||||
# if a GET (or any other method) we'll create a blank form
|
||||
else:
|
||||
form = NameForm(data={'your_name': 'unknown name'})
|
||||
|
||||
return render(request, 'my_app/name.html', {'form': form})
|
||||
|
||||
|
||||
def inherits(request):
|
||||
context = {}
|
||||
ret = render(request, 'my_app/inherits.html', context)
|
||||
return ret
|
||||
|
||||
|
||||
def template_error(request):
|
||||
context = {
|
||||
'entries': [Entry('v1', 'v1'), Entry('v2', 'v2')]
|
||||
}
|
||||
|
||||
ret = render(request, 'my_app/template_error.html', context)
|
||||
return ret
|
||||
|
||||
|
||||
def template_error2(request):
|
||||
context = {}
|
||||
ret = render(request, 'my_app/template_error2.html', context)
|
||||
return ret
|
||||
|
||||
|
||||
def no_var_error(request):
|
||||
context = {}
|
||||
ret = render(request, 'my_app/no_var_error.html', context)
|
||||
return ret
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
Django settings for my_django_proj_17 project.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.7/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.7/ref/settings/
|
||||
"""
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
import os
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'Placeholder_5_sue9bp&j=45#%_hcx3f34k!qnt$mxfd&7zq@7c7t@sn4_l)b'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
TEMPLATE_DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'my_app',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'my_django_proj_17.urls'
|
||||
|
||||
WSGI_APPLICATION = 'my_django_proj_17.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
|
||||
|
||||
# No database for our test.
|
||||
|
||||
# DATABASES = {
|
||||
# 'default': {
|
||||
# 'ENGINE': 'django.db.backends.sqlite3',
|
||||
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
# }
|
||||
# }
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.7/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.7/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
from django.conf.urls import patterns, include, url
|
||||
from django.contrib import admin
|
||||
|
||||
urlpatterns = patterns('',
|
||||
# Examples:
|
||||
# url(r'^$', 'my_django_proj_17.views.home', name='home'),
|
||||
# url(r'^blog/', include('blog.urls')),
|
||||
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^my_app/', include('my_app.urls')),
|
||||
)
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
"""
|
||||
WSGI config for my_django_proj_17 project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_django_proj_17.settings")
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
application = get_wsgi_application()
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == '__main__':
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'my_django_proj_21.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class MyAppConfig(AppConfig):
|
||||
name = 'my_app'
|
||||
@@ -0,0 +1,4 @@
|
||||
from django import forms
|
||||
|
||||
class NameForm(forms.Form):
|
||||
your_name = forms.CharField(label='Your name', max_length=100)
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
@@ -0,0 +1,72 @@
|
||||
'''
|
||||
Note: run test with manage.py test my_app
|
||||
|
||||
This is mostly for experimenting.
|
||||
|
||||
The actual code used is mostly a copy of this that lives in `django_debug.py`.
|
||||
'''
|
||||
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
|
||||
def collect_lines_for_django_template(template_contents):
|
||||
from django import template
|
||||
t = template.Template(template_contents)
|
||||
return _collect_valid_lines_in_django_template(t)
|
||||
|
||||
|
||||
def _collect_valid_lines_in_django_template(template):
|
||||
lines = set()
|
||||
for node in _iternodes(template.nodelist):
|
||||
lineno = _get_lineno(node)
|
||||
if lineno is not None:
|
||||
lines.add(lineno)
|
||||
return lines
|
||||
|
||||
|
||||
def _get_lineno(node):
|
||||
if hasattr(node, 'token') and hasattr(node.token, 'lineno'):
|
||||
return node.token.lineno
|
||||
return None
|
||||
|
||||
|
||||
def _iternodes(nodelist):
|
||||
for node in nodelist:
|
||||
yield node
|
||||
|
||||
try:
|
||||
children = node.child_nodelists
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
for attr in children:
|
||||
nodelist = getattr(node, attr, None)
|
||||
if nodelist:
|
||||
# i.e.: yield from _iternodes(nodelist)
|
||||
for node in _iternodes(nodelist):
|
||||
yield node
|
||||
|
||||
|
||||
class MyTest(SimpleTestCase):
|
||||
|
||||
def test_something(self):
|
||||
template_contents = '''{% if entries %}
|
||||
<ul>
|
||||
{% for entry in entries %}
|
||||
{% for entry in entries2 %}
|
||||
<li>
|
||||
{{ entry.key }}
|
||||
:
|
||||
{{ entry.val }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>No entries are available.</p>
|
||||
{% endif %}'''
|
||||
|
||||
self.assertEqual(
|
||||
collect_lines_for_django_template(template_contents),
|
||||
{1, 3, 4, 6, 8, 10, 11, 13}
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
try:
|
||||
from django.conf.urls import url
|
||||
except ImportError:
|
||||
from django.urls import re_path as url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.index, name='index'),
|
||||
url(r'^name$', views.get_name, name='name'),
|
||||
url(r'^template_error2$', views.template_error2, name='template_error2'),
|
||||
url(r'^template_error$', views.template_error, name='template_error'),
|
||||
url(r'^inherits$', views.inherits, name='inherits'),
|
||||
url(r'^no_var_error$', views.no_var_error, name='no_var_error'),
|
||||
]
|
||||
@@ -0,0 +1,80 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
import sys
|
||||
from .forms import NameForm
|
||||
|
||||
|
||||
class Entry(object):
|
||||
|
||||
def __init__(self, key, val):
|
||||
self.key = key
|
||||
self.val = val
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s:%s' % (self.key, self.val)
|
||||
|
||||
def __str__(self):
|
||||
return u'%s:%s' % (self.key, self.val)
|
||||
|
||||
|
||||
def index(request):
|
||||
import faulthandler
|
||||
faulthandler.enable()
|
||||
context = {
|
||||
'entries': [Entry('v1', 'v1'), Entry('v2', 'v2')]
|
||||
}
|
||||
ret = render(request, 'my_app/index.html', context)
|
||||
return ret
|
||||
|
||||
|
||||
def get_name(request):
|
||||
import faulthandler
|
||||
faulthandler.enable()
|
||||
# if this is a POST request we need to process the form data
|
||||
if request.method == 'POST':
|
||||
# create a form instance and populate it with data from the request:
|
||||
form = NameForm(request.POST)
|
||||
# check whether it's valid:
|
||||
if form.is_valid():
|
||||
# process the data in form.cleaned_data as required
|
||||
# ...
|
||||
# redirect to a new URL:
|
||||
return HttpResponseRedirect('/thanks/')
|
||||
|
||||
# if a GET (or any other method) we'll create a blank form
|
||||
else:
|
||||
form = NameForm(data={'your_name': 'unknown name'})
|
||||
|
||||
return render(request, 'my_app/name.html', {'form': form})
|
||||
|
||||
|
||||
def template_error(request):
|
||||
import faulthandler
|
||||
faulthandler.enable()
|
||||
context = {
|
||||
'entries': [Entry('v1', 'v1'), Entry('v2', 'v2')]
|
||||
}
|
||||
ret = render(request, 'my_app/template_error.html', context)
|
||||
return ret
|
||||
|
||||
|
||||
def template_error2(request):
|
||||
import faulthandler
|
||||
faulthandler.enable()
|
||||
context = {}
|
||||
ret = render(request, 'my_app/template_error2.html', context)
|
||||
return ret
|
||||
|
||||
|
||||
def inherits(request):
|
||||
context = {}
|
||||
ret = render(request, 'my_app/inherits.html', context)
|
||||
return ret
|
||||
|
||||
|
||||
def no_var_error(request):
|
||||
context = {}
|
||||
ret = render(request, 'my_app/no_var_error.html', context)
|
||||
return ret
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
"""
|
||||
Django settings for my_django_proj_21 project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 2.1.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/2.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/2.1/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'Placeholder_u1jqdxv=z@ue9)%onkenaqb*&4dzd2mmb98#j*8uq^fn#j67)p'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'my_app',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'my_django_proj_21.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'my_django_proj_21.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
|
||||
# No database for our test.
|
||||
# DATABASES = {
|
||||
# 'default': {
|
||||
# 'ENGINE': 'django.db.backends.sqlite3',
|
||||
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
# }
|
||||
# }
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/2.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/2.1/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
"""my_django_proj_21 URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/2.1/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
from django.urls.conf import include
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('my_app/', include('my_app.urls')),
|
||||
]
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for my_django_proj_21 project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'my_django_proj_21.settings')
|
||||
|
||||
application = get_wsgi_application()
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
from _pydevd_bundle.pydevd_extension_api import DebuggerEventHandler
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
class VerifyEvent(object):
|
||||
def on_debugger_modules_loaded(self, **kwargs):
|
||||
print ("INITIALIZE EVENT RECEIVED")
|
||||
# check that some core modules are loaded before this callback is invoked
|
||||
modules_loaded = all(mod in sys.modules for mod in ('pydevd_file_utils', '_pydevd_bundle.pydevd_constants'))
|
||||
if modules_loaded:
|
||||
print ("TEST SUCEEDED") # incorrect spelling on purpose
|
||||
else:
|
||||
print ("TEST FAILED")
|
||||
|
||||
|
||||
if os.environ.get("VERIFY_EVENT_TEST"):
|
||||
DebuggerEventHandler.register(VerifyEvent)
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
from _pydevd_bundle.pydevd_extension_api import StrPresentationProvider, TypeResolveProvider
|
||||
|
||||
|
||||
class RectResolver(TypeResolveProvider):
|
||||
def get_dictionary(self, var):
|
||||
return {'length': var.length, 'width': var.width, 'area': var.length * var.width}
|
||||
|
||||
def resolve(self, var, attribute):
|
||||
return getattr(var, attribute, None) if attribute != 'area' else var.length * var.width
|
||||
|
||||
def can_provide(self, type_object, type_name):
|
||||
return type_name.endswith('Rect')
|
||||
|
||||
|
||||
class RectToString(StrPresentationProvider):
|
||||
def get_str(self, val):
|
||||
return "Rectangle[Length: %s, Width: %s , Area: %s]" % (val.length, val.width, val.length * val.width)
|
||||
|
||||
def can_provide(self, type_object, type_name):
|
||||
return type_name.endswith('Rect')
|
||||
@@ -0,0 +1,245 @@
|
||||
from tests_python import debugger_unittest
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
|
||||
CHECK_BASELINE, CHECK_REGULAR, CHECK_CYTHON, CHECK_FRAME_EVAL = 'baseline', 'regular', 'cython', 'frame_eval'
|
||||
|
||||
pytest_plugins = [
|
||||
str('tests_python.debugger_fixtures'),
|
||||
]
|
||||
|
||||
RUNS = 5
|
||||
|
||||
|
||||
class PerformanceWriterThread(debugger_unittest.AbstractWriterThread):
|
||||
|
||||
CHECK = None
|
||||
|
||||
debugger_unittest.AbstractWriterThread.get_environ # overrides
|
||||
|
||||
def get_environ(self):
|
||||
env = os.environ.copy()
|
||||
if self.CHECK == CHECK_BASELINE:
|
||||
env['PYTHONPATH'] = r'X:\PyDev.Debugger.baseline'
|
||||
|
||||
elif self.CHECK == CHECK_CYTHON:
|
||||
env['PYDEVD_USE_CYTHON'] = 'YES'
|
||||
env['PYDEVD_USE_FRAME_EVAL'] = 'NO'
|
||||
|
||||
elif self.CHECK == CHECK_FRAME_EVAL:
|
||||
env['PYDEVD_USE_CYTHON'] = 'YES'
|
||||
env['PYDEVD_USE_FRAME_EVAL'] = 'YES'
|
||||
|
||||
elif self.CHECK == CHECK_REGULAR:
|
||||
env['PYDEVD_USE_CYTHON'] = 'NO'
|
||||
env['PYDEVD_USE_FRAME_EVAL'] = 'NO'
|
||||
|
||||
else:
|
||||
raise AssertionError("Don't know what to check.")
|
||||
return env
|
||||
|
||||
debugger_unittest.AbstractWriterThread.get_pydevd_file # overrides
|
||||
|
||||
def get_pydevd_file(self):
|
||||
if self.CHECK == CHECK_BASELINE:
|
||||
return os.path.abspath(os.path.join(r'X:\PyDev.Debugger.baseline', 'pydevd.py'))
|
||||
dirname = os.path.dirname(__file__)
|
||||
dirname = os.path.dirname(dirname)
|
||||
return os.path.abspath(os.path.join(dirname, 'pydevd.py'))
|
||||
|
||||
|
||||
class CheckDebuggerPerformance(debugger_unittest.DebuggerRunner):
|
||||
|
||||
def get_command_line(self):
|
||||
return [sys.executable]
|
||||
|
||||
def _get_time_from_result(self, stdout):
|
||||
match = re.search(r'TotalTime>>((\d|\.)+)<<', stdout)
|
||||
time_taken = match.group(1)
|
||||
return float(time_taken)
|
||||
|
||||
def obtain_results(self, benchmark_name, filename):
|
||||
|
||||
class PerformanceCheck(PerformanceWriterThread):
|
||||
TEST_FILE = debugger_unittest._get_debugger_test_file(filename)
|
||||
BENCHMARK_NAME = benchmark_name
|
||||
|
||||
writer_thread_class = PerformanceCheck
|
||||
|
||||
runs = RUNS
|
||||
all_times = []
|
||||
for _ in range(runs):
|
||||
stdout_ref = []
|
||||
|
||||
def store_stdout(stdout, stderr):
|
||||
stdout_ref.append(stdout)
|
||||
|
||||
with self.check_case(writer_thread_class) as writer:
|
||||
writer.additional_output_checks = store_stdout
|
||||
yield writer
|
||||
|
||||
assert len(stdout_ref) == 1
|
||||
all_times.append(self._get_time_from_result(stdout_ref[0]))
|
||||
print('partial for: %s: %.3fs' % (writer_thread_class.BENCHMARK_NAME, all_times[-1]))
|
||||
if len(all_times) > 3:
|
||||
all_times.remove(min(all_times))
|
||||
all_times.remove(max(all_times))
|
||||
time_when_debugged = sum(all_times) / float(len(all_times))
|
||||
|
||||
args = self.get_command_line()
|
||||
args.append(writer_thread_class.TEST_FILE)
|
||||
# regular_time = self._get_time_from_result(self.run_process(args, writer_thread=None))
|
||||
# simple_trace_time = self._get_time_from_result(self.run_process(args+['--regular-trace'], writer_thread=None))
|
||||
|
||||
if 'SPEEDTIN_AUTHORIZATION_KEY' in os.environ:
|
||||
|
||||
SPEEDTIN_AUTHORIZATION_KEY = os.environ['SPEEDTIN_AUTHORIZATION_KEY']
|
||||
|
||||
# sys.path.append(r'X:\speedtin\pyspeedtin')
|
||||
import pyspeedtin # If the authorization key is there, pyspeedtin must be available
|
||||
import pydevd
|
||||
pydevd_cython_project_id, pydevd_pure_python_project_id = 6, 7
|
||||
if writer_thread_class.CHECK == CHECK_BASELINE:
|
||||
project_ids = (pydevd_cython_project_id, pydevd_pure_python_project_id)
|
||||
elif writer_thread_class.CHECK == CHECK_REGULAR:
|
||||
project_ids = (pydevd_pure_python_project_id,)
|
||||
elif writer_thread_class.CHECK == CHECK_CYTHON:
|
||||
project_ids = (pydevd_cython_project_id,)
|
||||
else:
|
||||
raise AssertionError('Wrong check: %s' % (writer_thread_class.CHECK))
|
||||
for project_id in project_ids:
|
||||
api = pyspeedtin.PySpeedTinApi(authorization_key=SPEEDTIN_AUTHORIZATION_KEY, project_id=project_id)
|
||||
|
||||
benchmark_name = writer_thread_class.BENCHMARK_NAME
|
||||
|
||||
if writer_thread_class.CHECK == CHECK_BASELINE:
|
||||
version = '0.0.1_baseline'
|
||||
return # No longer commit the baseline (it's immutable right now).
|
||||
else:
|
||||
version = pydevd.__version__,
|
||||
|
||||
commit_id, branch, commit_date = api.git_commit_id_branch_and_date_from_path(pydevd.__file__)
|
||||
api.add_benchmark(benchmark_name)
|
||||
api.add_measurement(
|
||||
benchmark_name,
|
||||
value=time_when_debugged,
|
||||
version=version,
|
||||
released=False,
|
||||
branch=branch,
|
||||
commit_id=commit_id,
|
||||
commit_date=commit_date,
|
||||
)
|
||||
api.commit()
|
||||
|
||||
self.performance_msg = '%s: %.3fs ' % (writer_thread_class.BENCHMARK_NAME, time_when_debugged)
|
||||
|
||||
def method_calls_with_breakpoint(self):
|
||||
for writer in self.obtain_results('method_calls_with_breakpoint', '_performance_1.py'):
|
||||
writer.write_add_breakpoint(17, 'method')
|
||||
writer.write_make_initial_run()
|
||||
writer.finished_ok = True
|
||||
|
||||
return self.performance_msg
|
||||
|
||||
def method_calls_without_breakpoint(self):
|
||||
for writer in self.obtain_results('method_calls_without_breakpoint', '_performance_1.py'):
|
||||
writer.write_make_initial_run()
|
||||
writer.finished_ok = True
|
||||
|
||||
return self.performance_msg
|
||||
|
||||
def method_calls_with_step_over(self):
|
||||
for writer in self.obtain_results('method_calls_with_step_over', '_performance_1.py'):
|
||||
writer.write_add_breakpoint(26, None)
|
||||
|
||||
writer.write_make_initial_run()
|
||||
hit = writer.wait_for_breakpoint_hit('111')
|
||||
|
||||
writer.write_step_over(hit.thread_id)
|
||||
hit = writer.wait_for_breakpoint_hit('108')
|
||||
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
writer.finished_ok = True
|
||||
|
||||
return self.performance_msg
|
||||
|
||||
def method_calls_with_exception_breakpoint(self):
|
||||
for writer in self.obtain_results('method_calls_with_exception_breakpoint', '_performance_1.py'):
|
||||
writer.write_add_exception_breakpoint('ValueError')
|
||||
writer.write_make_initial_run()
|
||||
writer.finished_ok = True
|
||||
|
||||
return self.performance_msg
|
||||
|
||||
def global_scope_1_with_breakpoint(self):
|
||||
for writer in self.obtain_results('global_scope_1_with_breakpoint', '_performance_2.py'):
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Breakpoint here'), None)
|
||||
writer.write_make_initial_run()
|
||||
writer.finished_ok = True
|
||||
|
||||
return self.performance_msg
|
||||
|
||||
def global_scope_2_with_breakpoint(self):
|
||||
for writer in self.obtain_results('global_scope_2_with_breakpoint', '_performance_3.py'):
|
||||
writer.write_add_breakpoint(17, None)
|
||||
writer.write_make_initial_run()
|
||||
writer.finished_ok = True
|
||||
|
||||
return self.performance_msg
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Local times gotten (python 3.6)
|
||||
# method_calls_with_breakpoint: 1.150s
|
||||
# method_calls_without_breakpoint: 0.240s
|
||||
# method_calls_with_step_over: 2.680s
|
||||
# method_calls_with_exception_breakpoint: 0.235s
|
||||
# global_scope_1_with_breakpoint: 4.249s
|
||||
# global_scope_2_with_breakpoint: 2.807s
|
||||
# Checking: cython
|
||||
# method_calls_with_breakpoint: 0.526s
|
||||
# method_calls_without_breakpoint: 0.130s
|
||||
# method_calls_with_step_over: 1.133s
|
||||
# method_calls_with_exception_breakpoint: 0.136s
|
||||
# global_scope_1_with_breakpoint: 1.827s
|
||||
# global_scope_2_with_breakpoint: 1.405s
|
||||
# Checking: frame_eval
|
||||
# method_calls_with_breakpoint: 0.133s
|
||||
# method_calls_without_breakpoint: 0.128s
|
||||
# method_calls_with_step_over: 0.130s
|
||||
# method_calls_with_exception_breakpoint: 0.125s
|
||||
# global_scope_1_with_breakpoint: 0.281s
|
||||
# global_scope_2_with_breakpoint: 0.169s
|
||||
# TotalTime for profile: 209.01s
|
||||
|
||||
debugger_unittest.SHOW_WRITES_AND_READS = False
|
||||
debugger_unittest.SHOW_OTHER_DEBUG_INFO = False
|
||||
debugger_unittest.SHOW_STDOUT = False
|
||||
|
||||
import time
|
||||
start_time = time.time()
|
||||
|
||||
tmpdir = None
|
||||
|
||||
msgs = []
|
||||
for check in (
|
||||
# CHECK_BASELINE, -- Checks against the version checked out at X:\PyDev.Debugger.baseline.
|
||||
CHECK_REGULAR,
|
||||
CHECK_CYTHON,
|
||||
CHECK_FRAME_EVAL,
|
||||
):
|
||||
PerformanceWriterThread.CHECK = check
|
||||
msgs.append('Checking: %s' % (check,))
|
||||
check_debugger_performance = CheckDebuggerPerformance(tmpdir)
|
||||
msgs.append(check_debugger_performance.method_calls_with_breakpoint())
|
||||
msgs.append(check_debugger_performance.method_calls_without_breakpoint())
|
||||
msgs.append(check_debugger_performance.method_calls_with_step_over())
|
||||
msgs.append(check_debugger_performance.method_calls_with_exception_breakpoint())
|
||||
msgs.append(check_debugger_performance.global_scope_1_with_breakpoint())
|
||||
msgs.append(check_debugger_performance.global_scope_2_with_breakpoint())
|
||||
|
||||
for msg in msgs:
|
||||
print(msg)
|
||||
|
||||
print('TotalTime for profile: %.2fs' % (time.time() - start_time,))
|
||||
@@ -0,0 +1,240 @@
|
||||
# Based on: https://github.com/ESSS/pytest-regressions (License: MIT)
|
||||
# Created copy because we need Python 2.6 which is not available on pytest-regressions.
|
||||
# Note: only used for testing.
|
||||
|
||||
# encoding: UTF-8
|
||||
import difflib
|
||||
import pytest
|
||||
import sys
|
||||
from functools import partial
|
||||
|
||||
if sys.version_info[0] <= 2:
|
||||
from pathlib2 import Path
|
||||
else:
|
||||
from pathlib import Path
|
||||
|
||||
FORCE_REGEN = False
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def original_datadir(request):
|
||||
# Method from: https://github.com/gabrielcnr/pytest-datadir
|
||||
# License: MIT
|
||||
import os.path
|
||||
return Path(os.path.splitext(request.module.__file__)[0])
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def datadir(original_datadir, tmpdir):
|
||||
# Method from: https://github.com/gabrielcnr/pytest-datadir
|
||||
# License: MIT
|
||||
import shutil
|
||||
result = Path(str(tmpdir.join(original_datadir.stem)))
|
||||
if original_datadir.is_dir():
|
||||
shutil.copytree(str(original_datadir), str(result))
|
||||
else:
|
||||
result.mkdir()
|
||||
return result
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def data_regression(datadir, original_datadir, request):
|
||||
return DataRegressionFixture(datadir, original_datadir, request)
|
||||
|
||||
|
||||
def check_text_files(obtained_fn, expected_fn, fix_callback=lambda x: x, encoding=None):
|
||||
"""
|
||||
Compare two files contents. If the files differ, show the diff and write a nice HTML
|
||||
diff file into the data directory.
|
||||
:param Path obtained_fn: path to obtained file during current testing.
|
||||
:param Path expected_fn: path to the expected file, obtained from previous testing.
|
||||
:param str encoding: encoding used to open the files.
|
||||
:param callable fix_callback:
|
||||
A callback to "fix" the contents of the obtained (first) file.
|
||||
This callback receives a list of strings (lines) and must also return a list of lines,
|
||||
changed as needed.
|
||||
The resulting lines will be used to compare with the contents of expected_fn.
|
||||
"""
|
||||
__tracebackhide__ = True
|
||||
|
||||
obtained_fn = Path(obtained_fn)
|
||||
expected_fn = Path(expected_fn)
|
||||
obtained_lines = fix_callback(obtained_fn.read_text(encoding=encoding).splitlines())
|
||||
expected_lines = expected_fn.read_text(encoding=encoding).splitlines()
|
||||
|
||||
if obtained_lines != expected_lines:
|
||||
diff_lines = list(difflib.unified_diff(expected_lines, obtained_lines))
|
||||
if len(diff_lines) <= 500:
|
||||
html_fn = obtained_fn.with_suffix(".diff.html")
|
||||
try:
|
||||
differ = difflib.HtmlDiff()
|
||||
html_diff = differ.make_file(
|
||||
fromlines=expected_lines,
|
||||
fromdesc=expected_fn,
|
||||
tolines=obtained_lines,
|
||||
todesc=obtained_fn,
|
||||
)
|
||||
except Exception as e:
|
||||
html_fn = "(failed to generate html diff: %s)" % e
|
||||
else:
|
||||
html_fn.write_text(html_diff, encoding="UTF-8")
|
||||
|
||||
diff = ["FILES DIFFER:", str(expected_fn), str(obtained_fn)]
|
||||
diff += ["HTML DIFF: %s" % html_fn]
|
||||
diff += diff_lines
|
||||
raise AssertionError("\n".join(diff))
|
||||
else:
|
||||
# difflib has exponential scaling and for thousands of lines it starts to take minutes to render
|
||||
# the HTML diff.
|
||||
msg = [
|
||||
"Files are different, but diff is too big (%s lines)" % (len(diff_lines),),
|
||||
"- obtained: %s" % (obtained_fn,),
|
||||
"- expected: %s" % (expected_fn,),
|
||||
]
|
||||
raise AssertionError("\n".join(msg))
|
||||
|
||||
|
||||
def perform_regression_check(
|
||||
datadir,
|
||||
original_datadir,
|
||||
request,
|
||||
check_fn,
|
||||
dump_fn,
|
||||
extension,
|
||||
basename=None,
|
||||
fullpath=None,
|
||||
obtained_filename=None,
|
||||
dump_aux_fn=lambda filename: [],
|
||||
):
|
||||
"""
|
||||
First run of this check will generate a expected file. Following attempts will always try to
|
||||
match obtained files with that expected file.
|
||||
:param Path datadir: Fixture embed_data.
|
||||
:param Path original_datadir: Fixture embed_data.
|
||||
:param SubRequest request: Pytest request object.
|
||||
:param callable check_fn: A function that receives as arguments, respectively, absolute path to
|
||||
obtained file and absolute path to expected file. It must assert if contents of file match.
|
||||
Function can safely assume that obtained file is already dumped and only care about
|
||||
comparison.
|
||||
:param callable dump_fn: A function that receive an absolute file path as argument. Implementor
|
||||
must dump file in this path.
|
||||
:param callable dump_aux_fn: A function that receives the same file path as ``dump_fn``, but may
|
||||
dump additional files to help diagnose this regression later (for example dumping image of
|
||||
3d views and plots to compare later). Must return the list of file names written (used to display).
|
||||
:param six.text_type extension: Extension of files compared by this check.
|
||||
:param six.text_type obtained_filename: complete path to use to write the obtained file. By
|
||||
default will prepend `.obtained` before the file extension.
|
||||
..see: `data_regression.Check` for `basename` and `fullpath` arguments.
|
||||
"""
|
||||
import re
|
||||
|
||||
assert not (basename and fullpath), "pass either basename or fullpath, but not both"
|
||||
|
||||
__tracebackhide__ = True
|
||||
|
||||
if basename is None:
|
||||
basename = re.sub(r"[\W]", "_", request.node.name)
|
||||
|
||||
if fullpath:
|
||||
filename = source_filename = Path(fullpath)
|
||||
else:
|
||||
filename = datadir / (basename + extension)
|
||||
source_filename = original_datadir / (basename + extension)
|
||||
|
||||
def make_location_message(banner, filename, aux_files):
|
||||
msg = [banner, "- %s" % (filename,)]
|
||||
if aux_files:
|
||||
msg.append("Auxiliary:")
|
||||
msg += ["- %s" % (x,) for x in aux_files]
|
||||
return "\n".join(msg)
|
||||
|
||||
if not filename.is_file():
|
||||
source_filename.parent.mkdir(parents=True, exist_ok=True)
|
||||
dump_fn(source_filename)
|
||||
aux_created = dump_aux_fn(source_filename)
|
||||
|
||||
msg = make_location_message(
|
||||
"File not found in data directory, created:", source_filename, aux_created
|
||||
)
|
||||
pytest.fail(msg)
|
||||
else:
|
||||
if obtained_filename is None:
|
||||
if fullpath:
|
||||
obtained_filename = (datadir / basename).with_suffix(
|
||||
".obtained" + extension
|
||||
)
|
||||
else:
|
||||
obtained_filename = filename.with_suffix(".obtained" + extension)
|
||||
|
||||
dump_fn(obtained_filename)
|
||||
|
||||
try:
|
||||
check_fn(obtained_filename, filename)
|
||||
except AssertionError:
|
||||
if FORCE_REGEN:
|
||||
dump_fn(source_filename)
|
||||
aux_created = dump_aux_fn(source_filename)
|
||||
msg = make_location_message(
|
||||
"Files differ and FORCE_REGEN set, regenerating file at:",
|
||||
source_filename,
|
||||
aux_created,
|
||||
)
|
||||
pytest.fail(msg)
|
||||
else:
|
||||
dump_aux_fn(obtained_filename)
|
||||
raise
|
||||
|
||||
|
||||
class DataRegressionFixture(object):
|
||||
"""
|
||||
Implementation of `data_regression` fixture.
|
||||
"""
|
||||
|
||||
def __init__(self, datadir, original_datadir, request):
|
||||
"""
|
||||
:type datadir: Path
|
||||
:type original_datadir: Path
|
||||
:type request: FixtureRequest
|
||||
"""
|
||||
self.request = request
|
||||
self.datadir = datadir
|
||||
self.original_datadir = original_datadir
|
||||
|
||||
def check(self, data_dict, basename=None, fullpath=None):
|
||||
"""
|
||||
Checks the given dict against a previously recorded version, or generate a new file.
|
||||
:param dict data_dict: any yaml serializable dict.
|
||||
:param str basename: basename of the file to test/record. If not given the name
|
||||
of the test is used.
|
||||
Use either `basename` or `fullpath`.
|
||||
:param str fullpath: complete path to use as a reference file. This option
|
||||
will ignore ``datadir`` fixture when reading *expected* files but will still use it to
|
||||
write *obtained* files. Useful if a reference file is located in the session data dir for example.
|
||||
``basename`` and ``fullpath`` are exclusive.
|
||||
"""
|
||||
__tracebackhide__ = True
|
||||
|
||||
def dump(filename):
|
||||
"""Dump dict contents to the given filename"""
|
||||
import json
|
||||
|
||||
s = json.dumps(data_dict, sort_keys=True, indent=4)
|
||||
if isinstance(s, bytes):
|
||||
s = s.decode('utf-8')
|
||||
|
||||
s = u'\n'.join([line.rstrip() for line in s.splitlines()])
|
||||
s = s.encode('utf-8')
|
||||
|
||||
with filename.open("wb") as f:
|
||||
f.write(s)
|
||||
|
||||
perform_regression_check(
|
||||
datadir=self.datadir,
|
||||
original_datadir=self.original_datadir,
|
||||
request=self.request,
|
||||
check_fn=partial(check_text_files, encoding="UTF-8"),
|
||||
dump_fn=dump,
|
||||
extension=".json",
|
||||
basename=basename,
|
||||
fullpath=fullpath,
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
def call_me_back1(callback):
|
||||
a = 'other'
|
||||
callback()
|
||||
return a
|
||||
@@ -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')
|
||||
+268
@@ -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!')
|
||||
+11
@@ -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!')
|
||||
+47
@@ -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')
|
||||
+17
@@ -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')
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
def Call():
|
||||
for i in range(10): # break here
|
||||
last_i = i
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Call()
|
||||
print('TEST SUCEEDED!')
|
||||
+15
@@ -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!')
|
||||
|
||||
+14
@@ -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!')
|
||||
|
||||
+12
@@ -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
|
||||
+100
@@ -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')
|
||||
+23
@@ -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')
|
||||
+14
@@ -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')
|
||||
+72
@@ -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!')
|
||||
+11
@@ -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!')
|
||||
+13
@@ -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()
|
||||
+18
@@ -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
|
||||
+16
@@ -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!')
|
||||
+14
@@ -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!')
|
||||
+13
@@ -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!')
|
||||
+26
@@ -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!')
|
||||
+21
@@ -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')
|
||||
+21
@@ -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')
|
||||
+16
@@ -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')
|
||||
+26
@@ -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!')
|
||||
+51
@@ -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!')
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class MyClass(object):
|
||||
|
||||
def __getattribute__(self, attr):
|
||||
raise RuntimeError()
|
||||
|
||||
|
||||
obj = MyClass()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('TEST SUCEEDED') # break here
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user