diff --git a/IPython/config/application.py b/IPython/config/application.py index 881d807..ae2461e 100644 --- a/IPython/config/application.py +++ b/IPython/config/application.py @@ -49,21 +49,19 @@ Flags are command-line arguments passed as '--'. These take no parameters, unlike regular key-value arguments. They are typically used for setting boolean flags, or enabling modes that involve setting multiple options together. - -Flags *always* begin with '--', never just one '-'. """.strip() # trim newlines of front and back alias_description = """ These are commonly set parameters, given abbreviated aliases for convenience. -They are set in the same `name=value` way as class parameters, where +They are set in the same `--name=value` way as class parameters, where is replaced by the real parameter for which it is an alias. """.strip() # trim newlines of front and back keyvalue_description = """ Parameters are set from command-line arguments of the form: -`Class.trait=value`. Parameters will *never* be prefixed with '-'. +`--Class.trait=value`. This line is evaluated in Python, so simple expressions are allowed, e.g. - `C.a='range(3)'` For setting C.a=[0,1,2] + `--C.a='range(3)'` For setting C.a=[0,1,2] """.strip() # trim newlines of front and back #----------------------------------------------------------------------------- @@ -210,11 +208,12 @@ class Application(SingletonConfigurable): cls = classdict[classname] trait = cls.class_traits(config=True)[traitname] - help = cls.class_get_trait_help(trait) - help = help.replace(longname, "%s (%s)"%(alias, longname), 1) - lines.append(help) + help = cls.class_get_trait_help(trait).splitlines() + # reformat first line + help[0] = help[0].replace(longname, alias) + ' (%s)'%longname + lines.extend(help) lines.append('') - print '\n'.join(lines) + print os.linesep.join(lines) def print_flag_help(self): """Print the flag part of the help.""" diff --git a/IPython/config/configurable.py b/IPython/config/configurable.py index 888248b..f4f5959 100755 --- a/IPython/config/configurable.py +++ b/IPython/config/configurable.py @@ -155,7 +155,7 @@ class Configurable(HasTraits): def class_get_trait_help(cls, trait): """Get the help string for a single trait.""" lines = [] - header = "%s.%s : %s" % (cls.__name__, trait.name, trait.__class__.__name__) + header = "--%s.%s=<%s>" % (cls.__name__, trait.name, trait.__class__.__name__) lines.append(header) try: dvr = repr(trait.get_default_value()) diff --git a/IPython/config/loader.py b/IPython/config/loader.py index d1f72ed..a3bdb2e 100644 --- a/IPython/config/loader.py +++ b/IPython/config/loader.py @@ -326,7 +326,7 @@ class CommandLineConfigLoader(ConfigLoader): """ kv_pattern = re.compile(r'[A-Za-z]\w*(\.\w+)*\=.*') -flag_pattern = re.compile(r'\-\-\w+(\-\w)*') +flag_pattern = re.compile(r'\w+(\-\w)*') class KeyValueConfigLoader(CommandLineConfigLoader): """A config loader that loads key value pairs from the command line. @@ -426,7 +426,17 @@ class KeyValueConfigLoader(CommandLineConfigLoader): if flags is None: flags = self.flags - for item in self._decode_argv(argv): + # ensure argv is a list of unicode strings: + uargv = self._decode_argv(argv) + for idx,raw in enumerate(uargv): + # strip leading '-' + item = raw.lstrip('-') + + if raw == '--': + # don't parse arguments after '--' + self.extra_args.extend(uargv[idx+1:]) + break + if kv_pattern.match(item): lhs,rhs = item.split('=',1) # Substitute longnames for aliases. @@ -445,26 +455,23 @@ class KeyValueConfigLoader(CommandLineConfigLoader): # it succeeds. If it still fails, we let it raise. exec_str = u'self.config.' + lhs + '=' + repr(rhs) exec exec_str in locals(), globals() - elif flag_pattern.match(item): - # trim leading '--' - m = item[2:] - cfg,_ = flags.get(m, (None,None)) - if cfg is None: - raise ArgumentError("Unrecognized flag: %r"%item) - elif isinstance(cfg, (dict, Config)): + elif item in flags: + cfg,help = flags[item] + if isinstance(cfg, (dict, Config)): # don't clobber whole config sections, update # each section from config: for sec,c in cfg.iteritems(): self.config[sec].update(c) else: - raise ValueError("Invalid flag: %r"%flag) - elif item.startswith('-'): - # this shouldn't ever be valid - raise ArgumentError("Invalid argument: %r"%item) + raise ValueError("Invalid flag: '%s'"%raw) + elif raw.startswith('-'): + raise ArgumentError("invalid argument: '%s'"%raw) else: # keep all args that aren't valid in a list, # in case our parent knows what to do with them. - self.extra_args.append(item) + # self.extra_args.append(item) + self.extra_args.extend(uargv[idx:]) + break return self.config class ArgParseConfigLoader(CommandLineConfigLoader): diff --git a/IPython/config/tests/test_application.py b/IPython/config/tests/test_application.py index b9be7d2..e75a47b 100644 --- a/IPython/config/tests/test_application.py +++ b/IPython/config/tests/test_application.py @@ -79,7 +79,7 @@ class TestApplication(TestCase): def test_config(self): app = MyApp() - app.parse_command_line(["i=10","Foo.j=10","enabled=False","log_level=50"]) + app.parse_command_line(["--i=10","Foo.j=10","--enabled=False","-log_level=50"]) config = app.config self.assertEquals(config.Foo.i, 10) self.assertEquals(config.Foo.j, 10) @@ -88,7 +88,7 @@ class TestApplication(TestCase): def test_config_propagation(self): app = MyApp() - app.parse_command_line(["i=10","Foo.j=10","enabled=False","log_level=50"]) + app.parse_command_line(["i=10","--Foo.j=10","enabled=False","log_level=50"]) app.init_foo() app.init_bar() self.assertEquals(app.foo.i, 10) @@ -97,7 +97,7 @@ class TestApplication(TestCase): def test_flags(self): app = MyApp() - app.parse_command_line(["--disable"]) + app.parse_command_line(["-disable"]) app.init_bar() self.assertEquals(app.bar.enabled, False) app.parse_command_line(["--enable"]) @@ -126,10 +126,10 @@ class TestApplication(TestCase): def test_extra_args(self): app = MyApp() - app.parse_command_line(['extra', "Bar.b=5", "--disable", 'args']) + app.parse_command_line(["Bar.b=5", 'extra', "--disable", 'args']) app.init_bar() - self.assertEquals(app.bar.enabled, False) + self.assertEquals(app.bar.enabled, True) self.assertEquals(app.bar.b, 5) - self.assertEquals(app.extra_args, ['extra', 'args']) + self.assertEquals(app.extra_args, ['extra', "--disable", 'args']) diff --git a/IPython/config/tests/test_configurable.py b/IPython/config/tests/test_configurable.py index 9ce47fa..01d4f73 100644 --- a/IPython/config/tests/test_configurable.py +++ b/IPython/config/tests/test_configurable.py @@ -47,10 +47,10 @@ class MyConfigurable(Configurable): mc_help=u"""MyConfigurable options ---------------------- -MyConfigurable.a : Int +--MyConfigurable.a= Default: 1 The integer a. -MyConfigurable.b : Float +--MyConfigurable.b= Default: 1.0 The integer b.""" diff --git a/IPython/config/tests/test_loader.py b/IPython/config/tests/test_loader.py index e1b3509..1995933 100755 --- a/IPython/config/tests/test_loader.py +++ b/IPython/config/tests/test_loader.py @@ -130,9 +130,11 @@ class TestKeyValueCL(TestCase): def test_extra_args(self): cl = KeyValueConfigLoader() config = cl.load_config(['a=5', 'b', 'c=10', 'd']) - self.assertEquals(cl.extra_args, ['b', 'd']) + self.assertEquals(cl.extra_args, ['b', 'c=10' , 'd']) self.assertEquals(config.a, 5) - self.assertEquals(config.c, 10) + self.assertRaises(AttributeError, getattr, config, 'c') + config = cl.load_config(['--', 'a=5', 'c=10']) + self.assertEquals(cl.extra_args, ['a=5', 'c=10']) def test_unicode_args(self): cl = KeyValueConfigLoader() diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index 1038194..fca17f1 100755 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -93,7 +93,7 @@ shell_aliases = dict( cache_size='InteractiveShell.cache_size', colors='InteractiveShell.colors', logfile='InteractiveShell.logfile', - log_append='InteractiveShell.logappend', + logappend='InteractiveShell.logappend', c='InteractiveShellApp.code_to_run', ext='InteractiveShellApp.extra_extension', ) @@ -188,21 +188,28 @@ class InteractiveShellApp(Configurable): def _exec_file(self, fname): full_filename = filefind(fname, [u'.', self.ipython_dir]) - if os.path.isfile(full_filename): - if full_filename.endswith('.ipy'): - self.log.info("Running file in user namespace: %s" % - full_filename) - self.shell.safe_execfile_ipy(full_filename) - else: - # default to python, even without extension - self.log.info("Running file in user namespace: %s" % - full_filename) - # Ensure that __file__ is always defined to match Python behavior - self.shell.user_ns['__file__'] = fname - try: - self.shell.safe_execfile(full_filename, self.shell.user_ns) - finally: - del self.shell.user_ns['__file__'] + # Make sure that the running script gets a proper sys.argv as if it + # were run from a system shell. + save_argv = sys.argv + sys.argv = sys.argv[sys.argv.index(fname):] + try: + if os.path.isfile(full_filename): + if full_filename.endswith('.ipy'): + self.log.info("Running file in user namespace: %s" % + full_filename) + self.shell.safe_execfile_ipy(full_filename) + else: + # default to python, even without extension + self.log.info("Running file in user namespace: %s" % + full_filename) + # Ensure that __file__ is always defined to match Python behavior + self.shell.user_ns['__file__'] = fname + try: + self.shell.safe_execfile(full_filename, self.shell.user_ns) + finally: + del self.shell.user_ns['__file__'] + finally: + sys.argv = save_argv def _run_exec_files(self): """Run files from IPythonApp.exec_files"""