Hello community,

here is the log from the commit of package python3-traitlets for 
openSUSE:Factory checked in at 2016-03-16 10:36:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-traitlets (Old)
 and      /work/SRC/openSUSE:Factory/.python3-traitlets.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python3-traitlets"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-traitlets/python3-traitlets.changes      
2016-01-20 09:55:10.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.python3-traitlets.new/python3-traitlets.changes 
2016-03-16 10:36:35.000000000 +0100
@@ -1,0 +2,19 @@
+Tue Mar 15 04:32:29 UTC 2016 - a...@gmx.de
+
+- update to version 4.2.1:
+  * demote super().__init__ argument warning to deprecation
+
+- changes from version 4.2.0:
+  * JSONFileConfigLoader can be used as a context manager for updating
+    configuration.
+  * If a value in config does not map onto a configurable trait, a
+    message is displayed that the value will have no effect.
+  * Unused arguments are passed to super() in HasTraits.__init__,
+    improving support for multiple inheritance.
+  * Various bugfixes and improvements in the new API introduced in
+    4.1.
+  * Application subclasses may specify raise_config_file_errors = True
+    to exit on failure to load config files, instead of the default of
+    logging the failures.
+
+-------------------------------------------------------------------

Old:
----
  traitlets-4.1.0.tar.gz

New:
----
  traitlets-4.2.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python3-traitlets.spec ++++++
--- /var/tmp/diff_new_pack.0XF8OL/_old  2016-03-16 10:36:36.000000000 +0100
+++ /var/tmp/diff_new_pack.0XF8OL/_new  2016-03-16 10:36:36.000000000 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           python3-traitlets
-Version:        4.1.0
+Version:        4.2.1
 Release:        0
 Summary:        Traitlets Python config system
 License:        BSD-3-Clause

++++++ traitlets-4.1.0.tar.gz -> traitlets-4.2.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/MANIFEST.in 
new/traitlets-4.2.1/MANIFEST.in
--- old/traitlets-4.1.0/MANIFEST.in     1970-01-01 01:00:00.000000000 +0100
+++ new/traitlets-4.2.1/MANIFEST.in     2015-11-27 16:12:53.000000000 +0100
@@ -0,0 +1,22 @@
+include CONTRIBUTING.md
+include COPYING.md
+include README.md
+
+# Documentation
+graft docs
+exclude docs/\#*
+
+# Examples
+graft examples
+
+# docs subdirs we want to skip
+prune docs/build
+prune docs/gh-pages
+prune docs/dist
+
+# Patterns to exclude from any directory
+global-exclude *~
+global-exclude *.pyc
+global-exclude *.pyo
+global-exclude .git
+global-exclude .ipynb_checkpoints
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/PKG-INFO new/traitlets-4.2.1/PKG-INFO
--- old/traitlets-4.1.0/PKG-INFO        2016-01-15 18:00:30.000000000 +0100
+++ new/traitlets-4.2.1/PKG-INFO        2016-03-14 20:38:32.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: traitlets
-Version: 4.1.0
+Version: 4.2.1
 Summary: Traitlets Python config system
 Home-page: http://ipython.org
 Author: IPython Development Team
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/docs/source/changelog.rst 
new/traitlets-4.2.1/docs/source/changelog.rst
--- old/traitlets-4.1.0/docs/source/changelog.rst       2016-01-15 
17:57:59.000000000 +0100
+++ new/traitlets-4.2.1/docs/source/changelog.rst       2016-03-14 
16:51:29.000000000 +0100
@@ -1,6 +1,22 @@
 Changes in Traitlets
 ====================
 
+4.2
+---
+
+`4.2 on GitHub <https://github.com/ipython/traitlets/milestones/4.2>`__
+
+- :class:`JSONFileConfigLoader` can be used as a context manager for updating 
configuration.
+- If a value in config does not map onto a configurable trait,
+  a message is displayed that the value will have no effect.
+- Unused arguments are passed to ``super()`` in ``HasTraits.__init__``,
+  improving support for multiple inheritance.
+- Various bugfixes and improvements in the new API introduced in 4.1.
+- Application subclasses may specify ``raise_config_file_errors = True``
+  to exit on failure to load config files,
+  instead of the default of logging the failures.
+
+
 4.1
 ---
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/setup.cfg 
new/traitlets-4.2.1/setup.cfg
--- old/traitlets-4.1.0/setup.cfg       2015-04-09 02:27:21.000000000 +0200
+++ new/traitlets-4.2.1/setup.cfg       2016-03-14 20:38:32.000000000 +0100
@@ -1,2 +1,8 @@
 [bdist_wheel]
