Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Commit

Permalink
Django 2.2 tests and fixes for exception breakpoints in Django 1.7. F…
Browse files Browse the repository at this point in the history
…ixes #1298, #1294
  • Loading branch information
fabioz committed Apr 4, 2019
1 parent ed8f980 commit 13f3f63
Show file tree
Hide file tree
Showing 14 changed files with 144 additions and 46 deletions.
4 changes: 2 additions & 2 deletions src/ptvsd/_vendored/pydevd/.travis_install_python_deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ fi

if [ "$PYDEVD_PYTHON_VERSION" = "3.6" ]; then
conda install --yes pyqt=5 gevent
pip install "django>=2.1,<2.2"
pip install "django>=2.2,<2.3"
fi

if [ "$PYDEVD_PYTHON_VERSION" = "3.7" ]; then
conda install --yes pyqt=5 matplotlib
# Note: track the latest django
pip install "django>=2.1,<2.2"
pip install "django"
fi

pip install untangle
Expand Down
35 changes: 26 additions & 9 deletions src/ptvsd/_vendored/pydevd/pydevd_plugins/django_debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,21 @@ def suspend(plugin, main_debugger, thread, frame, bp_type):
return None


def _get_filename_from_origin_in_parent_frame_locals(frame, parent_frame_name):
filename = None
parent_frame = frame
while parent_frame.f_code.co_name != parent_frame_name:
parent_frame = parent_frame.f_back

origin = None
if parent_frame is not None:
origin = parent_frame.f_locals.get('origin')

if hasattr(origin, 'name') and origin.name is not None:
filename = normcase(_convert_to_str(origin.name))
return filename


def exception_break(plugin, main_debugger, pydb_frame, frame, args, arg):
main_debugger = args[0]
thread = args[3]
Expand All @@ -479,19 +494,21 @@ def exception_break(plugin, main_debugger, pydb_frame, frame, args, arg):
# In this case we don't actually have a regular render frame with the context
# (we didn't really get to that point).
token = getattr(value, 'token', None)

if token is None:
# Django 1.7 does not have token in exception. Try to get it from locals.
token = frame.f_locals.get('token')

lineno = getattr(token, 'lineno', None)

filename = None
if lineno is not None:
get_template_frame = frame
while get_template_frame.f_code.co_name != 'get_template':
get_template_frame = get_template_frame.f_back

origin = None
if get_template_frame is not None:
origin = get_template_frame.f_locals.get('origin')
filename = _get_filename_from_origin_in_parent_frame_locals(frame, 'get_template')

if hasattr(origin, 'name') and origin.name is not None:
filename = normcase(_convert_to_str(origin.name))
if filename is None:
# Django 1.7 does not have origin in get_template. Try to get it from
# load_template.
filename = _get_filename_from_origin_in_parent_frame_locals(frame, 'load_template')

if filename is not None and lineno is not None:
syntax_error_frame = DjangoTemplateSyntaxErrorFrame(
Expand Down
23 changes: 21 additions & 2 deletions src/ptvsd/_vendored/pydevd/tests_python/debugger_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
CMD_ADD_EXCEPTION_BREAK

import sys
import time


def get_java_location():
Expand Down Expand Up @@ -134,6 +135,15 @@ def create_request_thread(self, url=''):

class T(threading.Thread):

def wait_for_contents(self):
for _ in range(10):
if hasattr(self, 'contents'):
break
time.sleep(.3)
else:
raise AssertionError('Django did not return contents properly!')
return self.contents

def run(self):
try:
from urllib.request import urlopen
Expand Down Expand Up @@ -203,6 +213,15 @@ def create_request_thread(self, uri):

class T(threading.Thread):

def wait_for_contents(self):
for _ in range(10):
if hasattr(self, 'contents'):
break
time.sleep(.3)
else:
raise AssertionError('Django did not return contents properly!')
return self.contents

def run(self):
try:
from urllib.request import urlopen
Expand Down Expand Up @@ -442,10 +461,10 @@ def test_file(self, **kwargs):
version = [int(x) for x in django.get_version().split('.')][:2]
if version == [1, 7]:
django_folder = 'my_django_proj_17'
elif version == [2, 1]:
elif version in ([2, 1], [2, 2]):
django_folder = 'my_django_proj_21'
else:
raise AssertionError('Can only check django 1.7 and 2.1 right now. Found: %s' % (version,))
raise AssertionError('Can only check django 1.7, 2.1 and 2.2 right now. Found: %s' % (version,))

WriterThread.DJANGO_FOLDER = django_folder
for key, value in kwargs.items():
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% if chat_mode %}
"chat_mode=True"
{% else %}
"chat_mode=False"
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% include 'my_app/inherited.html' with chat_mode=True %}
{% include 'my_app/inherited.html' with chat_mode=False %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% if entries %}
<ul>
{% for entry in entries %}
<li>
{{ entry.key }}
:
{{ entry.invalid_attribute }}
</li>
{% endfor %}
</ul>
{% else %}
<p>No entries are available.</p>
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
{% doesnotexist %}
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@
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'),
]
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import sys
from .forms import NameForm


