@@ -3561,6 +3561,24 @@ def _assert_find_function(self, file_content, func_name, expected):
35613561 self .assertEqual (
35623562 expected , pdb .find_function (func_name , os_helper .TESTFN ))
35633563
3564+ def _fd_dir_for_pipe_targets (self ):
3565+ """Return a directory exposing live file descriptors, if any."""
3566+ proc_fd = "/proc/self/fd"
3567+ if os .path .isdir (proc_fd ) and os .path .exists (os .path .join (proc_fd , '0' )):
3568+ return proc_fd
3569+
3570+ dev_fd = "/dev/fd"
3571+ if os .path .isdir (dev_fd ) and os .path .exists (os .path .join (dev_fd , '0' )):
3572+ if sys .platform .startswith ("freebsd" ):
3573+ try :
3574+ if os .stat ("/dev" ).st_dev == os .stat (dev_fd ).st_dev :
3575+ return None
3576+ except FileNotFoundError :
3577+ return None
3578+ return dev_fd
3579+
3580+ return None
3581+
35643582 def test_find_function_empty_file (self ):
35653583 self ._assert_find_function (b'' , 'foo' , None )
35663584
@@ -3633,6 +3651,42 @@ def test_spec(self):
36333651 stdout , _ = self .run_pdb_script (script , commands )
36343652 self .assertIn ('None' , stdout )
36353653
3654+ def test_script_target_anonymous_pipe (self ):
3655+ fd_dir = self ._fd_dir_for_pipe_targets ()
3656+ if fd_dir is None :
3657+ self .skipTest ('anonymous pipe targets require /proc/self/fd or /dev/fd' )
3658+
3659+ read_fd , write_fd = os .pipe ()
3660+
3661+ def safe_close (fd ):
3662+ try :
3663+ os .close (fd )
3664+ except OSError :
3665+ pass
3666+
3667+ self .addCleanup (safe_close , read_fd )
3668+ self .addCleanup (safe_close , write_fd )
3669+
3670+ pipe_path = os .path .join (fd_dir , str (read_fd ))
3671+ if not os .path .exists (pipe_path ):
3672+ self .skipTest ('fd directory does not expose anonymous pipes' )
3673+
3674+ script_source = 'marker = "via_pipe"\n '
3675+ os .write (write_fd , script_source .encode ('utf-8' ))
3676+ os .close (write_fd )
3677+
3678+ original_path0 = sys .path [0 ]
3679+ self .addCleanup (sys .path .__setitem__ , 0 , original_path0 )
3680+
3681+ target = pdb ._ScriptTarget (pipe_path )
3682+ code_text = target .code
3683+ namespace = target .namespace
3684+ exec (code_text , namespace )
3685+
3686+ self .assertEqual (namespace ['marker' ], 'via_pipe' )
3687+ self .assertEqual (namespace ['__file__' ], target .filename )
3688+ self .assertIsNone (namespace ['__spec__' ])
3689+
36363690 def test_find_function_first_executable_line (self ):
36373691 code = textwrap .dedent ("""\
36383692 def foo(): pass
0 commit comments