-universal=1
+universal = 1
+
+[egg_info]
+tag_build = 
+tag_svn_revision = 0
+tag_date = 0
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/traitlets/_version.py 
new/traitlets-4.2.1/traitlets/_version.py
--- old/traitlets-4.1.0/traitlets/_version.py   2016-01-15 18:00:02.000000000 
+0100
+++ new/traitlets-4.2.1/traitlets/_version.py   2016-03-14 20:37:55.000000000 
+0100
@@ -1,2 +1,2 @@
-version_info = (4, 1, 0)
+version_info = (4, 2, 1)
 __version__ = '.'.join(map(str, version_info))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/traitlets/config/application.py 
new/traitlets-4.2.1/traitlets/config/application.py
--- old/traitlets-4.1.0/traitlets/config/application.py 2016-01-11 
16:09:05.000000000 +0100
+++ new/traitlets-4.2.1/traitlets/config/application.py 2016-03-14 
16:37:50.000000000 +0100
@@ -21,7 +21,7 @@
 )
 
 from traitlets.traitlets import (
-    Unicode, List, Enum, Dict, Instance, TraitError, observe, observe_compat, 
default,
+    Bool, Unicode, List, Enum, Dict, Instance, TraitError, observe, 
observe_compat, default,
 )
 from ipython_genutils.importstring import import_item
 from ipython_genutils.text import indent, wrap_paragraphs, dedent
@@ -149,6 +149,9 @@
     # the argv used to initialize the application
     argv = List()
 
+    # Whether failing to load config files should prevent startup
+    raise_config_file_errors = Bool(False)
+
     # The log level for the application
     log_level = 
Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
                     default_value=logging.WARN,
@@ -511,7 +514,7 @@
         self.extra_args = loader.extra_args
 
     @classmethod
