| Tor Norbye | 3a2425a | 2013-11-04 10:16:08 -0800 | [diff] [blame^] | 1 | import inspect |
| 2 | from django_frame import DjangoTemplateFrame, get_template_file_name, get_template_line |
| 3 | from pydevd_comm import CMD_SET_BREAK |
| 4 | from pydevd_constants import DJANGO_SUSPEND, GetThreadId |
| 5 | from pydevd_file_utils import NormFileToServer |
| 6 | from runfiles import DictContains |
| 7 | from pydevd_breakpoints import LineBreakpoint |
| 8 | import pydevd_vars |
| 9 | import traceback |
| 10 | |
| 11 | class DjangoLineBreakpoint(LineBreakpoint): |
| 12 | def __init__(self, type, file, line, flag, condition, func_name, expression): |
| 13 | self.file = file |
| 14 | self.line = line |
| 15 | LineBreakpoint.__init__(self, type, flag, condition, func_name, expression) |
| 16 | |
| 17 | def __eq__(self, other): |
| 18 | if not isinstance(other, DjangoLineBreakpoint): |
| 19 | return False |
| 20 | return self.file == other.file and self.line == other.line |
| 21 | |
| 22 | def is_triggered(self, frame): |
| 23 | file = get_template_file_name(frame) |
| 24 | line = get_template_line(frame) |
| 25 | return self.file == file and self.line == line |
| 26 | |
| 27 | def __str__(self): |
| 28 | return "DjangoLineBreakpoint: %s-%d" %(self.file, self.line) |
| 29 | |
| 30 | |
| 31 | def inherits(cls, *names): |
| 32 | if cls.__name__ in names: |
| 33 | return True |
| 34 | inherits_node = False |
| 35 | for base in inspect.getmro(cls): |
| 36 | if base.__name__ in names: |
| 37 | inherits_node = True |
| 38 | break |
| 39 | return inherits_node |
| 40 | |
| 41 | |
| 42 | def is_django_render_call(frame): |
| 43 | try: |
| 44 | name = frame.f_code.co_name |
| 45 | if name != 'render': |
| 46 | return False |
| 47 | |
| 48 | if not DictContains(frame.f_locals, 'self'): |
| 49 | return False |
| 50 | |
| 51 | cls = frame.f_locals['self'].__class__ |
| 52 | |
| 53 | inherits_node = inherits(cls, 'Node') |
| 54 | |
| 55 | if not inherits_node: |
| 56 | return False |
| 57 | |
| 58 | clsname = cls.__name__ |
| 59 | return clsname != 'TextNode' and clsname != 'NodeList' |
| 60 | except: |
| 61 | traceback.print_exc() |
| 62 | return False |
| 63 | |
| 64 | |
| 65 | def is_django_context_get_call(frame): |
| 66 | try: |
| 67 | if not DictContains(frame.f_locals, 'self'): |
| 68 | return False |
| 69 | |
| 70 | cls = frame.f_locals['self'].__class__ |
| 71 | |
| 72 | return inherits(cls, 'BaseContext') |
| 73 | except: |
| 74 | traceback.print_exc() |
| 75 | return False |
| 76 | |
| 77 | |
| 78 | def is_django_resolve_call(frame): |
| 79 | try: |
| 80 | name = frame.f_code.co_name |
| 81 | if name != '_resolve_lookup': |
| 82 | return False |
| 83 | |
| 84 | if not DictContains(frame.f_locals, 'self'): |
| 85 | return False |
| 86 | |
| 87 | cls = frame.f_locals['self'].__class__ |
| 88 | |
| 89 | clsname = cls.__name__ |
| 90 | return clsname == 'Variable' |
| 91 | except: |
| 92 | traceback.print_exc() |
| 93 | return False |
| 94 | |
| 95 | |
| 96 | def is_django_suspended(thread): |
| 97 | return thread.additionalInfo.suspend_type == DJANGO_SUSPEND |
| 98 | |
| 99 | |
| 100 | def suspend_django(py_db_frame, mainDebugger, thread, frame, cmd=CMD_SET_BREAK): |
| 101 | frame = DjangoTemplateFrame(frame) |
| 102 | |
| 103 | if frame.f_lineno is None: |
| 104 | return None |
| 105 | |
| 106 | #try: |
| 107 | # if thread.additionalInfo.filename == frame.f_code.co_filename and thread.additionalInfo.line == frame.f_lineno: |
| 108 | # return None # don't stay twice on the same line |
| 109 | #except AttributeError: |
| 110 | # pass |
| 111 | |
| 112 | pydevd_vars.addAdditionalFrameById(GetThreadId(thread), {id(frame): frame}) |
| 113 | |
| 114 | py_db_frame.setSuspend(thread, cmd) |
| 115 | thread.additionalInfo.suspend_type = DJANGO_SUSPEND |
| 116 | |
| 117 | thread.additionalInfo.filename = frame.f_code.co_filename |
| 118 | thread.additionalInfo.line = frame.f_lineno |
| 119 | |
| 120 | return frame |
| 121 | |
| 122 | |
| 123 | def find_django_render_frame(frame): |
| 124 | while frame is not None and not is_django_render_call(frame): |
| 125 | frame = frame.f_back |
| 126 | |
| 127 | return frame |
| 128 | |
| 129 | |
| 130 | |
| 131 | |
| 132 | |