@@ -3093,8 +3093,7 @@ def _restore_cmd2_env(self, cmd2_env: _SavedCmd2Env) -> None:
30933093
30943094 # This is a hidden flag for telling do_py to run a pyscript. It is intended only to be used by run_pyscript
30953095 # after it sets up sys.argv for the script being run. When this flag is present, it takes precedence over all
3096- # other arguments. run_pyscript uses this method instead of "py run('file')" because file names with
3097- # 2 or more consecutive spaces cause issues with our parser, which isn't meant to parse Python statements.
3096+ # other arguments.
30983097 py_parser .add_argument ('--pyscript' , help = argparse .SUPPRESS )
30993098
31003099 # Preserve quotes since we are passing these strings to Python
@@ -3104,65 +3103,66 @@ def do_py(self, args: argparse.Namespace) -> Optional[bool]:
31043103 Enter an interactive Python shell
31053104 :return: True if running of commands should stop
31063105 """
3106+ def py_quit ():
3107+ """Function callable from the interactive Python console to exit that environment"""
3108+ raise EmbeddedConsoleExit
3109+
31073110 from .py_bridge import PyBridge
3111+ py_bridge = PyBridge (self )
3112+ saved_sys_path = None
3113+
31083114 if self .in_pyscript ():
31093115 err = "Recursively entering interactive Python consoles is not allowed."
31103116 self .perror (err )
31113117 return
31123118
3113- py_bridge = PyBridge (self )
3114- py_code_to_run = ''
3115-
3116- # Handle case where we were called by run_pyscript
3117- if args .pyscript :
3118- args .pyscript = utils .strip_quotes (args .pyscript )
3119-
3120- # Run the script - use repr formatting to escape things which
3121- # need to be escaped to prevent issues on Windows
3122- py_code_to_run = 'run({!r})' .format (args .pyscript )
3123-
3124- elif args .command :
3125- py_code_to_run = args .command
3126- if args .remainder :
3127- py_code_to_run += ' ' + ' ' .join (args .remainder )
3128-
3129- # Set cmd_echo to True so PyBridge statements like: py app('help')
3130- # run at the command line will print their output.
3131- py_bridge .cmd_echo = True
3132-
31333119 try :
31343120 self ._in_py = True
3121+ py_code_to_run = ''
31353122
3136- def py_run (filename : str ):
3137- """Run a Python script file in the interactive console.
3138- :param filename: filename of script file to run
3139- """
3140- expanded_filename = os .path .expanduser (filename )
3123+ # Locals for the Python environment we are creating
3124+ localvars = dict (self .py_locals )
3125+ localvars [self .py_bridge_name ] = py_bridge
3126+ localvars ['quit' ] = py_quit
3127+ localvars ['exit' ] = py_quit
3128+
3129+ if self .self_in_py :
3130+ localvars ['self' ] = self
3131+
3132+ # Handle case where we were called by run_pyscript
3133+ if args .pyscript :
3134+ # Read the script file
3135+ expanded_filename = os .path .expanduser (utils .strip_quotes (args .pyscript ))
31413136
31423137 try :
31433138 with open (expanded_filename ) as f :
3144- interp . runcode ( f .read () )
3139+ py_code_to_run = f .read ()
31453140 except OSError as ex :
31463141 self .pexcept ("Error reading script file '{}': {}" .format (expanded_filename , ex ))
3142+ return
31473143
3148- def py_quit ():
3149- """Function callable from the interactive Python console to exit that environment"""
3150- raise EmbeddedConsoleExit
3144+ localvars ['__name__' ] = '__main__'
3145+ localvars ['__file__' ] = expanded_filename
31513146
3152- # Set up Python environment
3153- self .py_locals [self .py_bridge_name ] = py_bridge
3154- self .py_locals ['run' ] = py_run
3155- self .py_locals ['quit' ] = py_quit
3156- self .py_locals ['exit' ] = py_quit
3147+ # Place the script's directory at sys.path[0] just as Python does when executing a script
3148+ saved_sys_path = list (sys .path )
3149+ sys .path .insert (0 , os .path .dirname (os .path .abspath (expanded_filename )))
31573150
3158- if self .self_in_py :
3159- self .py_locals ['self' ] = self
3160- elif 'self' in self .py_locals :
3161- del self .py_locals ['self' ]
3151+ else :
3152+ # This is the default name chosen by InteractiveConsole when no locals are passed in
3153+ localvars ['__name__' ] = '__console__'
3154+
3155+ if args .command :
3156+ py_code_to_run = args .command
3157+ if args .remainder :
3158+ py_code_to_run += ' ' + ' ' .join (args .remainder )
31623159
3163- localvars = self .py_locals
3160+ # Set cmd_echo to True so PyBridge statements like: py app('help')
3161+ # run at the command line will print their output.
3162+ py_bridge .cmd_echo = True
3163+
3164+ # Create the Python interpreter
31643165 interp = InteractiveConsole (locals = localvars )
3165- interp .runcode ('import sys, os;sys.path.insert(0, os.getcwd())' )
31663166
31673167 # Check if we are running Python code
31683168 if py_code_to_run :
@@ -3177,8 +3177,7 @@ def py_quit():
31773177 else :
31783178 cprt = 'Type "help", "copyright", "credits" or "license" for more information.'
31793179 instructions = ('End with `Ctrl-D` (Unix) / `Ctrl-Z` (Windows), `quit()`, `exit()`.\n '
3180- 'Non-Python commands can be issued with: {}("your command")\n '
3181- 'Run Python code from external script files with: run("script.py")'
3180+ 'Non-Python commands can be issued with: {}("your command")'
31823181 .format (self .py_bridge_name ))
31833182
31843183 saved_cmd2_env = None
@@ -3205,7 +3204,10 @@ def py_quit():
32053204 pass
32063205
32073206 finally :
3208- self ._in_py = False
3207+ with self .sigint_protection :
3208+ if saved_sys_path is not None :
3209+ sys .path = saved_sys_path
3210+ self ._in_py = False
32093211
32103212 return py_bridge .stop
32113213
0 commit comments