-    def _load_config_files(cls, basefilename, path=None, log=None):
+    def _load_config_files(cls, basefilename, path=None, log=None, 
raise_config_file_errors=False):
         """Load config files (py,json) by filename and path.
 
         yield each config object in turn.
@@ -536,6 +539,8 @@
                     # unlikely event that the error raised before filefind 
finished
                     filename = loader.full_filename or basefilename
                     # problem while running the file
+                    if raise_config_file_errors:
+                        raise
                     if log:
                         log.error("Exception while loading config file %s",
                                 filename, exc_info=True)
@@ -553,7 +558,9 @@
         """Load config files by filename and path."""
         filename, ext = os.path.splitext(filename)
         loaded = []
-        for config in self._load_config_files(filename, path=path, 
log=self.log):
+        for config in self._load_config_files(filename, path=path, 
log=self.log,
+            raise_config_file_errors=self.raise_config_file_errors,
+        ):
             loaded.append(config)
             self.update_config(config)
         if len(loaded) > 1:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/traitlets/config/configurable.py 
new/traitlets-4.2.1/traitlets/config/configurable.py
--- old/traitlets-4.1.0/traitlets/config/configurable.py        2016-01-13 
11:14:04.000000000 +0100
+++ new/traitlets-4.2.1/traitlets/config/configurable.py        2016-02-17 
12:48:39.000000000 +0100
@@ -7,8 +7,9 @@
 from __future__ import print_function
 
 from copy import deepcopy
+import warnings
 
-from .loader import Config, LazyConfigValue
+from .loader import Config, LazyConfigValue, _is_section_key
 from traitlets.traitlets import HasTraits, Instance, observe, observe_compat, 
default
 from ipython_genutils.text import indent, dedent, wrap_paragraphs
 from ipython_genutils.py3compat import iteritems
@@ -151,15 +152,21 @@
                     # config object. If we don't, a mutable config_value will 
be
                     # shared by all instances, effectively making it a class 
attribute.
                     setattr(self, name, deepcopy(config_value))
-                elif isinstance(self, LoggingConfigurable):
+                elif not _is_section_key(name) and not 
isinstance(config_value, Config):
                     from difflib import get_close_matches
+                    if isinstance(self, LoggingConfigurable):
+                        warn = self.log.warning
+                    else:
+                        warn = lambda msg: warnings.warn(msg, stacklevel=9)
                     matches = get_close_matches(name, traits)
+                    msg = u"Config option `{option}` not recognized by 
`{klass}`.".format(
+                        option=name, klass=self.__class__.__name__)
+                    
                     if len(matches) == 1:
-                        self.log.warning(u"Config option `{option}` not 
recognized by `{klass}`, do you mean : `{matches}`"
-                                .format(option=name, 
klass=type(self).__name__, matches=matches[0]))
+                        msg += u"  Did you mean 
`{matches}`?".format(matches=matches[0])
                     elif len(matches) >= 1:
-                        self.log.warning(u"Config option `{option}` not 
recognized by `{klass}`, do you mean one of : `{matches}`"
-                                .format(option=name, 
klass=type(self).__name__, matches=' ,'.join(matches)))
+                        msg +="  Did you mean one of: 
`{matches}`?".format(matches=', '.join(sorted(matches)))
+                    warn(msg)
 
     @observe('config')
     @observe_compat
@@ -180,19 +187,13 @@
         self._load_config(change['new'], traits=traits, 
section_names=section_names)
 
     def update_config(self, config):
-        """Update config and trigger reload of config via trait events"""
-        # Save a copy of the old config
-        oldconfig = deepcopy(self.config)
-        # merge new config
+        """Update config and load the new values"""
+        # load config
+        self._load_config(config)
+        # merge it into self.config
         self.config.merge(config)
-        # unconditionally notify trait change, which triggers load of new 
config
-        self.notify_change({
-            'name': 'config',
-            'old': oldconfig,
-            'new': self.config,
-            'owner': self,
-            'type': 'change',
-        })
+        # TODO: trigger change event if/when dict-update change events take 
place
+        # DO NOT trigger full trait-change
 
     @classmethod
     def class_get_help(cls, inst=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/traitlets/config/loader.py 
new/traitlets-4.2.1/traitlets/config/loader.py
--- old/traitlets-4.1.0/traitlets/config/loader.py      2015-07-11 
05:20:55.000000000 +0200
+++ new/traitlets-4.2.1/traitlets/config/loader.py      2016-02-17 
12:48:39.000000000 +0100
@@ -385,7 +385,16 @@
         self.full_filename = filefind(self.filename, self.path)
 
 class JSONFileConfigLoader(FileConfigLoader):
-    """A JSON file loader for config"""
+    """A JSON file loader for config
+
+    Can also act as a context manager that rewrite the configuration file to 
disk on exit.
+
+    Example::
+
+        with 
JSONFileConfigLoader('myapp.json','/home/jupyter/configurations/') as c:
+            c.MyNewConfigurable.new_value = 'Updated'
+
+    """
 
     def load_config(self):
         """Load the config from a file and return it as a Config object."""
@@ -414,6 +423,23 @@
         else:
             raise ValueError('Unknown version of JSON config file: 
{version}'.format(version=version))
 
+    def __enter__(self):
+        self.load_config()
+        return self.config
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        """
+        Exit the context manager but do not handle any errors.
+
+        In case of any error, we do not want to write the potentially broken
+        configuration to disk.
+        """
+        self.config.version = 1
+        json_config = json.dumps(self.config, indent=2)
+        with open(self.full_filename, 'w') as f:
+            f.write(json_config)
+
+
 
 class PyFileConfigLoader(FileConfigLoader):
     """A config loader for pure python files.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/traitlets-4.1.0/traitlets/config/tests/test_application.py 
new/traitlets-4.2.1/traitlets/config/tests/test_application.py
--- old/traitlets-4.1.0/traitlets/config/tests/test_application.py      
2016-01-11 16:09:05.000000000 +0100
+++ new/traitlets-4.2.1/traitlets/config/tests/test_application.py      
2016-03-14 16:37:50.000000000 +0100
@@ -18,6 +18,7 @@
 
 pjoin = os.path.join
 
+from nose import SkipTest
 import nose.tools as nt
 
 from traitlets.config.configurable import Configurable
@@ -223,6 +224,31 @@
                 app.load_config_file(name, path=[td1, td2])
                 app.init_bar()
                 self.assertEqual(app.bar.b, 1)
+    
+    def test_log_bad_config(self):
+        if not hasattr(nt, 'assert_logs'):
+            raise SkipTest("Test requires nose.tests.assert_logs")
+        app = MyApp()
+        app.log = logging.getLogger()
+        name = 'config.py'
+        with TemporaryDirectory() as td:
+            with open(pjoin(td, name), 'w') as f:
+                f.write("syntax error()")
+            with nt.assert_logs(app.log, logging.ERROR) as captured:
+                app.load_config_file(name, path=[td])
+        output = '\n'.join(captured.output)
+        self.assertIn('SyntaxError', output)
+    
+    def test_raise_on_bad_config(self):
+        app = MyApp()
+        app.raise_config_file_errors = True
+        app.log = logging.getLogger()
+        name = 'config.py'
+        with TemporaryDirectory() as td:
+            with open(pjoin(td, name), 'w') as f:
+                f.write("syntax error()")
+            with self.assertRaises(SyntaxError):
+                app.load_config_file(name, path=[td])
 
 
 class DeprecatedApp(Application):