class Entry(object):

def __init__(self, key, val):
Expand All @@ -17,13 +18,15 @@ def __unicode__(self):
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':
Expand All @@ -38,6 +41,27 @@ def get_name(request):

# if a GET (or any other method) we'll create a blank form
else:
form = NameForm(data= {'your_name': 'unknown name'})
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


return render(request, 'my_app/name.html', {'form': form})
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% if chat_mode %}
"chat_mode=True"
{% else %}
"chat_mode=False"
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% include 'my_app/inherited.html' with chat_mode=True %}
{% include 'my_app/inherited.html' with chat_mode=False %}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
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'),
]
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,9 @@ def template_error2(request):
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
55 changes: 25 additions & 30 deletions src/ptvsd/_vendored/pydevd/tests_python/test_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -870,15 +870,10 @@ def test_case_flask(case_setup_flask):
writer.wait_for_vars(['<var name="content" type="str"'])
writer.write_run_thread(hit.thread_id)

for _ in xrange(10):
if hasattr(t, 'contents'):
break
time.sleep(.3)
else:
raise AssertionError('Flask did not return contents properly!')
contents = t.wait_for_contents()

assert '<title>Hello</title>' in t.contents
assert 'Flask-Jinja-Test' in t.contents
assert '<title>Hello</title>' in contents
assert 'Flask-Jinja-Test' in contents

writer.finished_ok = True

Expand Down Expand Up @@ -919,14 +914,9 @@ def get_environ(writer):

writer.write_run_thread(hit.thread_id)

for _ in xrange(10):
if hasattr(t, 'contents'):
break
time.sleep(.3)
else:
raise AssertionError('Django did not return contents properly!')
contents = t.wait_for_contents()

contents = t.contents.replace(' ', '').replace('\r', '').replace('\n', '')
contents = contents.replace(' ', '').replace('\r', '').replace('\n', '')
if contents != '<ul><li>v1:v1</li><li>v2:v2</li></ul>':
raise AssertionError('%s != <ul><li>v1:v1</li><li>v2:v2</li></ul>' % (contents,))

Expand Down Expand Up @@ -954,13 +944,28 @@ def test_case_django_b(case_setup_django):


@pytest.mark.skipif(not TEST_DJANGO, reason='No django available')
@pytest.mark.parametrize("jmc", [False, True])
def test_case_django_no_attribute_exception_breakpoint(case_setup_django, jmc):
django_version = [int(x) for x in django.get_version().split('.')][:2]
def test_case_django_template_inherits_no_exception(case_setup_django):
with case_setup_django.test_file(EXPECTED_RETURNCODE='any') as writer:

# Check that it doesn't have issues with inherits + django exception breakpoints.
writer.write_add_exception_breakpoint_django()

writer.write_make_initial_run()

t = writer.create_request_thread('my_app/inherits')
time.sleep(5) # Give django some time to get to startup before requesting the page
t.start()
contents = t.wait_for_contents()

contents = contents.replace(' ', '').replace('\r', '').replace('\n', '')
assert contents == '''"chat_mode=True""chat_mode=False"'''

writer.finished_ok = True

if django_version < [2, 1]:
pytest.skip('Template exceptions only supporting Django 2.1 onwards.')

@pytest.mark.skipif(not TEST_DJANGO, reason='No django available')
@pytest.mark.parametrize("jmc", [False, True])
def test_case_django_no_attribute_exception_breakpoint(case_setup_django, jmc):
kwargs = {}
if jmc:

Expand Down Expand Up @@ -993,11 +998,6 @@ def get_environ(writer):

@pytest.mark.skipif(not TEST_DJANGO, reason='No django available')
def test_case_django_no_attribute_exception_breakpoint_and_regular_exceptions(case_setup_django):
django_version = [int(x) for x in django.get_version().split('.')][:2]

if django_version < [2, 1]:
pytest.skip('Template exceptions only supporting Django 2.1 onwards.')

with case_setup_django.test_file(EXPECTED_RETURNCODE='any') as writer:
writer.write_add_exception_breakpoint_django()

Expand Down Expand Up @@ -1026,11 +1026,6 @@ def test_case_django_no_attribute_exception_breakpoint_and_regular_exceptions(ca
@pytest.mark.skipif(not TEST_DJANGO, reason='No django available')
@pytest.mark.parametrize("jmc", [False, True])
def test_case_django_invalid_template_exception_breakpoint(case_setup_django, jmc):
django_version = [int(x) for x in django.get_version().split('.')][:2]

if django_version < [2, 1]:
pytest.skip('Template exceptions only supporting Django 2.1 onwards.')

kwargs = {}
if jmc:

Expand Down

0 comments on commit 13f3f63

Please sign in to comment.