From a7c5280451515750f81ad43d7dfa066ba2adab10 2010-08-12 00:09:18 From: Brian Granger Date: 2010-08-12 00:09:18 Subject: [PATCH] Adding support for HasTraits to take keyword arguments. --- diff --git a/IPython/config/configurable.py b/IPython/config/configurable.py index 1756cab..18cb050 100755 --- a/IPython/config/configurable.py +++ b/IPython/config/configurable.py @@ -48,7 +48,7 @@ class Configurable(HasTraits): config = Instance(Config,(),{}) created = None - def __init__(self, config=None): + def __init__(self, **kwargs): """Create a conigurable given a config config. Parameters @@ -71,7 +71,7 @@ class Configurable(HasTraits): This ensures that instances will be configured properly. """ - super(Configurable, self).__init__() + config = kwargs.pop('config', None) if config is not None: # We used to deepcopy, but for now we are trying to just save # by reference. This *could* have side effects as all components @@ -81,6 +81,9 @@ class Configurable(HasTraits): # making that a class attribute. # self.config = deepcopy(config) self.config = config + # This should go second so individual keyword arguments override + # the values in config. + super(Configurable, self).__init__(**kwargs) self.created = datetime.datetime.now() #------------------------------------------------------------------------- diff --git a/IPython/config/tests/test_configurable.py b/IPython/config/tests/test_configurable.py index 4e69820..d57c36d 100644 --- a/IPython/config/tests/test_configurable.py +++ b/IPython/config/tests/test_configurable.py @@ -34,6 +34,22 @@ from IPython.config.loader import Config #----------------------------------------------------------------------------- +class MyConfigurable(Configurable): + a = Int(1, config=True) + b = Float(1.0, config=True) + c = Str('no config') + + +class Foo(Configurable): + a = Int(0, config=True) + b = Str('nope', config=True) + + +class Bar(Foo): + b = Str('gotit', config=False) + c = Float(config=True) + + class TestConfigurableConfig(TestCase): def test_default(self): @@ -48,8 +64,8 @@ class TestConfigurableConfig(TestCase): config.foo = 'foo' config.bar = 'bar' c1 = Configurable(config=config) - c2 = Configurable(c1.config) - c3 = Configurable(c2.config) + c2 = Configurable(config=c1.config) + c3 = Configurable(config=c2.config) self.assertEquals(c1.config, config) self.assertEquals(c2.config, config) self.assertEquals(c3.config, config) @@ -61,35 +77,48 @@ class TestConfigurableConfig(TestCase): self.assert_(c2.config is c3.config) def test_inheritance(self): - class MyConfigurable(Configurable): - a = Int(1, config=True) - b = Float(1.0, config=True) - c = Str('no config') config = Config() config.MyConfigurable.a = 2 config.MyConfigurable.b = 2.0 c1 = MyConfigurable(config=config) - c2 = MyConfigurable(c1.config) + c2 = MyConfigurable(config=c1.config) self.assertEquals(c1.a, config.MyConfigurable.a) self.assertEquals(c1.b, config.MyConfigurable.b) self.assertEquals(c2.a, config.MyConfigurable.a) self.assertEquals(c2.b, config.MyConfigurable.b) def test_parent(self): - class Foo(Configurable): - a = Int(0, config=True) - b = Str('nope', config=True) - class Bar(Foo): - b = Str('gotit', config=False) - c = Float(config=True) config = Config() config.Foo.a = 10 config.Foo.b = "wow" config.Bar.b = 'later' config.Bar.c = 100.0 f = Foo(config=config) - b = Bar(f.config) + b = Bar(config=f.config) self.assertEquals(f.a, 10) self.assertEquals(f.b, 'wow') self.assertEquals(b.b, 'gotit') self.assertEquals(b.c, 100.0) + + def test_override1(self): + config = Config() + config.MyConfigurable.a = 2 + config.MyConfigurable.b = 2.0 + c = MyConfigurable(a=3, config=config) + self.assertEquals(c.a, 3) + self.assertEquals(c.b, config.MyConfigurable.b) + self.assertEquals(c.c, 'no config') + + def test_override2(self): + config = Config() + config.Foo.a = 1 + config.Bar.b = 'or' # Up above b is config=False, so this won't do it. + config.Bar.c = 10.0 + c = Bar(config=config) + self.assertEquals(c.a, config.Foo.a) + self.assertEquals(c.b, 'gotit') + self.assertEquals(c.c, config.Bar.c) + c = Bar(a=2, b='and', c=20.0, config=config) + self.assertEquals(c.a, 2) + self.assertEquals(c.b, 'and') + self.assertEquals(c.c, 20.0) diff --git a/IPython/core/alias.py b/IPython/core/alias.py index c05db21..506097a 100644 --- a/IPython/core/alias.py +++ b/IPython/core/alias.py @@ -106,12 +106,11 @@ class AliasManager(Configurable): user_aliases = List(default_value=[], config=True) shell = Instance('IPython.core.iplib.InteractiveShellABC') - def __init__(self, shell, config=None): - super(AliasManager, self).__init__(config=config) + def __init__(self, shell=None, config=None): + super(AliasManager, self).__init__(shell=shell, config=config) self.alias_table = {} self.exclude_aliases() self.init_aliases() - self.shell = shell def __contains__(self, name): if name in self.alias_table: diff --git a/IPython/core/builtin_trap.py b/IPython/core/builtin_trap.py index 0924510..758d514 100755 --- a/IPython/core/builtin_trap.py +++ b/IPython/core/builtin_trap.py @@ -39,8 +39,8 @@ class BuiltinTrap(Configurable): shell = Instance('IPython.core.iplib.InteractiveShellABC') - def __init__(self, shell): - super(BuiltinTrap, self).__init__(None) + def __init__(self, shell=None): + super(BuiltinTrap, self).__init__(shell=shell, config=None) self._orig_builtins = {} # We define this to track if a single BuiltinTrap is nested. # Only turn off the trap when the outermost call to __exit__ is made. diff --git a/IPython/core/display_trap.py b/IPython/core/display_trap.py index 7d6539c..d835b54 100644 --- a/IPython/core/display_trap.py +++ b/IPython/core/display_trap.py @@ -23,6 +23,7 @@ Authors: import sys from IPython.config.configurable import Configurable +from IPython.utils.traitlets import Any #----------------------------------------------------------------------------- # Classes and functions @@ -36,9 +37,10 @@ class DisplayTrap(Configurable): (no callbacks or formatters) until more of the core is refactored. """ - def __init__(self, hook): - super(DisplayTrap, self).__init__(None) - self.hook = hook + hook = Any + + def __init__(self, hook=None): + super(DisplayTrap, self).__init__(hook=hook, config=None) self.old_hook = None # We define this to track if a single BuiltinTrap is nested. # Only turn off the trap when the outermost call to __exit__ is made. diff --git a/IPython/core/extensions.py b/IPython/core/extensions.py index 82f84cd..bf1757e 100644 --- a/IPython/core/extensions.py +++ b/IPython/core/extensions.py @@ -55,9 +55,8 @@ class ExtensionManager(Configurable): shell = Instance('IPython.core.iplib.InteractiveShellABC') - def __init__(self, shell, config=None): - super(ExtensionManager, self).__init__(config=config) - self.shell = shell + def __init__(self, shell=None, config=None): + super(ExtensionManager, self).__init__(shell=shell, config=config) self.shell.on_trait_change( self._on_ipython_dir_changed, 'ipython_dir' ) diff --git a/IPython/core/iplib.py b/IPython/core/iplib.py index af27eb9..a098db6 100644 --- a/IPython/core/iplib.py +++ b/IPython/core/iplib.py @@ -510,7 +510,7 @@ class InteractiveShell(Configurable, Magic): self.magic_logstart() def init_builtins(self): - self.builtin_trap = BuiltinTrap(self) + self.builtin_trap = BuiltinTrap(shell=self) def init_inspector(self): # Object inspector @@ -539,7 +539,7 @@ class InteractiveShell(Configurable, Magic): pass def init_displayhook(self): - self.display_trap = DisplayTrap(self.outputcache) + self.display_trap = DisplayTrap(hook=self.outputcache) def init_reload_doctest(self): # Do a proper resetting of doctest, including the necessary displayhook @@ -1759,7 +1759,7 @@ class InteractiveShell(Configurable, Magic): #------------------------------------------------------------------------- def init_alias(self): - self.alias_manager = AliasManager(self, config=self.config) + self.alias_manager = AliasManager(shell=self, config=self.config) self.ns_table['alias'] = self.alias_manager.alias_table, #------------------------------------------------------------------------- @@ -1767,7 +1767,7 @@ class InteractiveShell(Configurable, Magic): #------------------------------------------------------------------------- def init_extension_manager(self): - self.extension_manager = ExtensionManager(self, config=self.config) + self.extension_manager = ExtensionManager(shell=self, config=self.config) def init_plugin_manager(self): self.plugin_manager = PluginManager(config=self.config) @@ -2370,7 +2370,7 @@ class InteractiveShell(Configurable, Magic): #------------------------------------------------------------------------- def init_prefilter(self): - self.prefilter_manager = PrefilterManager(self, config=self.config) + self.prefilter_manager = PrefilterManager(shell=self, config=self.config) # Ultimately this will be refactored in the new interpreter code, but # for now, we should expose the main prefilter method (there's legacy # code out there that may rely on this). diff --git a/IPython/core/prefilter.py b/IPython/core/prefilter.py index 10e366b..50a8b67 100755 --- a/IPython/core/prefilter.py +++ b/IPython/core/prefilter.py @@ -212,8 +212,8 @@ class PrefilterManager(Configurable): multi_line_specials = CBool(True, config=True) shell = Instance('IPython.core.iplib.InteractiveShellABC') - def __init__(self, shell, config=None): - super(PrefilterManager, self).__init__(config=config) + def __init__(self, shell=None, config=None): + super(PrefilterManager, self).__init__(shell=shell, config=config) self.shell = shell self.init_transformers() self.init_handlers() @@ -227,7 +227,9 @@ class PrefilterManager(Configurable): """Create the default transformers.""" self._transformers = [] for transformer_cls in _default_transformers: - transformer_cls(self.shell, self, config=self.config) + transformer_cls( + shell=self.shell, prefilter_manager=self, config=self.config + ) def sort_transformers(self): """Sort the transformers by priority. @@ -261,7 +263,9 @@ class PrefilterManager(Configurable): """Create the default checkers.""" self._checkers = [] for checker in _default_checkers: - checker(self.shell, self, config=self.config) + checker( + shell=self.shell, prefilter_manager=self, config=self.config + ) def sort_checkers(self): """Sort the checkers by priority. @@ -296,7 +300,9 @@ class PrefilterManager(Configurable): self._handlers = {} self._esc_handlers = {} for handler in _default_handlers: - handler(self.shell, self, config=self.config) + handler( + shell=self.shell, prefilter_manager=self, config=self.config + ) @property def handlers(self): @@ -451,10 +457,10 @@ class PrefilterTransformer(Configurable): prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager') enabled = Bool(True, config=True) - def __init__(self, shell, prefilter_manager, config=None): - super(PrefilterTransformer, self).__init__(config=config) - self.shell = shell - self.prefilter_manager = prefilter_manager + def __init__(self, shell=None, prefilter_manager=None, config=None): + super(PrefilterTransformer, self).__init__( + shell=shell, prefilter_manager=prefilter_manager, config=config + ) self.prefilter_manager.register_transformer(self) def transform(self, line, continue_prompt): @@ -559,10 +565,10 @@ class PrefilterChecker(Configurable): prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager') enabled = Bool(True, config=True) - def __init__(self, shell, prefilter_manager, config=None): - super(PrefilterChecker, self).__init__(config=config) - self.shell = shell - self.prefilter_manager = prefilter_manager + def __init__(self, shell=None, prefilter_manager=None, config=None): + super(PrefilterChecker, self).__init__( + shell=shell, prefilter_manager=prefilter_manager, config=config + ) self.prefilter_manager.register_checker(self) def check(self, line_info): @@ -751,10 +757,10 @@ class PrefilterHandler(Configurable): shell = Instance('IPython.core.iplib.InteractiveShellABC') prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager') - def __init__(self, shell, prefilter_manager, config=None): - super(PrefilterHandler, self).__init__(config=config) - self.shell = shell - self.prefilter_manager = prefilter_manager + def __init__(self, shell=None, prefilter_manager=None, config=None): + super(PrefilterHandler, self).__init__( + shell=shell, prefilter_manager=prefilter_manager, config=config + ) self.prefilter_manager.register_handler( self.handler_name, self, diff --git a/IPython/extensions/parallelmagic.py b/IPython/extensions/parallelmagic.py index e61d9a7..3f53468 100755 --- a/IPython/extensions/parallelmagic.py +++ b/IPython/extensions/parallelmagic.py @@ -38,9 +38,8 @@ class ParalleMagic(Plugin): verbose = Bool(False, config=True) shell = Instance('IPython.core.iplib.InteractiveShellABC') - def __init__(self, shell, config=None): - super(ParalleMagic, self).__init__(config=config) - self.shell = shell + def __init__(self, shell=None, config=None): + super(ParalleMagic, self).__init__(shell=shell, config=config) self._define_magics() # A flag showing if autopx is activated or not self.autopx = False @@ -196,7 +195,7 @@ def load_ipython_extension(ip): """Load the extension in IPython.""" global _loaded if not _loaded: - plugin = ParalleMagic(ip, config=ip.config) + plugin = ParalleMagic(shell=ip, config=ip.config) ip.plugin_manager.register_plugin('parallel_magic', plugin) _loaded = True diff --git a/IPython/extensions/pretty.py b/IPython/extensions/pretty.py index 5e94db0..8f05b23 100644 --- a/IPython/extensions/pretty.py +++ b/IPython/extensions/pretty.py @@ -67,9 +67,8 @@ class PrettyResultDisplay(Plugin): # The final argument can also be a callable defaults_for_type_by_name = List(default_value=[], config=True) - def __init__(self, shell, config=None): - super(PrettyResultDisplay, self).__init__(config=config) - self.shell = shell + def __init__(self, shell=None, config=None): + super(PrettyResultDisplay, self).__init__(shell=shell, config=config) self._setup_defaults() def _setup_defaults(self): @@ -124,7 +123,7 @@ def load_ipython_extension(ip): """Load the extension in IPython as a hook.""" global _loaded if not _loaded: - plugin = PrettyResultDisplay(ip, config=ip.config) + plugin = PrettyResultDisplay(shell=ip, config=ip.config) ip.set_hook('result_display', plugin, priority=99) _loaded = True ip.plugin_manager.register_plugin('pretty_result_display', plugin) diff --git a/IPython/extensions/tests/test_pretty.py b/IPython/extensions/tests/test_pretty.py index 29e9752..c7da78a 100644 --- a/IPython/extensions/tests/test_pretty.py +++ b/IPython/extensions/tests/test_pretty.py @@ -44,7 +44,7 @@ class TestPrettyResultDisplay(TestCase): def setUp(self): self.ip = InteractiveShellStub() - self.prd = pretty_ext.PrettyResultDisplay(self.ip, config=None) + self.prd = pretty_ext.PrettyResultDisplay(shell=self.ip, config=None) def test_for_type(self): self.prd.for_type(A, a_pprinter) diff --git a/IPython/kernel/clusterdir.py b/IPython/kernel/clusterdir.py index faba277..6a7c296 100755 --- a/IPython/kernel/clusterdir.py +++ b/IPython/kernel/clusterdir.py @@ -82,9 +82,8 @@ class ClusterDir(Configurable): pid_dir = Unicode(u'') location = Unicode(u'') - def __init__(self, location): - super(ClusterDir, self).__init__(None) - self.location = location + def __init__(self, location=u''): + super(ClusterDir, self).__init__(location=location) def _location_changed(self, name, old, new): if not os.path.isdir(new): @@ -166,7 +165,7 @@ class ClusterDir(Configurable): The full path to the cluster directory. If it does exist, it will be used. If not, it will be created. """ - return ClusterDir(cluster_dir) + return ClusterDir(location=cluster_dir) @classmethod def create_cluster_dir_by_profile(cls, path, profile=u'default'): @@ -183,7 +182,7 @@ class ClusterDir(Configurable): if not os.path.isdir(path): raise ClusterDirError('Directory not found: %s' % path) cluster_dir = os.path.join(path, u'cluster_' + profile) - return ClusterDir(cluster_dir) + return ClusterDir(location=cluster_dir) @classmethod def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'): @@ -216,7 +215,7 @@ class ClusterDir(Configurable): for p in paths: cluster_dir = os.path.join(p, dirname) if os.path.isdir(cluster_dir): - return ClusterDir(cluster_dir) + return ClusterDir(location=cluster_dir) else: raise ClusterDirError('Cluster directory not found in paths: %s' % dirname) @@ -235,7 +234,7 @@ class ClusterDir(Configurable): cluster_dir = expand_path(cluster_dir) if not os.path.isdir(cluster_dir): raise ClusterDirError('Cluster directory not found: %s' % cluster_dir) - return ClusterDir(cluster_dir) + return ClusterDir(location=cluster_dir) #----------------------------------------------------------------------------- diff --git a/IPython/kernel/configobjfactory.py b/IPython/kernel/configobjfactory.py index c9d8245..b16dbfc 100644 --- a/IPython/kernel/configobjfactory.py +++ b/IPython/kernel/configobjfactory.py @@ -43,7 +43,7 @@ class ConfiguredObjectFactory(Configurable): zi.implements(IConfiguredObjectFactory) - def __init__(self, config): + def __init__(self, config=None): super(ConfiguredObjectFactory, self).__init__(config=config) def create(self): @@ -56,7 +56,7 @@ class IAdaptedConfiguredObjectFactory(zi.Interface): This class is useful if you have the adapt an instance and configure it. """ - def __init__(config, adaptee=None): + def __init__(config=None, adaptee=None): """Get ready to adapt adaptee and then configure it using config.""" def create(): @@ -67,7 +67,7 @@ class AdaptedConfiguredObjectFactory(Configurable): # zi.implements(IAdaptedConfiguredObjectFactory) - def __init__(self, config, adaptee): + def __init__(self, config=None, adaptee=None): # print # print "config pre:", config super(AdaptedConfiguredObjectFactory, self).__init__(config=config) diff --git a/IPython/kernel/launcher.py b/IPython/kernel/launcher.py index abb312d..fbcc4e9 100644 --- a/IPython/kernel/launcher.py +++ b/IPython/kernel/launcher.py @@ -89,9 +89,8 @@ class BaseLauncher(Configurable): # the --work-dir option. work_dir = Unicode(u'') - def __init__(self, work_dir, config=None): - super(BaseLauncher, self).__init__(config) - self.work_dir = work_dir + def __init__(self, work_dir=u'', config=None): + super(BaseLauncher, self).__init__(work_dir=work_dir, config=config) self.state = 'before' # can be before, running, after self.stop_deferreds = [] self.start_data = None @@ -265,9 +264,9 @@ class LocalProcessLauncher(BaseLauncher): # spawnProcess. cmd_and_args = List([]) - def __init__(self, work_dir, config=None): + def __init__(self, work_dir=u'', config=None): super(LocalProcessLauncher, self).__init__( - work_dir, config + work_dir=work_dir, config=config ) self.process_protocol = None self.start_deferred = None @@ -356,9 +355,9 @@ class LocalEngineSetLauncher(BaseLauncher): ['--log-to-file','--log-level', '40'], config=True ) - def __init__(self, work_dir, config=None): + def __init__(self, work_dir=u'', config=None): super(LocalEngineSetLauncher, self).__init__( - work_dir, config + work_dir=work_dir, config=config ) self.launchers = [] @@ -367,7 +366,7 @@ class LocalEngineSetLauncher(BaseLauncher): self.cluster_dir = unicode(cluster_dir) dlist = [] for i in range(n): - el = LocalEngineLauncher(self.work_dir, self.config) + el = LocalEngineLauncher(work_dir=self.work_dir, config=self.config) # Copy the engine args over to each engine launcher. import copy el.engine_args = copy.deepcopy(self.engine_args) @@ -560,9 +559,9 @@ class WindowsHPCLauncher(BaseLauncher): scheduler = Str('', config=True) job_cmd = Str(find_job_cmd(), config=True) - def __init__(self, work_dir, config=None): + def __init__(self, work_dir=u'', config=None): super(WindowsHPCLauncher, self).__init__( - work_dir, config + work_dir=work_dir, config=config ) @property @@ -633,9 +632,9 @@ class WindowsHPCControllerLauncher(WindowsHPCLauncher): extra_args = List([], config=False) def write_job_file(self, n): - job = IPControllerJob(self) + job = IPControllerJob(config=self.config) - t = IPControllerTask(self) + t = IPControllerTask(config=self.config) # The tasks work directory is *not* the actual work directory of # the controller. It is used as the base path for the stdout/stderr # files that the scheduler redirects to. @@ -664,10 +663,10 @@ class WindowsHPCEngineSetLauncher(WindowsHPCLauncher): extra_args = List([], config=False) def write_job_file(self, n): - job = IPEngineSetJob(self) + job = IPEngineSetJob(config=self.config) for i in range(n): - t = IPEngineTask(self) + t = IPEngineTask(config=self.config) # The tasks work directory is *not* the actual work directory of # the engine. It is used as the base path for the stdout/stderr # files that the scheduler redirects to. @@ -725,9 +724,9 @@ class BatchSystemLauncher(BaseLauncher): # The full path to the instantiated batch script. batch_file = Unicode(u'') - def __init__(self, work_dir, config=None): + def __init__(self, work_dir=u'', config=None): super(BatchSystemLauncher, self).__init__( - work_dir, config + work_dir=work_dir, config=config ) self.batch_file = os.path.join(self.work_dir, self.batch_file_name) self.context = {} diff --git a/IPython/kernel/winhpcjob.py b/IPython/kernel/winhpcjob.py index adc5f60..b862bc8 100644 --- a/IPython/kernel/winhpcjob.py +++ b/IPython/kernel/winhpcjob.py @@ -262,7 +262,7 @@ class IPControllerTask(WinHPCTask): work_directory = CStr('', config=False) def __init__(self, config=None): - super(IPControllerTask, self).__init__(config) + super(IPControllerTask, self).__init__(config=config) the_uuid = uuid.uuid1() self.std_out_file_path = os.path.join('log','ipcontroller-%s.out' % the_uuid) self.std_err_file_path = os.path.join('log','ipcontroller-%s.err' % the_uuid) @@ -290,7 +290,7 @@ class IPEngineTask(WinHPCTask): work_directory = CStr('', config=False) def __init__(self, config=None): - super(IPEngineTask,self).__init__(config) + super(IPEngineTask,self).__init__(config=config) the_uuid = uuid.uuid1() self.std_out_file_path = os.path.join('log','ipengine-%s.out' % the_uuid) self.std_err_file_path = os.path.join('log','ipengine-%s.err' % the_uuid) diff --git a/IPython/utils/tests/test_traitlets.py b/IPython/utils/tests/test_traitlets.py index fbf13c2..c7cac4e 100755 --- a/IPython/utils/tests/test_traitlets.py +++ b/IPython/utils/tests/test_traitlets.py @@ -360,6 +360,13 @@ class TestHasTraits(TestCase): traits = a.traits(config_key=lambda v: True) self.assertEquals(traits, dict(i=A.i, f=A.f, j=A.j)) + def test_init(self): + class A(HasTraits): + i = Int() + x = Float() + a = A(i=1, x=10.0) + self.assertEquals(a.i, 1) + self.assertEquals(a.x, 10.0) #----------------------------------------------------------------------------- # Tests for specific trait types diff --git a/IPython/utils/traitlets.py b/IPython/utils/traitlets.py index 0c94da5..85afa85 100644 --- a/IPython/utils/traitlets.py +++ b/IPython/utils/traitlets.py @@ -399,8 +399,8 @@ class HasTraits(object): return inst - def __init__(self, *kw): - # Allow trait values to be set using keywork arguments. + def __init__(self, **kw): + # Allow trait values to be set using keyword arguments. for key, value in kw.iteritems(): setattr(self, key, value)