@@ -235,6 +261,7 @@
         with mock.patch.object(self.log, 'debug', _capture):
             super(DeprecatedApp, self)._config_changed(name, old, new)
 
+
 def test_deprecated_notifier():
     app = DeprecatedApp()
     nt.assert_false(app.override_called)
@@ -242,4 +269,4 @@
     app.config = Config({'A': {'b': 'c'}})
     nt.assert_true(app.override_called)
     nt.assert_true(app.parent_called)
-    
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/traitlets-4.1.0/traitlets/config/tests/test_configurable.py 
new/traitlets-4.2.1/traitlets/config/tests/test_configurable.py
--- old/traitlets-4.1.0/traitlets/config/tests/test_configurable.py     
2016-01-13 11:14:04.000000000 +0100
+++ new/traitlets-4.2.1/traitlets/config/tests/test_configurable.py     
2016-03-10 09:53:45.000000000 +0100
@@ -4,11 +4,16 @@
 # Copyright (c) IPython Development Team.
 # Distributed under the terms of the Modified BSD License.
 
+import logging
 from unittest import TestCase
 
+import nose.tools as nt
+from nose import SkipTest
+
 from traitlets.config.configurable import (
-    Configurable, 
-    SingletonConfigurable
+    Configurable,
+    LoggingConfigurable,
+    SingletonConfigurable,
 )
 
 from traitlets.traitlets import (
@@ -103,7 +108,8 @@
         config.Bar.b = 'later'
         config.Bar.c = 100.0
         f = Foo(config=config)
-        b = Bar(config=f.config)
+        with expected_warnings(['`b` not recognized']):
+            b = Bar(config=f.config)
         self.assertEqual(f.a, 10)
         self.assertEqual(f.b, 'wow')
         self.assertEqual(b.b, 'gotit')
@@ -123,11 +129,13 @@
         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)
+        with expected_warnings(['`b` not recognized']):
+            c = Bar(config=config)
         self.assertEqual(c.a, config.Foo.a)
         self.assertEqual(c.b, 'gotit')
         self.assertEqual(c.c, config.Bar.c)
-        c = Bar(a=2, b='and', c=20.0, config=config)
+        with expected_warnings(['`b` not recognized']):
+            c = Bar(a=2, b='and', c=20.0, config=config)
         self.assertEqual(c.a, 2)
         self.assertEqual(c.b, 'and')
         self.assertEqual(c.c, 20.0)
@@ -411,4 +419,39 @@
         d2 = DefaultConfigurable()
         self.assertIs(d2.config, single.config)
         self.assertEqual(d2.a, 5)
-        
+
+
+def test_warn_match():
+    if not hasattr(nt, 'assert_logs'):
+        raise SkipTest("Test requires nose.tests.assert_logs")
+    class A(LoggingConfigurable):
+        foo = Integer(config=True)
+        bar = Integer(config=True)
+        baz = Integer(config=True)
+    
+    logger = logging.getLogger('test_warn_match')
+    
+    cfg = Config({'A': {'bat': 5}})
+    with nt.assert_logs(logger, logging.WARNING) as captured:
+        a = A(config=cfg, log=logger)
+    
+    output = '\n'.join(captured.output)
+    nt.assert_in('Did you mean one of: `bar, baz`?', output)
+    nt.assert_in('Config option `bat` not recognized by `A`.', output)
+
+    cfg = Config({'A': {'fool': 5}})
+    with nt.assert_logs(logger, logging.WARNING) as captured:
+        a = A(config=cfg, log=logger)
+    
+    output = '\n'.join(captured.output)
+    nt.assert_in('Config option `fool` not recognized by `A`.', output)
+    nt.assert_in('Did you mean `foo`?', output)
+
+    cfg = Config({'A': {'totally_wrong': 5}})
+    with nt.assert_logs(logger, logging.WARNING) as captured:
+        a = A(config=cfg, log=logger)
+
+    output = '\n'.join(captured.output)
+    nt.assert_in('Config option `totally_wrong` not recognized by `A`.', 
output)
+    nt.assert_not_in('Did you mean', output)
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/traitlets-4.1.0/traitlets/config/tests/test_loader.py 
new/traitlets-4.2.1/traitlets/config/tests/test_loader.py
--- old/traitlets-4.1.0/traitlets/config/tests/test_loader.py   2015-07-11 
05:20:55.000000000 +0200
+++ new/traitlets-4.2.1/traitlets/config/tests/test_loader.py   2016-02-17 
12:48:39.000000000 +0100
@@ -99,7 +99,45 @@
         cl = JSONFileConfigLoader(fname, log=log)
         config = cl.load_config()
         self._check_conf(config)
