2222from inspect import currentframe , ismodule
2323from tempfile import NamedTemporaryFile
2424from types import CodeType
25+ from typing import Optional
2526
2627import pyficache
2728
@@ -104,8 +105,8 @@ def print_source_location_info(
104105 fn_name = None ,
105106 f_lasti = None ,
106107 remapped_file = None ,
107- remapped_line_number : int = - 1 ,
108- remapped_column_number : int = - 1 ,
108+ remapped_line_number : int = - 1 ,
109+ remapped_column_number : int = - 1 ,
109110):
110111 """Print out a source location, e.g. the first line in
111112 line in:
@@ -154,7 +155,7 @@ def prefix_for_filename(deparsed_text: str) -> str:
154155 # check if it is blank and if so use other lines.
155156 for line in lines :
156157 if line :
157- cleaned_line = re .sub (r"[()'\"\s]" , "_" , line .strip ())
158+ cleaned_line = re .sub (r"[()<> '\"\s]" , "_" , line .strip ())
158159 return proc_obj ._saferepr (cleaned_line )[1 :- 1 ][:10 ]
159160 return "..."
160161
@@ -221,10 +222,12 @@ def prefix_for_source_text(source_text: str, maxwidth: int) -> str:
221222 if not (
222223 remapped_file := pyficache .main .code2tempfile .get (frame .f_code )
223224 ):
224- remapped_file = cmdfns .source_tempfile_remap (
225- "eval_string" ,
225+ remapped_file = create_tempfile_and_remap_filename (
226226 dbgr_obj .eval_string ,
227227 tempdir = proc_obj .settings ("tempdir" ),
228+ prefix = "eval_string" ,
229+ suffix = ".py" ,
230+ delete = False ,
228231 )
229232 # pyficache.remap_file(filename, remapped_file)
230233 pyficache .main .code2tempfile [frame .f_code ] = filename
@@ -270,8 +273,8 @@ def prefix_for_source_text(source_text: str, maxwidth: int) -> str:
270273 pass
271274 else :
272275 m = re .search ("^<frozen (.*)>" , filename )
273- if m and m .group (1 ) in pyficache .file2file_remap :
274- remapped_file = pyficache .file2file_remap [m . group ( 1 ) ]
276+ if m and ( frozen_name := m .group (1 ) ) in pyficache .file2file_remap :
277+ remapped_file = pyficache .file2file_remap [frozen_name ]
275278 pass
276279 elif filename in pyficache .file2file_remap :
277280 remapped_file = pyficache .file2file_remap [filename ]
@@ -281,10 +284,12 @@ def prefix_for_source_text(source_text: str, maxwidth: int) -> str:
281284 remapped_file = pyficache .remap_file_pat (
282285 filename , pyficache .main .remap_re_hash
283286 )
284- elif m and m .group (1 ) in sys .modules :
285- remapped_file = m .group (1 )
286- pyficache .remap_file (filename , remapped_file )
287- pass
287+ elif m and frozen_name in sys .modules :
288+ # try with good ol linecache and consider fixing pyficache
289+ remapped_file = sys .modules [frozen_name ].__file__
290+ pyficache .remap_file (remapped_file , filename )
291+ filename = remapped_file
292+ pass
288293
289294 opts = {
290295 "reload_on_change" : proc_obj .settings ("reload" ),
@@ -303,15 +308,18 @@ def prefix_for_source_text(source_text: str, maxwidth: int) -> str:
303308 if orig_line_number == 0 :
304309 line_number = 0
305310 line , remapped_line_number = pyficache .get_pyasm_line (
306- filename , line_number , is_source_line = True , offset = frame .f_lasti ,
311+ filename ,
312+ line_number ,
313+ is_source_line = True ,
314+ offset = frame .f_lasti ,
307315 )
308316 if remapped_line_number >= 0 :
309317 # FIXME: +1 is because getlines is 0 origin.
310318 remapped_line_number += 1
311319 if line is not None and opts ["style" ] not in ("plain" , "none" ):
312320 line = pyficache .highlight_string (
313- line , lexer = pyficache .pyasm_lexer , style = opts ["style" ]
314- )
321+ line , lexer = pyficache .pyasm_lexer , style = opts ["style" ]
322+ )
315323 if line .endswith ("\n " ):
316324 line = line [:- 1 ]
317325
@@ -349,19 +357,17 @@ def prefix_for_source_text(source_text: str, maxwidth: int) -> str:
349357 lines = linecache .getlines (filename )
350358 temp_name = filename
351359 if lines and not pyficache .is_python_assembly_file (filename ):
352- # FIXME: DRY code with version in cmdproc.py print_location
360+ ####
353361 prefix = osp .basename (temp_name ).split ("." )[0 ] + "-"
354- fd = NamedTemporaryFile (
355- suffix = ".py" ,
356- prefix = prefix ,
357- delete = False ,
358- dir = proc_obj .settings ("tempdir" ),
362+ text = "\n " .join (lines )
363+ create_tempfile_and_remap_filename (
364+ text ,
365+ filename = filename ,
366+ tempdir = proc_obj .settings ("tempdir" ),
367+ prefix = ".py" ,
368+ delete = False
359369 )
360- with fd :
361- fd .write ("\n " .join (lines ).encode ("utf-8" ))
362- remapped_file = fd .name
363- pyficache .remap_file (remapped_file , filename )
364- fd .close ()
370+ #####
365371 if source_text :
366372 pyficache .main .code2tempfile [frame .f_code ] = remapped_file
367373 intf_obj .msg (
@@ -452,9 +458,59 @@ def prefix_for_source_text(source_text: str, maxwidth: int) -> str:
452458 return True
453459
454460
461+ def create_tempfile_and_remap_filename (
462+ text : str ,
463+ filename : str ,
464+ tempdir : str ,
465+ prefix : Optional [str ] = None ,
466+ suffix : str = ".py" ,
467+ delete = False ,
468+ ) -> str :
469+ """
470+ Using `lines` associated with `filename`, create a temporary filename
471+ using `prefix` in directory `tempdir`.
472+
473+ `filename is typically the `co_filename` field inside a Python
474+ code object which is bogus. For example it might be <string> or <frozen runpy>
475+ or some valid filename that just does not exist in our environment.
476+
477+ Therefore we create file name in the filesystem an use pyfcache to
478+ remap that 'filename` to newly create filename with the contents given .
479+ """
480+
481+ # FIXME: DRY code with version in cmdproc.py print_location
482+ fd = NamedTemporaryFile (
483+ suffix = ".py" ,
484+ prefix = prefix ,
485+ delete = delete ,
486+ dir = tempdir ,
487+ )
488+ with fd :
489+ fd .write (bytes (text , "UTF-8" ))
490+ remapped_file = fd .name
491+ pyficache .remap_file (remapped_file , filename )
492+ fd .close ()
493+ pass
494+ return fd .name
495+
496+
455497# Demo it
456498if __name__ == "__main__" :
457499
500+ def inside_frozen ():
501+ from trepan .processor .cmdproc import CommandProcessor
502+ from trepan .processor .command .mock import MockDebugger
503+ from inspect import currentframe
504+ from trepan .processor .print import print_location
505+
506+ d = MockDebugger ()
507+ cmdproc = CommandProcessor (d .core )
508+ cmdproc .frame = currentframe ().f_back
509+ cmdproc .event = "call"
510+ cmdproc .setup ()
511+
512+ print_location (cmdproc )
513+
458514 def five ():
459515 from trepan .processor .cmdproc import CommandProcessor
460516 from trepan .processor .command .mock import MockDebugger
@@ -479,4 +535,8 @@ def five():
479535"""
480536 )
481537
538+ import runpy
539+
540+ runpy ._run_code (inside_frozen .__code__ , {}, None )
541+
482542 exec ("five()" )
0 commit comments