33import os
44import pdb
55import re
6- import warnings
76from pathlib import Path
87from textwrap import dedent , indent
9- from typing import Generator , List , Optional , Tuple , Type
8+ from typing import Generator , List , Optional , Tuple
109
1110from .ansi import isatty , sformat
1211from .prettier import PrettyFormat , env_true
@@ -57,13 +56,14 @@ class DebugOutput:
5756 Represents the output of a debug command.
5857 """
5958 arg_class = DebugArgument
60- __slots__ = 'filename' , 'lineno' , 'frame' , 'arguments'
59+ __slots__ = 'filename' , 'lineno' , 'frame' , 'arguments' , 'warning'
6160
62- def __init__ (self , * , filename : str , lineno : int , frame : str , arguments : List [DebugArgument ]):
61+ def __init__ (self , * , filename : str , lineno : int , frame : str , arguments : List [DebugArgument ], warning = None ):
6362 self .filename = filename
6463 self .lineno = lineno
6564 self .frame = frame
6665 self .arguments = arguments
66+ self .warning = warning
6767
6868 def str (self , highlight = False ) -> str :
6969 if highlight :
@@ -72,8 +72,12 @@ def str(self, highlight=False) -> str:
7272 sformat (self .lineno , sformat .green ),
7373 sformat (self .frame , sformat .green , sformat .italic )
7474 )
75+ if self .warning :
76+ prefix += sformat (' ({})' .format (self .warning ), sformat .dim )
7577 else :
7678 prefix = '{0.filename}:{0.lineno} {0.frame}' .format (self )
79+ if self .warning :
80+ prefix += ' ({})' .format (self .warning )
7781 return prefix + '\n ' + '\n ' .join (a .str (highlight ) for a in self .arguments )
7882
7983 def __str__ (self ) -> str :
@@ -127,15 +131,15 @@ def _process(self, args, kwargs, func_regex) -> DebugOutput:
127131 curframe = inspect .currentframe ()
128132 try :
129133 frames = inspect .getouterframes (curframe , context = self ._frame_context_length )
130- except IndexError as e :
134+ except IndexError :
131135 # NOTICE: we should really catch all conceivable errors here, if you find one please report.
132136 # IndexError happens in odd situations such as code called from within jinja templates
133- self ._warn ('error parsing code, {0.__class__.__name__}: {0}' .format (e ), SyntaxWarning )
134137 return self .output_class (
135138 filename = '<unknown>' ,
136139 lineno = 0 ,
137140 frame = '' ,
138- arguments = list (self ._args_inspection_failed (args , kwargs ))
141+ arguments = list (self ._args_inspection_failed (args , kwargs )),
142+ warning = self ._show_warnings and 'error parsing code, IndexError' ,
139143 )
140144 # BEWARE: this must be called by a method which in turn is called "directly" for the frame to be correct
141145 call_frame = frames [2 ]
@@ -150,22 +154,23 @@ def _process(self, args, kwargs, func_regex) -> DebugOutput:
150154 pass
151155
152156 if call_frame .code_context :
153- func_ast , code_lines , lineno = self ._parse_code (call_frame , func_regex , filename )
157+ func_ast , code_lines , lineno , warning = self ._parse_code (call_frame , func_regex , filename )
154158 if func_ast :
155159 arguments = list (self ._process_args (func_ast , code_lines , args , kwargs ))
156160 else :
157161 # parsing failed
158162 arguments = list (self ._args_inspection_failed (args , kwargs ))
159163 else :
160164 lineno = call_frame .lineno
161- self . _warn ( 'no code context for debug call, code inspection impossible' )
165+ warning = 'no code context for debug call, code inspection impossible'
162166 arguments = list (self ._args_inspection_failed (args , kwargs ))
163167
164168 return self .output_class (
165169 filename = filename ,
166170 lineno = lineno ,
167171 frame = call_frame .function ,
168- arguments = arguments
172+ arguments = arguments ,
173+ warning = self ._show_warnings and warning ,
169174 )
170175
171176 def _args_inspection_failed (self , args , kwargs ):
@@ -206,17 +211,22 @@ def _process_args(self, func_ast, code_lines, args, kwargs) -> Generator[DebugAr
206211 for name , value in kwargs .items ():
207212 yield self .output_class .arg_class (value , name = name , variable = kw_arg_names .get (name ))
208213
209- def _parse_code (self , call_frame , func_regex , filename ) -> Tuple [Optional [ast .AST ], Optional [List [str ]], int ]:
214+ def _parse_code (
215+ self , call_frame , func_regex , filename
216+ ) -> Tuple [Optional [ast .AST ], Optional [List [str ]], int , Optional [str ]]:
210217 call_lines = []
211218 for line in range (call_frame .index , - 1 , - 1 ):
212- new_line = call_frame .code_context [line ]
219+ try :
220+ new_line = call_frame .code_context [line ]
221+ except IndexError : # pragma: no cover
222+ return None , None , line , 'error passing code. line not found'
213223 call_lines .append (new_line )
214224 if re .search (func_regex , new_line ):
215225 break
216226 call_lines .reverse ()
217227 lineno = call_frame .lineno - len (call_lines ) + 1
218228
219- original_code = code = dedent ('' .join (call_lines ))
229+ code = dedent ('' .join (call_lines ))
220230 func_ast = None
221231 tail_index = call_frame .index
222232 try :
@@ -238,18 +248,16 @@ def _parse_code(self, call_frame, func_regex, filename) -> Tuple[Optional[ast.AS
238248 break
239249
240250 if not func_ast :
241- self ._warn ('error passing code:\n "{}"\n Error: {}' .format (original_code , e1 ), SyntaxWarning )
242- return None , None , lineno
251+ return None , None , lineno , 'error passing code. Error: {}' .format (e1 )
243252
244253 if not isinstance (func_ast , ast .Call ):
245- self ._warn ('error passing code, found {} not Call' .format (func_ast .__class__ ), SyntaxWarning )
246- return None , None , lineno
254+ return None , None , lineno , 'error passing code, found {} not Call' .format (func_ast .__class__ )
247255
248256 code_lines = [l for l in code .split ('\n ' ) if l ]
249257 # this removes the trailing bracket from the lines of code meaning it doesn't appear in the
250258 # representation of the last argument
251259 code_lines [- 1 ] = code_lines [- 1 ][:- 1 ]
252- return func_ast , code_lines , lineno
260+ return func_ast , code_lines , lineno , None
253261
254262 @staticmethod
255263 def _wrap_parse (code , filename ):
@@ -271,9 +279,5 @@ def _get_offsets(func_ast):
271279 for kw in func_ast .keywords :
272280 yield kw .value .lineno - 2 , kw .value .col_offset - len (kw .arg ) - 2
273281
274- def _warn (self , msg , category : Type [Warning ] = RuntimeWarning ):
275- if self ._show_warnings :
276- warnings .warn (msg , category )
277-
278282
279283debug = Debug ()
0 commit comments