-    
+
+    def test_context_manager(self):
+
+        fd, fname = mkstemp('.json')
+        f = os.fdopen(fd, 'w')
+        f.write('{}')
+        f.close()
+
+        cl = JSONFileConfigLoader(fname, log=log)
+
+        value = 'context_manager'
+
+        with cl as c:
+            c.MyAttr.value = value
+
+        self.assertEqual(cl.config.MyAttr.value, value)
+
+        # check that another loader does see the change
+        cl2 = JSONFileConfigLoader(fname, log=log)
+        self.assertEqual(cl.config.MyAttr.value, value)
+
+    def test_json_context_bad_write(self):
+        fd, fname = mkstemp('.json')
+        f = os.fdopen(fd, 'w')
+        f.write('{}')
+        f.close()
+        
+        with JSONFileConfigLoader(fname, log=log) as config:
+            config.A.b = 1
+        
+        with self.assertRaises(TypeError):
+            with JSONFileConfigLoader(fname, log=log) as config:
+                config.A.cant_json = lambda x: x
+        
+        loader = JSONFileConfigLoader(fname, log=log)
+        cfg = loader.load_config()
+        assert cfg.A.b == 1
+        assert 'cant_json' not in cfg.A
+
     def test_collision(self):
         a = Config()
         b = Config()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/traitlets/tests/test_traitlets.py 
new/traitlets-4.2.1/traitlets/tests/test_traitlets.py
--- old/traitlets-4.1.0/traitlets/tests/test_traitlets.py       2016-01-11 
16:09:05.000000000 +0100
+++ new/traitlets-4.2.1/traitlets/tests/test_traitlets.py       2016-02-17 
16:36:08.000000000 +0100
@@ -22,7 +22,7 @@
     Union, All, Undefined, Type, This, Instance, TCPAddress, List, Tuple,
     ObjectName, DottedObjectName, CRegExp, link, directional_link,
     ForwardDeclaredType, ForwardDeclaredInstance, validate, observe, default,
-    observe_compat,
+    observe_compat, BaseDescriptor, HasDescriptors,
 )
 from ipython_genutils import py3compat
 from ipython_genutils.testing.decorators import skipif
@@ -266,6 +266,25 @@
         self.assertEqual(B.tt.this_class, B)
         self.assertEqual(B.ttt.this_class, B)
 
+class TestHasDescriptors(TestCase):
+
+    def test_setup_instance(self):
+
+        class FooDescriptor(BaseDescriptor):
+
+            def instance_init(self, inst):
+                foo = inst.foo # instance should have the attr
+
+        class HasFooDescriptors(HasDescriptors):
+
+            fd = FooDescriptor()
+
+            def setup_instance(self, *args, **kwargs):
+                self.foo = kwargs.get('foo', None)
+                super(HasFooDescriptors, self).setup_instance(*args, **kwargs)
+
+        hfd = HasFooDescriptors(foo='bar')
+
 class TestHasTraitsNotify(TestCase):
 
     def setUp(self):
@@ -1025,7 +1044,7 @@
 
         tree = Tree(
             value='foo',
-            leaves=[Tree('bar'), Tree('buzz')]
+            leaves=[Tree(value='bar'), Tree(value='buzz')]
         )
 
         with self.assertRaises(TraitError):
@@ -2163,3 +2182,33 @@
     obj.trait = 5
     nt.assert_true(obj.child_called)
     nt.assert_true(obj.parent_called)
+
+def test_super_args():
+    class SuperRecorder(object):
+        def __init__(self, *args, **kwargs):
+            self.super_args = args
+            self.super_kwargs = kwargs
+    
+    class SuperHasTraits(HasTraits, SuperRecorder):
+        i = Integer()
+    
+    obj = SuperHasTraits('a1', 'a2', b=10, i=5, c='x')
+    nt.assert_equal(obj.i, 5)
+    assert not hasattr(obj, 'b')
+    assert not hasattr(obj, 'c')
+    nt.assert_equal(obj.super_args, ('a1', 'a2'))
+    nt.assert_equal(obj.super_kwargs, {'b': 10, 'c': 'x'})
+
+def test_super_bad_args():
+    class SuperHasTraits(HasTraits):
+        a = Integer()
+    
+    if sys.version_info < (3,):
+        # Legacy Python, object.__init__ warns itself, instead of raising
+        w = ['object.__init__']
+    else:
+        w = ["Passing unrecoginized arguments"]
+    with expected_warnings(w):
+        obj = SuperHasTraits(a=1, b=2)
+    nt.assert_equal(obj.a, 1)
+    assert not hasattr(obj, 'b')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/traitlets/traitlets.py 
new/traitlets-4.2.1/traitlets/traitlets.py
--- old/traitlets-4.1.0/traitlets/traitlets.py  2016-01-15 17:57:59.000000000 
+0100
+++ new/traitlets-4.2.1/traitlets/traitlets.py  2016-03-14 20:37:18.000000000 
+0100
@@ -107,7 +107,7 @@
     try:
         fname = inspect.getsourcefile(method) or "<unknown>"
         lineno = inspect.getsourcelines(method)[1] or 0
