diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 804c4a4..52e7968 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -26,6 +26,7 @@ import codeop import inspect import os import re +import runpy import sys import tempfile import types @@ -2356,6 +2357,28 @@ class InteractiveShell(SingletonConfigurable, Magic): self.showtraceback() warn('Unknown failure executing file: <%s>' % fname) + def safe_run_module(self, mod_name, where): + """A safe version of runpy.run_module(). + + This version will never throw an exception, but instead print + helpful error messages to the screen. + + Parameters + ---------- + mod_name : string + The name of the module to be executed. + where : dict + The globals namespace. + """ + try: + where.update( + runpy.run_module(str(mod_name), run_name="__main__", + alter_sys=True) + ) + except: + self.showtraceback() + warn('Unknown failure executing module: <%s>' % mod_name) + def run_cell(self, raw_cell, store_history=False): """Run a complete IPython cell. diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index 6d90f52..9398518 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -103,6 +103,7 @@ shell_aliases = dict( logfile='InteractiveShell.logfile', logappend='InteractiveShell.logappend', c='InteractiveShellApp.code_to_run', + m='InteractiveShellApp.module_to_run', ext='InteractiveShellApp.extra_extension', ) shell_aliases['cache-size'] = 'InteractiveShell.cache_size' @@ -146,6 +147,9 @@ class InteractiveShellApp(Configurable): code_to_run = Unicode('', config=True, help="Execute the given command string." ) + module_to_run = Unicode('', config=True, + help="Run the module as a script." + ) pylab_import_all = Bool(True, config=True, help="""If true, an 'import *' is done from numpy and pylab, when using pylab""" @@ -183,6 +187,7 @@ class InteractiveShellApp(Configurable): self._run_exec_lines() self._run_exec_files() self._run_cmd_line_code() + self._run_module() # flush output, so itwon't be attached to the first cell sys.stdout.flush() @@ -294,3 +299,15 @@ class InteractiveShellApp(Configurable): fname) self.shell.showtraceback() + def _run_module(self): + """Run module specified at the command-line.""" + if self.module_to_run: + # Make sure that the module gets a proper sys.argv as if it were + # run using `python -m`. + save_argv = sys.argv + sys.argv = [sys.executable] + self.extra_args + try: + self.shell.safe_run_module(self.module_to_run, + self.shell.user_ns) + finally: + sys.argv = save_argv diff --git a/IPython/frontend/terminal/ipapp.py b/IPython/frontend/terminal/ipapp.py index abd4730..e13fbfc 100755 --- a/IPython/frontend/terminal/ipapp.py +++ b/IPython/frontend/terminal/ipapp.py @@ -265,13 +265,16 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): self.interact = True def _file_to_run_changed(self, name, old, new): + if new: + self.something_to_run = True if new and not self.force_interact: self.interact = False _code_to_run_changed = _file_to_run_changed + _module_to_run_changed = _file_to_run_changed # internal, not-configurable interact=Bool(True) - + something_to_run=Bool(False) def parse_command_line(self, argv=None): """override to allow old '-pylab' flag with deprecation warning""" @@ -306,7 +309,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): if not self.ignore_old_config: check_for_old_config(self.ipython_dir) # print self.extra_args - if self.extra_args: + if self.extra_args and not self.something_to_run: self.file_to_run = self.extra_args[0] # create the shell self.init_shell()