diff --git a/IPython/config/loader.py b/IPython/config/loader.py index aae5b02..433c076 100644 --- a/IPython/config/loader.py +++ b/IPython/config/loader.py @@ -275,6 +275,12 @@ class ArgParseConfigLoader(CommandLineConfigLoader): self._convert_to_config() return self.config + def get_extra_args(self): + if hasattr(self, 'extra_args'): + return self.extra_args + else: + return [] + def _create_parser(self): self.parser = argparse.ArgumentParser(*self.args, **self.kw) self._add_arguments() @@ -292,9 +298,9 @@ class ArgParseConfigLoader(CommandLineConfigLoader): def _parse_args(self, args=None): """self.parser->self.parsed_data""" if args is None: - self.parsed_data = self.parser.parse_args() + self.parsed_data, self.extra_args = self.parser.parse_known_args() else: - self.parsed_data = self.parser.parse_args(args) + self.parsed_data, self.extra_args = self.parser.parse_known_args(args) def _convert_to_config(self): """self.parsed_data->self.config""" diff --git a/IPython/core/application.py b/IPython/core/application.py index 90b2f40..a7e961a 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -117,7 +117,14 @@ class Application(object): #------------------------------------------------------------------------- def create_default_config(self): - """Create defaults that can't be set elsewhere.""" + """Create defaults that can't be set elsewhere. + + For the most part, we try to set default in the class attributes + of Components. But, defaults the top-level Application (which is + not a HasTraitlets or Component) are not set in this way. Instead + we set them here. The Global section is for variables like this that + don't belong to a particular component. + """ self.default_config = Config() self.default_config.Global.ipythondir = get_ipython_dir() self.log.debug('Default config loaded:') @@ -139,6 +146,7 @@ class Application(object): loader = self.create_command_line_config() self.command_line_config = loader.load_config() + self.extra_args = loader.get_extra_args() try: self.log_level = self.command_line_config.Global.log_level diff --git a/IPython/core/ipapp.py b/IPython/core/ipapp.py index a61abcf..cb67ad4 100644 --- a/IPython/core/ipapp.py +++ b/IPython/core/ipapp.py @@ -104,11 +104,6 @@ cl_args = ( action='store_false', dest='Global.display_banner', default=NoConfigDefault, help="Don't display a banner upon starting IPython.") ), - (('-c',), dict( - type=str, dest='InteractiveShell.c', default=NoConfigDefault, - help="Execute the given command string.", - metavar='InteractiveShell.c') - ), (('-cache_size',), dict( type=int, dest='InteractiveShell.cache_size', default=NoConfigDefault, help="Set the size of the output cache.", @@ -251,6 +246,15 @@ cl_args = ( help="The dotted module name of an IPython extension to load.", metavar='Global.extra_extension') ), + (('-c',), dict( + type=str, dest='Global.code_to_run', default=NoConfigDefault, + help="Execute the given command string.", + metavar='Global.code_to_run') + ), + (('-i',), dict( + action='store_true', dest='Global.force_interact', default=NoConfigDefault, + help="If running code from the command line, become interactive afterwards.") + ), # These are only here to get the proper deprecation warnings (('-pylab','-wthread','-qthread','-q4thread','-gthread'), dict( action='store_true', dest='Global.threaded_shell', default=NoConfigDefault, @@ -272,7 +276,16 @@ class IPythonApp(Application): def create_default_config(self): super(IPythonApp, self).create_default_config() - self.default_config.Global.display_banner=True + self.default_config.Global.display_banner = True + + # If the -c flag is given or a file is given to run at the cmd line + # like "ipython foo.py", normally we exit without starting the main + # loop. The force_interact config variable allows a user to override + # this and interact. It is also set by the -i cmd line flag, just + # like Python. + self.default_config.Global.force_interact = False + # By default always interact by starting the IPython mainloop. + self.default_config.Global.interact = True # Let the parent class set the default, but each time log_level # changes from config, we need to update self.log_level as that is # what updates the actual log level in self.log. @@ -324,15 +337,22 @@ class IPythonApp(Application): config.InteractiveShell.colors = 'NoColor' config.InteractiveShell.xmode = 'Plain' - # All this should be moved to traitlet handlers in InteractiveShell - # But, currently InteractiveShell doesn't have support for changing - # these values at runtime. Once we support that, this should - # be moved there!!! if hasattr(config.Global, 'nosep'): if config.Global.nosep: config.InteractiveShell.separate_in = \ config.InteractiveShell.separate_out = \ - config.InteractiveShell.separate_out2 = '0' + config.InteractiveShell.separate_out2 = '' + + # if there is code of files to run from the cmd line, don't interact + # unless the -i flag (Global.force_interact) is true. + code_to_run = config.Global.get('code_to_run','') + file_to_run = False + if len(self.extra_args)>=1: + if self.extra_args[0]: + file_to_run = True + if file_to_run or code_to_run: + if not config.Global.force_interact: + config.Global.interact = False def construct(self): # I am a little hesitant to put these into InteractiveShell itself. @@ -352,7 +372,8 @@ class IPythonApp(Application): # so the banner shows *before* all extension loading stuff. self.shell.display_banner = False - if self.master_config.Global.display_banner: + if self.master_config.Global.display_banner and \ + self.master_config.Global.interact: self.shell.show_banner() # Make sure there is a space below the banner. @@ -361,6 +382,7 @@ class IPythonApp(Application): self._load_extensions() self._run_exec_lines() self._run_exec_files() + self._run_cmd_line_code() def _load_extensions(self): """Load all IPython extensions in Global.extensions. @@ -400,29 +422,55 @@ class IPythonApp(Application): self.log.warn("Unknown error in handling Global.exec_lines:") self.shell.showtraceback() + def _exec_file(self, fname): + full_filename = filefind(fname, ['.', self.ipythondir]) + if os.path.isfile(full_filename): + if full_filename.endswith('.py'): + self.log.info("Running file in user namespace: %s" % full_filename) + self.shell.safe_execfile(full_filename, self.shell.user_ns) + elif full_filename.endswith('.ipy'): + self.log.info("Running file in user namespace: %s" % full_filename) + self.shell.safe_execfile_ipy(full_filename) + else: + self.log.warn("File does not have a .py or .ipy extension: <%s>" % full_filename) + def _run_exec_files(self): try: if hasattr(self.master_config.Global, 'exec_files'): self.log.debug("Running files in Global.exec_files...") exec_files = self.master_config.Global.exec_files for fname in exec_files: - full_filename = filefind(fname, ['.', self.ipythondir]) - if os.path.isfile(full_filename): - if full_filename.endswith('.py'): - self.log.info("Running file in user namespace: %s" % full_filename) - self.shell.safe_execfile(full_filename, self.shell.user_ns) - elif full_filename.endswith('.ipy'): - self.log.info("Running file in user namespace: %s" % full_filename) - self.shell.safe_execfile_ipy(full_filename) - else: - self.log.warn("File does not have a .py or .ipy extension: <%s>" % full_filename) + self._exec_file(fname) except: self.log.warn("Unknown error in handling Global.exec_files:") self.shell.showtraceback() + def _run_cmd_line_code(self): + if hasattr(self.master_config.Global, 'code_to_run'): + line = self.master_config.Global.code_to_run + try: + self.log.info("Running code given at command line (-c): %s" % line) + self.shell.runlines(line) + except: + self.log.warn("Error in executing line in user namespace: %s" % line) + self.shell.showtraceback() + return + # Like Python itself, ignore the second if the first of these is present + try: + fname = self.extra_args[0] + except: + pass + else: + try: + self._exec_file(fname) + except: + self.log.warn("Error in executing file in user namespace: %s" % fname) + self.shell.showtraceback() + def start_app(self): - self.log.debug("Starting IPython's mainloop...") - self.shell.mainloop() + if self.master_config.Global.interact: + self.log.debug("Starting IPython's mainloop...") + self.shell.mainloop() def load_default_config(ipythondir=None): diff --git a/IPython/core/iplib.py b/IPython/core/iplib.py index 58c526f..c1bc026 100644 --- a/IPython/core/iplib.py +++ b/IPython/core/iplib.py @@ -189,7 +189,6 @@ class InteractiveShell(Component, Magic): banner = Str('') banner1 = Str(default_banner, config=True) banner2 = Str('', config=True) - c = Str('', config=True) cache_size = Int(1000, config=True) color_info = CBool(True, config=True) colors = CaselessStrEnum(('NoColor','LightBG','Linux'), @@ -207,7 +206,6 @@ class InteractiveShell(Component, Magic): embedded_active = CBool(False) editor = Str(get_default_editor(), config=True) filename = Str("") - interactive = CBool(False, config=True) ipythondir= Unicode('', config=True) # Set to get_ipython_dir() in __init__ logstart = CBool(False, config=True) logfile = Str('', config=True) @@ -1702,8 +1700,6 @@ class InteractiveShell(Component, Magic): """ with nested(self.builtin_trap, self.display_trap): - if self.c: # Emulate Python's -c option - self.exec_init_cmd() # if you run stuff with -c , raw hist is not updated # ensure that it's in sync @@ -1722,16 +1718,6 @@ class InteractiveShell(Component, Magic): # handling seems rather unpredictable... self.write("\nKeyboardInterrupt in interact()\n") - def exec_init_cmd(self): - """Execute a command given at the command line. - - This emulates Python's -c option.""" - - #sys.argv = ['-c'] - self.push_line(self.prefilter_manager.prefilter_lines(self.c, False)) - if not self.interactive: - self.ask_exit() - def interact_prompt(self): """ Print the prompt (in read-eval-print loop) @@ -2297,24 +2283,6 @@ class InteractiveShell(Component, Magic): else: return lineout - # def init_exec_commands(self): - # for cmd in self.config.EXECUTE: - # print "execute:", cmd - # self.api.runlines(cmd) - # - # batchrun = False - # if self.config.has_key('EXECFILE'): - # for batchfile in [path(arg) for arg in self.config.EXECFILE - # if arg.lower().endswith('.ipy')]: - # if not batchfile.isfile(): - # print "No such batch file:", batchfile - # continue - # self.api.runlines(batchfile.text()) - # batchrun = True - # # without -i option, exit after running the batch file - # if batchrun and not self.interactive: - # self.ask_exit() - #------------------------------------------------------------------------- # IPython extensions #-------------------------------------------------------------------------