-    except TypeError as e:
+    except (IOError, TypeError) as e:
         # Failed to inspect for some reason
         warn(warn_msg + ('\n(inspection failed) %s' % e), DeprecationWarning)
     else:
@@ -460,6 +460,7 @@
 
         This looks for:
 
+        * default generators registered with the @default descriptor.
         * obj._{name}_default() on the class with the traitlet, or a subclass
           that obj belongs to.
         * trait.make_dynamic_default, which is defined by Instance
@@ -486,17 +487,16 @@
         return getattr(self, 'make_dynamic_default', None)
 
     def instance_init(self, obj):
-        obj._cross_validation_lock = True
         # If no dynamic initialiser is present, and the trait implementation or
         # use provides a static default, transfer that to obj._trait_values.
-        if (self._dynamic_default_callable(obj) is None) \
-                and (self.default_value is not Undefined):
-            v = self._validate(obj, self.default_value)
-            if self.name is not None:
-                obj._trait_values[self.name] = v
-        obj._cross_validation_lock = False
+        with obj.cross_validation_lock:
+            if (self._dynamic_default_callable(obj) is None) \
+                    and (self.default_value is not Undefined):
+                v = self._validate(obj, self.default_value)
+                if self.name is not None:
+                    obj._trait_values[self.name] = v
 
-    def get(self, obj, cls):
+    def get(self, obj, cls=None):
         try:
             value = obj._trait_values[self.name]
         except KeyError:
@@ -800,7 +800,7 @@
     the registered cross validator could potentially make changes to attributes
     of the ``HasTraits`` instance. However, we recommend not to do so. The 
reason
     is that the cross-validation of attributes may run in arbitrary order when
-    exitting the ``hold_trait_modification` context, and such changes may not
+    exiting the ``hold_trait_notifications` context, and such changes may not
     commute.
     """
     return ValidateHandler(names)
@@ -899,18 +899,22 @@
     """The base class for all classes that have descriptors.
     """
 
-    def __new__(cls, *args, **kw):
+    def __new__(cls, *args, **kwargs):
         # This is needed because object.__new__ only accepts
         # the cls argument.
         new_meth = super(HasDescriptors, cls).__new__
         if new_meth is object.__new__:
             inst = new_meth(cls)
         else:
-            inst = new_meth(cls, **kw)
-        inst.setup_instance()
+            inst = new_meth(cls, *args, **kwargs)
+        inst.setup_instance(*args, **kwargs)
         return inst
 
-    def setup_instance(self):
+    def setup_instance(self, *args, **kwargs):
+        """
+        This is called **before** self.__init__ is called.
+        """
+        self._cross_validation_lock = False
         cls = self.__class__
         for key in dir(cls):
             # Some descriptors raise AttributeError like zope.interface's
@@ -927,20 +931,43 @@
 
 class HasTraits(py3compat.with_metaclass(MetaHasTraits, HasDescriptors)):
 
-    def setup_instance(self):
+    def setup_instance(self, *args, **kwargs):
         self._trait_values = {}
         self._trait_notifiers = {}
         self._trait_validators = {}
-        super(HasTraits, self).setup_instance()
+        super(HasTraits, self).setup_instance(*args, **kwargs)
 
-    def __init__(self, *args, **kw):
+    def __init__(self, *args, **kwargs):
         # Allow trait values to be set using keyword arguments.
         # We need to use setattr for this to trigger validation and
         # notifications.
-        self._cross_validation_lock = False
+        super_args = args
+        super_kwargs = {}
         with self.hold_trait_notifications():
-            for key, value in iteritems(kw):
-                setattr(self, key, value)
+            for key, value in iteritems(kwargs):
+                if self.has_trait(key):
+                    setattr(self, key, value)
+                else:
+                    # passthrough args that don't set traits to super
+                    super_kwargs[key] = value
+        try:
+            super(HasTraits, self).__init__(*super_args, **super_kwargs)
+        except TypeError as e:
+            arg_s_list = [ repr(arg) for arg in super_args ]
+            for k, v in super_kwargs.items():
+                arg_s_list.append("%s=%r" % (k, v))
+            arg_s = ', '.join(arg_s_list)
+            warn(
+                "Passing unrecoginized arguments to 
super({classname}).__init__({arg_s}).\n"
+                "{error}\n"
+                "This error will be raised in a future release of traitlets."
+                .format(
+                    arg_s=arg_s, classname=self.__class__.__name__,
+                    error=e,
+                ),
+                DeprecationWarning,
+                stacklevel=2,
+            )
 
     def __getstate__(self):
         d = self.__dict__.copy()
@@ -968,6 +995,23 @@
                 if isinstance(value, EventHandler):
                     value.instance_init(self)
 
+    @property
+    @contextlib.contextmanager
+    def cross_validation_lock(self):
+        """
+        A contextmanager for running a block with our cross validation lock set
+        to True.
+
+        At the end of the block, the lock's value is restored to its value
+        prior to entering the block.
+        """
+        original_value = self._cross_validation_lock
+        try:
+            self._cross_validation_lock = True
+            yield
+        finally:
+            self._cross_validation_lock = original_value
+
     @contextlib.contextmanager
     def hold_trait_notifications(self):
         """Context manager for bundling trait change notifications and cross
@@ -1010,7 +1054,7 @@
                 for name in list(cache.keys()):
                     trait = getattr(self.__class__, name)
                     value = trait._cross_validate(self, getattr(self, name))
-                    setattr(self, name, value)
+                    self.set_trait(name, value)
             except TraitError as e:
                 # Roll back in case of TraitError during final cross 
validation.
                 self.notify_change = lambda x: None
@@ -1019,7 +1063,7 @@
                         # TODO: Separate in a rollback function per 
notification type.
                         if change['type'] == 'change':
                             if change['old'] is not Undefined:
-                                setattr(self, name, change['old'])
+                                self.set_trait(name, change['old'])
                             else:
                                 self._trait_values.pop(name)
                 cache = {}
@@ -1077,7 +1121,7 @@
 
             if isinstance(c, _CallbackWrapper):
                 c = c.__call__
-            elif isinstance(c, EventHandler):
+            elif isinstance(c, EventHandler) and c.name is not None:
                 c = getattr(self, c.name)
             
             c(change)
@@ -1150,8 +1194,8 @@
         ----------
         handler : callable
             A callable that is called when a trait changes. Its
-            signature can be ``handler()`` or ``handler(change)``, where change
-            is a dictionary. The change dictionary at least holds a 'type' key.
+            signature should be ``handler(change)``, where ``change```is a
+            dictionary. The change dictionary at least holds a 'type' key.
             * ``type``: the type of notification.
             Other keys may be passed depending on the value of 'type'. In the
             case where type is 'change', we also have the following keys:
@@ -1224,10 +1268,6 @@
             The names of the traits that should be cross-validated
         """
         for name in names:
-            if name in self._trait_validators:
-                raise TraitError("A cross-validator for the trait"
-                                 " '%s' already exists" % name)
-
             magic_name = '_%s_validate' % name
             if hasattr(self, magic_name):
                 class_value = getattr(self.__class__, magic_name)
@@ -1350,11 +1390,12 @@
 
     def set_trait(self, name, value):
         """Forcibly sets trait attribute, including read-only attributes."""
+        cls = self.__class__
         if not self.has_trait(name):
-            raise TraitError("Class %s does not have a trait named %s" %
-                                (self.__class__.__name__, name))
+            raise TraitError("Class %s does not have a trait"
+                             "named %s" % (cls.__name__, name))
         else:
-            self.traits()[name].set(self, value)
+            getattr(cls, name).set(self, value)
 
 #-----------------------------------------------------------------------------
 # Actual TraitTypes implementations/subclasses
@@ -1662,8 +1703,7 @@
         super(Union, self).instance_init(obj)
 
     def validate(self, obj, value):
-        obj._cross_validation_lock = True
-        try:
+        with obj.cross_validation_lock:
             for trait_type in self.trait_types:
                 try:
                     v = trait_type._validate(obj, value)
@@ -1671,17 +1711,22 @@
                     return v
                 except TraitError:
                     continue
-        finally:
-            obj._cross_validation_lock = False
         self.error(obj, value)
 
-
     def __or__(self, other):
         if isinstance(other, Union):
             return Union(self.trait_types + other.trait_types)
         else:
             return Union(self.trait_types + [other])
 
+    def make_dynamic_default(self):
+        for trait_type in self.trait_types:
+            if trait_type.default_value != Undefined:
+                return trait_type.default_value
+            elif hasattr(trait_type, 'make_dynamic_default'):
+                return trait_type.make_dynamic_default()
+
+
 #-----------------------------------------------------------------------------
 # Basic TraitTypes implementations/subclasses
 #-----------------------------------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/traitlets.egg-info/PKG-INFO 
new/traitlets-4.2.1/traitlets.egg-info/PKG-INFO
--- old/traitlets-4.1.0/traitlets.egg-info/PKG-INFO     1970-01-01 
01:00:00.000000000 +0100
+++ new/traitlets-4.2.1/traitlets.egg-info/PKG-INFO     2016-03-14 
20:38:32.000000000 +0100
@@ -0,0 +1,21 @@
+Metadata-Version: 1.1
+Name: traitlets
+Version: 4.2.1
+Summary: Traitlets Python config system
+Home-page: http://ipython.org
+Author: IPython Development Team
+Author-email: ipython-...@scipy.org
+License: BSD
+Description: A configuration system for Python applications.
+Keywords: Interactive,Interpreter,Shell,Web
+Platform: Linux
+Platform: Mac OS X
+Platform: Windows
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: System Administrators
+Classifier: Intended Audience :: Science/Research
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/traitlets.egg-info/SOURCES.txt 
new/traitlets-4.2.1/traitlets.egg-info/SOURCES.txt
--- old/traitlets-4.1.0/traitlets.egg-info/SOURCES.txt  1970-01-01 
01:00:00.000000000 +0100
+++ new/traitlets-4.2.1/traitlets.egg-info/SOURCES.txt  2016-03-14 
20:38:32.000000000 +0100
@@ -0,0 +1,46 @@
+CONTRIBUTING.md
+COPYING.md
+MANIFEST.in
+README.md
+setup.cfg
+setup.py
+docs/Makefile
+docs/make.bat
+docs/requirements.txt
+docs/source/changelog.rst
+docs/source/conf.py
+docs/source/config.rst
+docs/source/defining_traits.rst
+docs/source/index.rst
+docs/source/migration.rst
+docs/source/trait_types.rst
+docs/source/using_traitlets.rst
+examples/myapp.py
+traitlets/__init__.py
+traitlets/_version.py
+traitlets/log.py
+traitlets/traitlets.py
+traitlets.egg-info/PKG-INFO
+traitlets.egg-info/SOURCES.txt
+traitlets.egg-info/dependency_links.txt
+traitlets.egg-info/requires.txt
+traitlets.egg-info/top_level.txt
+traitlets/config/__init__.py
+traitlets/config/application.py
+traitlets/config/configurable.py
+traitlets/config/loader.py
+traitlets/config/manager.py
+traitlets/config/tests/__init__.py
+traitlets/config/tests/test_application.py
+traitlets/config/tests/test_configurable.py
+traitlets/config/tests/test_loader.py
+traitlets/tests/__init__.py
+traitlets/tests/_warnings.py
+traitlets/tests/test_traitlets.py
+traitlets/tests/utils.py
+traitlets/utils/__init__.py
+traitlets/utils/getargspec.py
+traitlets/utils/importstring.py
+traitlets/utils/sentinel.py
+traitlets/utils/tests/__init__.py
+traitlets/utils/tests/test_importstring.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/traitlets-4.1.0/traitlets.egg-info/dependency_links.txt 
new/traitlets-4.2.1/traitlets.egg-info/dependency_links.txt
--- old/traitlets-4.1.0/traitlets.egg-info/dependency_links.txt 1970-01-01 
01:00:00.000000000 +0100
+++ new/traitlets-4.2.1/traitlets.egg-info/dependency_links.txt 2016-03-14 
20:38:32.000000000 +0100
@@ -0,0 +1 @@
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/traitlets.egg-info/requires.txt 
new/traitlets-4.2.1/traitlets.egg-info/requires.txt
--- old/traitlets-4.1.0/traitlets.egg-info/requires.txt 1970-01-01 
01:00:00.000000000 +0100
+++ new/traitlets-4.2.1/traitlets.egg-info/requires.txt 2016-03-14 
20:38:32.000000000 +0100
@@ -0,0 +1,2 @@
+ipython_genutils
+decorator
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/traitlets-4.1.0/traitlets.egg-info/top_level.txt 
new/traitlets-4.2.1/traitlets.egg-info/top_level.txt
--- old/traitlets-4.1.0/traitlets.egg-info/top_level.txt        1970-01-01 
01:00:00.000000000 +0100
+++ new/traitlets-4.2.1/traitlets.egg-info/top_level.txt        2016-03-14 
20:38:32.000000000 +0100
@@ -0,0 +1 @@
+traitlets


Reply via email to