Repository: ipython/traitlets
Pull request #384 (2017-03-22 01:32:08)

add `trait_values` method
Returns a ``dict`` of trait values via `getattr`. This is useful for parsing a `HasTraits` object into json.


Patch:
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 8d996bf..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-build: false
-
-environment:
-  matrix:
-   - PYTHON: "C:\\Python36-x64"
-     PYTHON_VERSION: "3.6.x"
-     PYTHON_ARCH: "64"
-
-   - PYTHON: "C:\\Python34-x64"
-     PYTHON_VERSION: "3.4.x"
-     PYTHON_ARCH: "32"
-
-   - PYTHON: "C:\\Python27-x64"
-     PYTHON_VERSION: "2.7.x"
-     PYTHON_ARCH: "64"
-
-init:
-  - "ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH%"
-
-install:
-  - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
-  - "%CMD_IN_ENV%  pip install --upgrade setuptools pip"
-  - "%CMD_IN_ENV%  pip install .[test]"
-  - "%CMD_IN_ENV%  mkdir results"
-  - "%CMD_IN_ENV%  cd results"
-test_script:
-  - "%CMD_IN_ENV%  pytest --pyargs -v traitlets"
diff --git a/traitlets/config/application.py b/traitlets/config/application.py
index 84380b4..45183cf 100644
--- a/traitlets/config/application.py
+++ b/traitlets/config/application.py
@@ -11,10 +11,8 @@ from copy import deepcopy
 import json
 import logging
 import os
-import pprint
 import re
 import sys
-
 from traitlets.config.configurable import Configurable, SingletonConfigurable
 from traitlets.config.loader import (
     KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound, JSONFileConfigLoader
@@ -238,29 +236,23 @@ class Application(SingletonConfigurable):
     #: the alias map for configurables
     #: Keys might strings or tuples for additional options; single-letter alias accessed like `-v`.
     #: Values might be like "Class.trait" strings of two-tuples: (Class.trait, help-text).
-    aliases = {'log-level' : 'Application.log_level'}
+    aliases = Dict({'log-level' : 'Application.log_level'})
 
     # flags for loading Configurables or store_const style flags
     # flags are loaded from this dict by '--key' flags
     # this must be a dict of two-tuples, the first element being the Config/dict
     # and the second being the help string for the flag
-    flags = {
-        'debug': ({
-            'Application': {
-                'log_level': logging.DEBUG,
-            },
-        }, "Set log-level to debug, for the most verbose logging."),
-        'show-config': ({
-            'Application': {
-                'show_config': True,
-            },
-        }, "Show the application's configuration (human-readable format)"),
-        'show-config-json': ({
-            'Application': {
-                'show_config_json': True,
-            },
-        }, "Show the application's configuration (json format)"),
-    }
+    flags = Dict()
+    @observe('flags')
+    @observe_compat
+    def _flags_changed(self, change):
+        """ensure flags dict is valid"""
+        new = change.new
+        for key, value in new.items():
+            assert len(value) == 2, "Bad flag: %r:%s" % (key, value)
+            assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s" % (key, value)
+            assert isinstance(value[1], six.string_types), "Bad flag: %r:%s" % (key, value)
+
 
     # subcommands for launching other applications
     # if this is not empty, this will be a parent Application
@@ -282,25 +274,6 @@ class Application(SingletonConfigurable):
         """
     )
 
-    _loaded_config_files = List()
-
-    show_config = Bool(
-        help="Instead of starting the Application, dump configuration to stdout"
-    ).tag(config=True)
-
-    show_config_json = Bool(
-        help="Instead of starting the Application, dump configuration to stdout (as JSON)"
-    ).tag(config=True)
-
-    @observe('show_config_json')
-    def _show_config_json_changed(self, change):
-        self.show_config = change.new
-
-    @observe('show_config')
-    def _show_config_changed(self, change):
-        if change.new:
-            self._save_start = self.start
-            self.start = self.start_show_config
 
     def __init__(self, **kwargs):
         SingletonConfigurable.__init__(self, **kwargs)
@@ -310,7 +283,7 @@ class Application(SingletonConfigurable):
         if cls not in self.classes:
             if self.classes is cls.classes:
                 # class attr, assign instead of insert
-                self.classes = [cls] + self.classes
+                cls.classes = [cls] + self.classes
             else:
                 self.classes.insert(0, self.__class__)
 
@@ -338,45 +311,6 @@ class Application(SingletonConfigurable):
         if self.subapp is not None:
             return self.subapp.start()
 
-    def start_show_config(self):
-        """start function used when show_config is True"""
-        config = self.config.copy()
-        # exclude show_config flags from displayed config
-        for cls in self.__class__.mro():
-            if cls.__name__ in config:
-                cls_config = config[cls.__name__]
-                cls_config.pop('show_config', None)
-                cls_config.pop('show_config_json', None)
-
-        if self.show_config_json:
-            json.dump(config, sys.stdout,
-                      indent=1, sort_keys=True, default=repr)
-            # add trailing newline
-            sys.stdout.write('\n')
-            return
-
-        if self._loaded_config_files:
-            print("Loaded config files:")
-            for f in self._loaded_config_files:
-                print('  ' + f)
-            print()
-
-        for classname in sorted(config):
-            class_config = config[classname]
-            if not class_config:
-                continue
-            print(classname)
-            pformat_kwargs = dict(indent=4)
-            if sys.version_info >= (3,4):
-                # use compact pretty-print on Pythons that support it
-                pformat_kwargs['compact'] = True
-            for traitname in sorted(class_config):
-                value = class_config[traitname]
-                print('  .{} = {}'.format(
-                    traitname,
-                    pprint.pformat(value, **pformat_kwargs),
-                ))
-
     def print_alias_help(self):
         """Print the alias part of the help."""
         if not self.aliases:
@@ -681,10 +615,10 @@ class Application(SingletonConfigurable):
             if log:
                 log.debug("Looking for %s in %s", basefilename, path or os.getcwd())
             jsonloader = cls.json_config_loader_class(basefilename+'.json', path=path, log=log)
+            config = None
             loaded = []
             filenames = []
             for loader in [pyloader, jsonloader]:
-                config = None
                 try:
                     config = loader.load_config()
                 except ConfigFileNotFound:
@@ -710,27 +644,29 @@ class Application(SingletonConfigurable):
                                 " {1} has higher priority: {2}".format(
                                 filename, loader.full_filename, json.dumps(collisions, indent=2),
                             ))
-                    yield (config, loader.full_filename)
+                    yield config
                     loaded.append(config)
                     filenames.append(loader.full_filename)
 
+
+
     @catch_config_error
     def load_config_file(self, filename, path=None):
         """Load config files by filename and path."""
         filename, ext = os.path.splitext(filename)
         new_config = Config()
-        for (config, filename) 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,
         ):
             new_config.merge(config)
-            self._loaded_config_files.append(filename)
         # add self.cli_config to preserve CLI config priority
         new_config.merge(self.cli_config)
         self.update_config(new_config)
 
+
     def _classes_with_config_traits(self, classes=None):
         """
-        Yields only classes with configurable traits, and their subclasses.
+        Yields only classes with own traits, and their subclasses.
 
         :param classes:
             The list of classes to iterate; if not set, uses :attr:`classes`.
@@ -766,14 +702,12 @@ class Application(SingletonConfigurable):
             if inc_yes:
                 yield cl
 
-    def generate_config_file(self, classes=None):
+    def generate_config_file(self):
         """generate default config file from Configurables"""
         lines = ["# Configuration file for %s." % self.name]
         lines.append('')
-        classes = self.classes if classes is None else classes
-        config_classes = list(self._classes_with_config_traits(classes))
-        for cls in config_classes:
-            lines.append(cls.class_config_section(config_classes))
+        for cls in self._classes_with_config_traits():
+            lines.append(cls.class_config_section())
         return '\n'.join(lines)
 
     def exit(self, exit_status=0):
@@ -794,9 +728,6 @@ class Application(SingletonConfigurable):
 # utility functions, for convenience
 #-----------------------------------------------------------------------------
 
-default_aliases = Application.aliases
-default_flags = Application.flags
-
 def boolean_flag(name, configurable, set_help='', unset_help=''):
     """Helper for building basic --trait, --no-trait flags.
 
@@ -839,7 +770,3 @@ def get_config():
         return Application.instance().config
     else:
         return Config()
-
-
-if __name__ == '__main__':
-    Application.launch_instance()
diff --git a/traitlets/config/configurable.py b/traitlets/config/configurable.py
index a6f742c..bb7ebad 100644
--- a/traitlets/config/configurable.py
+++ b/traitlets/config/configurable.py
@@ -79,17 +79,6 @@ class Configurable(HasTraits):
 
         # load kwarg traits, other than config
         super(Configurable, self).__init__(**kwargs)
-        
-        # record traits set by config
-        config_override_names = set()
-        def notice_config_override(change):
-            """Record traits set by both config and kwargs.
-
-            They will need to be overridden again after loading config.
-            """
-            if change.name in kwargs:
-                config_override_names.add(change.name)
-        self.observe(notice_config_override)
 
         # load config
         if config is not None:
@@ -104,11 +93,12 @@ class Configurable(HasTraits):
         else:
             # allow _config_default to return something
             self._load_config(self.config)
-        self.unobserve(notice_config_override)
-
-        for name in config_override_names:
-            setattr(self, name, kwargs[name])
 
+        # Ensure explicit kwargs are applied after loading config.
+        # This is usually redundant, but ensures config doesn't override
+        # explicitly assigned values.
+        for key, value in kwargs.items():
+            setattr(self, key, value)
 
     #-------------------------------------------------------------------------
     # Static trait notifiations
@@ -228,7 +218,7 @@ class Configurable(HasTraits):
         """
         assert inst is None or isinstance(inst, cls)
         final_help = []
-        base_classes = ', '.join(p.__name__ for p in cls.__bases__)
+        base_classes = ','.join(p.__name__ for p in cls.__bases__)
         final_help.append(u'%s(%s) options' % (cls.__name__, base_classes))
         final_help.append(len(final_help[0])*u'-')
         for k, v in sorted(cls.class_traits(config=True).items()):
@@ -270,10 +260,6 @@ class Configurable(HasTraits):
             helptext = '\n'.join(wrap_paragraphs(helptext, 76))
             lines.append(indent(helptext, 4))
 
-        if 'Enum' in trait.__class__.__name__:
-            # include Enum choices
-            lines.append(indent('Choices: %r' % (trait.values,)))
-
         if inst is not None:
             lines.append(indent('Current: %r' % getattr(inst, trait.name), 4))
         else:
@@ -285,6 +271,9 @@ class Configurable(HasTraits):
                 if len(dvr) > 64:
                     dvr = dvr[:61]+'...'
                 lines.append(indent('Default: %s' % dvr, 4))
+        if 'Enum' in trait.__class__.__name__:
+            # include Enum choices
+            lines.append(indent('Choices: %r' % (trait.values,)))
 
         return '\n'.join(lines)
 
@@ -294,41 +283,8 @@ class Configurable(HasTraits):
         print(cls.class_get_help(inst))
 
     @classmethod
-    def _defining_class(cls, trait, classes):
-        """Get the class that defines a trait
-
-        For reducing redundant help output in config files.
-        Returns the current class if:
-        - the trait is defined on this class, or
-        - the class where it is defined would not be in the config file
-
-        Parameters
-        ----------
-        trait: Trait
-            The trait to look for
-        classes: list
-            The list of other classes to consider for redundancy.
-            Will return `cls` even if it is not defined on `cls`
-            if the defining class is not in `classes`.
-        """
-        defining_cls = cls
-        for parent in cls.mro():
-            if issubclass(parent, Configurable) and \
-            parent in classes and \
-            parent.class_own_traits(config=True).get(trait.name, None) is trait:
-                defining_cls = parent
-        return defining_cls
-
-    @classmethod
-    def class_config_section(cls, classes=None):
-        """Get the config section for this class.
-        
-        Parameters
-        ----------
-        classes: list, optional
-            The list of other classes in the config file.
-            Used to reduce redundant information.
-        """
+    def class_config_section(cls):
+        """Get the config class config section"""
         def c(s):
             """return a commented, wrapped block."""
             s = '\n\n'.join(wrap_paragraphs(s, 78))
@@ -336,12 +292,8 @@ class Configurable(HasTraits):
             return '## ' + s.replace('\n', '\n#  ')
 
         # section header
-        breaker = '#' + '-' * 78
-        parent_classes = ', '.join(
-            p.__name__ for p in cls.__bases__
-            if issubclass(p, Configurable)
-        )
-
+        breaker = '#' + '-'*78
+        parent_classes = ','.join(p.__name__ for p in cls.__bases__)
         s = "# %s(%s) configuration" % (cls.__name__, parent_classes)
         lines = [breaker, s, breaker]
         # get the description trait
@@ -355,29 +307,9 @@ class Configurable(HasTraits):
             lines.append(c(desc))
             lines.append('')
 
-        for name, trait in sorted(cls.class_traits(config=True).items()):
-            default_repr = trait.default_value_repr()
-
-            if classes:
-                defining_class = cls._defining_class(trait, classes)
-            else:
-                defining_class = cls
-            if defining_class is cls:
-                # cls owns the trait, show full help
-                if trait.help:
-                    lines.append(c(trait.help))
-                if 'Enum' in type(trait).__name__:
-                    # include Enum choices
-                    lines.append('#  Choices: %r' % (trait.values,))
-                lines.append('#  Default: %s' % default_repr)
-            else:
-                # Trait appears multiple times and isn't defined here.
-                # Truncate help to first line + "See also Original.trait"
-                if trait.help:
-                    lines.append(c(trait.help.split('\n', 1)[0]))
-                lines.append('#  See also %s.%s' % (defining_class.__name__, name))
-
-            lines.append('# c.%s.%s = %s' % (cls.__name__, name, default_repr))
+        for name, trait in sorted(cls.class_own_traits(config=True).items()):
+            lines.append(c(trait.help))
+            lines.append('#c.%s.%s = %s' % (cls.__name__, name, trait.default_value_repr()))
             lines.append('')
         return '\n'.join(lines)
 
@@ -389,7 +321,7 @@ class Configurable(HasTraits):
         """
         lines = []
         classname = cls.__name__
-        for k, trait in sorted(cls.class_traits(config=True).items()):
+        for k, trait in sorted(cls.class_own_traits(config=True).items()):
             ttype = trait.__class__.__name__
 
             termline = classname + '.' + trait.name
@@ -412,7 +344,7 @@ class Configurable(HasTraits):
                     dvr = dvr[:61]+'...'
                 # Double up backslashes, so they get to the rendered docs
                 dvr = dvr.replace('\\n', '\\\\n')
-                lines.append(indent('Default: ``%s``' % dvr, 4))
+                lines.append('    Default: ``%s``' % dvr)
                 lines.append('')
 
             help = trait.help or 'No description'
@@ -515,8 +447,8 @@ class SingletonConfigurable(LoggingConfigurable):
             return cls._instance
         else:
             raise MultipleInstanceError(
-                "An incompatible sibling of '%s' is already instanciated"
-                " as singleton: %s" % (cls.__name__, type(cls._instance).__name__)
+                'Multiple incompatible subclass instances of '
+                '%s are being created.' % cls.__name__
             )
 
     @classmethod
diff --git a/traitlets/config/loader.py b/traitlets/config/loader.py
index 2734524..68c0b68 100644
--- a/traitlets/config/loader.py
+++ b/traitlets/config/loader.py
@@ -16,7 +16,7 @@ from ast import literal_eval
 from ipython_genutils.path import filefind
 from ipython_genutils import py3compat
 from ipython_genutils.encoding import DEFAULT_ENCODING
-from six import text_type, string_types, PY3
+from six import text_type, string_types
 from traitlets.traitlets import (
     HasTraits, Container, List, Dict, Any,
 )
@@ -492,12 +492,8 @@ class PyFileConfigLoader(FileConfigLoader):
             get_config=get_config,
             __file__=self.full_filename,
         )
-        # encode filename to bytes only on py2 on non-Windows:
-        if PY3 or sys.platform.startswith('win'):
-            conf_filename = self.full_filename
-        else:
-            fs_encoding = sys.getfilesystemencoding() or 'ascii'
-            conf_filename = self.full_filename.encode(fs_encoding)
+        fs_encoding = sys.getfilesystemencoding() or 'ascii'
+        conf_filename = self.full_filename.encode(fs_encoding)
         py3compat.execfile(conf_filename, namespace)
 
 
diff --git a/traitlets/traitlets.py b/traitlets/traitlets.py
index 2874539..1a61274 100644
--- a/traitlets/traitlets.py
+++ b/traitlets/traitlets.py
@@ -270,15 +270,11 @@ class link(object):
     def __init__(self, source, target):
         _validate_link(source, target)
         self.source, self.target = source, target
-        self.link()
-
-    def link(self):
         try:
-            setattr(self.target[0], self.target[1],
-                    getattr(self.source[0], self.source[1]))
+            setattr(target[0], target[1], getattr(source[0], source[1]))
         finally:
-            self.source[0].observe(self._update_target, names=self.source[1])
-            self.target[0].observe(self._update_source, names=self.target[1])
+            source[0].observe(self._update_target, names=source[1])
+            target[0].observe(self._update_source, names=target[1])
 
     @contextlib.contextmanager
     def _busy_updating(self):
@@ -303,6 +299,7 @@ class link(object):
     def unlink(self):
         self.source[0].unobserve(self._update_target, names=self.source[1])
         self.target[0].unobserve(self._update_source, names=self.target[1])
+        self.source, self.target = None, None
 
 
 class directional_link(object):
@@ -328,12 +325,9 @@ class directional_link(object):
         self._transform = transform if transform else lambda x: x
         _validate_link(source, target)
         self.source, self.target = source, target
-        self.link()
-
-    def link(self):
         try:
-            setattr(self.target[0], self.target[1],
-                    self._transform(getattr(self.source[0], self.source[1])))
+            setattr(target[0], target[1],
+                    self._transform(getattr(source[0], source[1])))
         finally:
             self.source[0].observe(self._update, names=self.source[1])
 
@@ -354,6 +348,7 @@ class directional_link(object):
 
     def unlink(self):
         self.source[0].unobserve(self._update, names=self.source[1])
+        self.source, self.target = None, None
 
 dlink = directional_link
 
@@ -528,12 +523,6 @@ class TraitType(BaseDescriptor):
                     type(self).__name__, self.name, obj))
             value = self._validate(obj, default)
             obj._trait_values[self.name] = value
-            obj.notify_change(Bunch(
-                name=self.name,
-                value=value,
-                owner=obj,
-                type='default',
-            ))
             return value
         except Exception:
             # This should never be reached.
@@ -1176,7 +1165,7 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)):
 
         # Now static ones
         magic_name = '_%s_changed' % name
-        if change.type == "change" and hasattr(self, magic_name):
+        if hasattr(self, magic_name):
             class_value = getattr(self.__class__, magic_name)
             if not isinstance(class_value, ObserveHandler):
                 _deprecated_method(class_value, self.__class__, magic_name,
@@ -1423,6 +1412,28 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)):
         """Returns True if the object has a trait with the specified name."""
         return isinstance(getattr(self.__class__, name, None), TraitType)
 
+    def trait_values(self, **metadata):
+        """A ``dict`` of trait names and their values.
+
+        The metadata kwargs allow functions to be passed in which
+        filter traits based on metadata values.  The functions should
+        take a single value as an argument and return a boolean.  If
+        any function returns False, then the trait is not included in
+        the output.  If a metadata key doesn't exist, None will be passed
+        to the function.
+
+        Returns
+        -------
+        A ``dict`` of trait names and their values.
+
+        Notes
+        -----
+        Trait values are retrieved via ``getattr``, any exceptions raised
+        by traits or the operations they may trigger will result in the
+        absence of a trait value in the result ``dict``.
+        """
+        return {name: getattr(self, name) for name in self.trait_names(**metadata)}
+
     def trait_defaults(self, *names, **metadata):
         """Return a trait's default value or a dictionary of them
 


Test patch:
diff --git a/traitlets/config/tests/test_application.py b/traitlets/config/tests/test_application.py
index 87cb845..7f2757b 100644
--- a/traitlets/config/tests/test_application.py
+++ b/traitlets/config/tests/test_application.py
@@ -26,25 +26,20 @@ from pytest import mark
 
 from traitlets.config.configurable import Configurable
 from traitlets.config.loader import Config
-from traitlets.tests.utils import get_output_error_code, check_help_output, check_help_all_output
+from traitlets.tests.utils import check_help_output, check_help_all_output
 
 from traitlets.config.application import (
     Application
 )
 
 from ipython_genutils.tempdir import TemporaryDirectory
-from traitlets import (
-    HasTraits,
+from traitlets.traitlets import (
     Bool, Unicode, Integer, List, Tuple, Set, Dict
 )
 
 class Foo(Configurable):
 
-    i = Integer(0, help="""
-    The integer i.
-
-    Details about i.
-    """).tag(config=True)
+    i = Integer(0, help="The integer i.").tag(config=True)
     j = Integer(1, help="The integer j.").tag(config=True)
     name = Unicode(u'Brian', help="First name.").tag(config=True)
     la = List([]).tag(config=True)
@@ -69,9 +64,7 @@ class MyApp(Application):
     warn_tpyo = Unicode(u"yes the name is wrong on purpose", config=True,
             help="Should print a warning if `MyApp.warn-typo=...` command is passed")
 
-    aliases = {}
-    aliases.update(Application.aliases)
-    aliases.update({
+    aliases = Dict({
                     ('fooi', 'i') : 'Foo.i',
                     ('j', 'fooj') : ('Foo.j', "`j` terse help msg"),
                     'name' : 'Foo.name',
@@ -82,9 +75,7 @@ class MyApp(Application):
                     'log-level' : 'Application.log_level',
                 })
 
-    flags = {}
-    flags.update(Application.flags)
-    flags.update({('enable', 'e'):
+    flags = Dict({('enable', 'e'):
                         ({'Bar': {'enabled' : True}},
                          "Set Bar.enabled to True"),
                   ('d', 'disable'):
@@ -123,7 +114,7 @@ class TestApplication(TestCase):
         app = MyApp()
         self.assertEqual(app.name, u'myapp')
         self.assertEqual(app.running, False)
-        self.assertEqual(app.classes, [MyApp, Bar, Foo])
+        self.assertEqual(app.classes, [MyApp,Bar,Foo])
         self.assertEqual(app.config_file, u'')
 
     def test_mro_discovery(self):
@@ -415,38 +406,17 @@ class TestApplication(TestCase):
         assert 'The integer b.' in app.generate_config_file()
 
     def test_generate_config_file_classes_to_include(self):
-        class NotInConfig(HasTraits):
-            from_hidden = Unicode('x', help="""From hidden class
-            
-            Details about from_hidden.
-            """).tag(config=True)
-
-        class NoTraits(Foo, Bar, NotInConfig):
+        class NoTraits(Foo, Bar):
             pass
 
         app = MyApp()
         app.classes.append(NoTraits)
-
         conf_txt = app.generate_config_file()
-        print(conf_txt)
         self.assertIn('The integer b.', conf_txt)
+        self.assertIn('# Bar(Configurable)', conf_txt)
         self.assertIn('# Foo(Configurable)', conf_txt)
         self.assertNotIn('# Configurable', conf_txt)
-        self.assertIn('# NoTraits(Foo, Bar)', conf_txt)
-
-        # inherited traits, parent in class list:
-        self.assertIn('# c.NoTraits.i', conf_txt)
-        self.assertIn('# c.NoTraits.j', conf_txt)
-        self.assertIn('# c.NoTraits.n', conf_txt)
-        self.assertIn('#  See also Foo.j', conf_txt)
-        self.assertIn('#  See also Bar.b', conf_txt)
-        self.assertEqual(conf_txt.count('Details about i.'), 1)
-
-        # inherited traits, parent not in class list:
-        self.assertIn("# c.NoTraits.from_hidden", conf_txt)
-        self.assertNotIn('#  See also NotInConfig.', conf_txt)
-        self.assertEqual(conf_txt.count('Details about from_hidden.'), 1)
-        self.assertNotIn("NotInConfig", conf_txt)
+        self.assertIn('# NoTraits(Foo,Bar)', conf_txt)
 
     def test_multi_file(self):
         app = MyApp()
@@ -592,45 +562,6 @@ def test_help_output():
     check_help_output(__name__)
     check_help_all_output(__name__)
 
-
-def test_show_config_cli():
-    out, err, ec = get_output_error_code([sys.executable, '-m', __name__, '--show-config'])
-    assert ec == 0
-    assert 'show_config' not in out
-
-
-def test_show_config_json_cli():
-    out, err, ec = get_output_error_code([sys.executable, '-m', __name__, '--show-config-json'])
-    assert ec == 0
-    assert 'show_config' not in out
-
-
-def test_show_config(capsys):
-    cfg = Config()
-    cfg.MyApp.i = 5
-    # don't show empty
-    cfg.OtherApp
-    
-    app = MyApp(config=cfg, show_config=True)
-    app.start()
-    out, err = capsys.readouterr()
-    assert 'MyApp' in out
-    assert 'i = 5' in out
-    assert 'OtherApp' not in out
-
-
-def test_show_config_json(capsys):
-    cfg = Config()
-    cfg.MyApp.i = 5
-    cfg.OtherApp
-    
-    app = MyApp(config=cfg, show_config_json=True)
-    app.start()
-    out, err = capsys.readouterr()
-    displayed = json.loads(out)
-    assert Config(displayed) == cfg
-
-
 if __name__ == '__main__':
     # for test_help_output:
     MyApp.launch_instance()
diff --git a/traitlets/config/tests/test_configurable.py b/traitlets/config/tests/test_configurable.py
index 4baa106..b3ccae1 100644
--- a/traitlets/config/tests/test_configurable.py
+++ b/traitlets/config/tests/test_configurable.py
@@ -6,7 +6,6 @@
 
 import logging
 import sys
-import warnings
 from unittest import TestCase
 
 from pytest import mark
@@ -18,8 +17,8 @@ from traitlets.config.configurable import (
 )
 
 from traitlets.traitlets import (
-    Integer, Float, Unicode, List, Dict, Set, Enum,
-    _deprecations_shown, validate,
+    Integer, Float, Unicode, List, Dict, Set,
+    _deprecations_shown,
 )
 
 from traitlets.config.loader import Config
@@ -186,46 +185,6 @@ class TestConfigurable(TestCase):
         inst = MyConfigurable(a=5, b=4)
         self.assertEqual(MyConfigurable.class_get_help(inst), mc_help_inst)
 
-    def test_generated_config_enum_comments(self):
-        class MyConf(Configurable):
-            an_enum = Enum('Choice1 choice2'.split(),
-                           help="Many choices.").tag(config=True)
-
-        help_str = "Many choices."
-        enum_choices_str = "Choices: ['Choice1', 'choice2']"
-
-        self.assertIn(help_str, MyConf.class_get_help())
-        self.assertIn(enum_choices_str, MyConf.class_get_help())
-
-        self.assertIn(help_str, MyConf.class_config_section())
-        self.assertIn(enum_choices_str, MyConf.class_config_section())
-        ## Check order of Help-msg <--> Choices sections
-        self.assertGreater(MyConf.class_config_section().index(enum_choices_str),
-                           MyConf.class_config_section().index(help_str))
-
-        class MyConf2(Configurable):
-            an_enum = Enum('Choice1 choice2'.split(),
-                           default_value='choice2',
-                           help="Many choices.").tag(config=True)
-
-        defaults_str = "Default: 'choice2'"
-
-        self.assertIn(help_str, MyConf2.class_get_help())
-        self.assertIn(enum_choices_str, MyConf2.class_get_help())
-        self.assertIn(defaults_str, MyConf2.class_get_help())
-        ## Check order of Default <--> Choices sections
-        self.assertGreater(MyConf2.class_get_help().index(defaults_str),
-                           MyConf2.class_get_help().index(enum_choices_str))
-
-        self.assertIn(help_str, MyConf2.class_config_section())
-        self.assertIn(enum_choices_str, MyConf2.class_config_section())
-        self.assertIn(defaults_str, MyConf2.class_config_section())
-        ## Check order of Default <--> Choices sections
-        self.assertGreater(MyConf2.class_config_section().index(defaults_str),
-                           MyConf2.class_config_section().index(enum_choices_str))
-
-
-
 
 class TestSingletonConfigurable(TestCase):
 
@@ -499,32 +458,6 @@ class TestConfigContainers(TestCase):
         d2 = DefaultConfigurable()
         self.assertIs(d2.config, single.config)
         self.assertEqual(d2.a, 5)
-    
-    def test_kwarg_config_priority(self):
-        # a, c set in kwargs
-        # a, b set in config
-        # verify that:
-        # - kwargs are set before config
-        # - kwargs have priority over config
-        class A(Configurable):
-            a = Unicode('default', config=True)
-            b = Unicode('default', config=True)
-            c = Unicode('default', config=True)
-            c_during_config = Unicode('never')
-            @validate('b')
-            def _record_c(self, proposal):
-                # setting b from config records c's value at the time
-                self.c_during_config = self.c
-                return proposal.value
-
-        cfg = Config()
-        cfg.A.a = 'a-config'
-        cfg.A.b = 'b-config'
-        obj = A(a='a-kwarg', c='c-kwarg', config=cfg)
-        assert obj.a == 'a-kwarg'
-        assert obj.b == 'b-config'
-        assert obj.c == 'c-kwarg'
-        assert obj.c_during_config == 'c-kwarg'
 
 
 class TestLogger(TestCase):
diff --git a/traitlets/config/tests/test_loader.py b/traitlets/config/tests/test_loader.py
index bfbce5c..7a1ac3d 100644
--- a/traitlets/config/tests/test_loader.py
+++ b/traitlets/config/tests/test_loader.py
@@ -78,7 +78,7 @@ class TestFileCL(TestCase):
         self.assertEqual(config.D.C.value, 'hi there')
 
     def test_python(self):
-        fd, fname = mkstemp('.py', prefix=u'μnïcø∂e')
+        fd, fname = mkstemp('.py')
         f = os.fdopen(fd, 'w')
         f.write(pyfile)
         f.close()
@@ -88,7 +88,7 @@ class TestFileCL(TestCase):
         self._check_conf(config)
 
     def test_json(self):
-        fd, fname = mkstemp('.json', prefix=u'μnïcø∂e')
+        fd, fname = mkstemp('.json')
         f = os.fdopen(fd, 'w')
         f.write(json1file)
         f.close()
@@ -99,7 +99,7 @@ class TestFileCL(TestCase):
 
     def test_context_manager(self):
 
-        fd, fname = mkstemp('.json', prefix=u'μnïcø∂e')
+        fd, fname = mkstemp('.json')
         f = os.fdopen(fd, 'w')
         f.write('{}')
         f.close()
@@ -118,7 +118,7 @@ class TestFileCL(TestCase):
         self.assertEqual(cl.config.MyAttr.value, value)
 
     def test_json_context_bad_write(self):
-        fd, fname = mkstemp('.json', prefix=u'μnïcø∂e')
+        fd, fname = mkstemp('.json')
         f = os.fdopen(fd, 'w')
         f.write('{}')
         f.close()
@@ -164,7 +164,7 @@ class TestFileCL(TestCase):
         })
 
     def test_v2raise(self):
-        fd, fname = mkstemp('.json', prefix=u'μnïcø∂e')
+        fd, fname = mkstemp('.json')
         f = os.fdopen(fd, 'w')
         f.write(json2file)
         f.close()
diff --git a/traitlets/tests/test_traitlets.py b/traitlets/tests/test_traitlets.py
index 3a81e88..b3efaa2 100644
--- a/traitlets/tests/test_traitlets.py
+++ b/traitlets/tests/test_traitlets.py
@@ -3,7 +3,7 @@
 
 # Copyright (c) IPython Development Team.
 # Distributed under the terms of the Modified BSD License.
-#
+# 
 # Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
 # also under the terms of the Modified BSD License.
 
@@ -521,29 +521,29 @@ class TestHasTraitsNotify(TestCase):
 
         class A(HasTraits):
             listen_to = ['a']
-
+            
             a = Int(0)
             b = 0
-
+            
             def __init__(self, **kwargs):
                 super(A, self).__init__(**kwargs)
                 self.on_trait_change(self.listener1, ['a'])
-
+            
             def listener1(self, name, old, new):
                 self.b += 1
 
         class B(A):
-
+                    
             c = 0
             d = 0
-
+            
             def __init__(self, **kwargs):
                 super(B, self).__init__(**kwargs)
                 self.on_trait_change(self.listener2)
-
+            
             def listener2(self, name, old, new):
                 self.c += 1
-
+            
             def _a_changed(self, name, old, new):
                 self.d += 1
 
@@ -653,7 +653,7 @@ class TestObserveDecorator(TestCase):
             b = Int()
             _notify1 = []
             _notify_any = []
-
+            
             @observe('a')
             def _a_changed(self, change):
                 self._notify1.append(change)
@@ -717,29 +717,29 @@ class TestObserveDecorator(TestCase):
 
         class A(HasTraits):
             listen_to = ['a']
-
+            
             a = Int(0)
             b = 0
-
+            
             def __init__(self, **kwargs):
                 super(A, self).__init__(**kwargs)
                 self.observe(self.listener1, ['a'])
-
+            
             def listener1(self, change):
                 self.b += 1
 
         class B(A):
-
+                    
             c = 0
             d = 0
-
+            
             def __init__(self, **kwargs):
                 super(B, self).__init__(**kwargs)
                 self.observe(self.listener2)
-
+            
             def listener2(self, change):
                 self.c += 1
-
+            
             @observe('a')
             def _a_changed(self, change):
                 self.d += 1
@@ -839,7 +839,7 @@ class TestHasTraits(TestCase):
             def __init__(self, i):
                 super(A, self).__init__()
                 self.i = i
-
+        
         a = A(5)
         self.assertEqual(a.i, 5)
         # should raise TypeError if no positional arg given
@@ -1499,7 +1499,7 @@ class TestList(TraitTestBase):
     _default_value = []
     _good_values = [[], [1], list(range(10)), (1,2)]
     _bad_values = [10, [1,'a'], 'a']
-
+    
     def coerce(self, value):
         if value is not None:
             value = list(value)
@@ -1509,7 +1509,7 @@ class Foo(object):
     pass
 
 class NoneInstanceListTrait(HasTraits):
-
+    
     value = List(Instance(Foo))
 
 class TestNoneInstanceList(TraitTestBase):
@@ -1575,7 +1575,7 @@ class TestTupleTrait(TraitTestBase):
 
     obj = TupleTrait()
 
-    _default_value = (1,)
+    _default_value = (1,) 
     _good_values = [(1,), (0,), [1]]
     _bad_values = [10, (1, 2), ('a'), (), None]
 
@@ -1647,7 +1647,7 @@ def test_dict_assignment():
     c = DictTrait()
     c.value = d
     d['a'] = 5
-    assert d == c.value
+    assert d == c.value  
     assert c.value is d
 
 
@@ -1745,7 +1745,7 @@ class TestValidationHook(TestCase):
                 if self.parity == 'odd' and (value % 2 == 0):
                     raise TraitError('Expected an odd number')
                 return value
-
+        
         u = Parity()
         u.parity = 'odd'
         u.value = 1  # OK
@@ -1827,8 +1827,8 @@ class TestLink(TestCase):
         b.count = 4
         self.assertEqual(a.value, b.count)
 
-    def test_unlink_link(self):
-        """Verify two linked traitlets can be unlinked and relinked."""
+    def test_unlink(self):
+        """Verify two linked traitlets can be unlinked."""
 
         # Create two simple classes with Int traitlets.
         class A(HasTraits):
@@ -1844,10 +1844,6 @@ class TestLink(TestCase):
         # Change one of the values to make sure they don't stay in sync.
         a.value = 5
         self.assertNotEqual(a.value, b.value)
-        c.link()
-        self.assertEqual(a.value, b.value)
-        a.value += 1
-        self.assertEqual(a.value, b.value)
 
     def test_callbacks(self):
         """Verify two linked traitlets have their callbacks called once."""
@@ -1859,7 +1855,7 @@ class TestLink(TestCase):
             count = Int()
         a = A(value=9)
         b = B(count=8)
-
+        
         # Register callbacks that count.
         callback_count = []
         def a_callback(name, old, new):
@@ -1955,8 +1951,8 @@ class TestDirectionalLink(TestCase):
         b.value = 6
         self.assertEqual(a.value, 5)
 
-    def test_unlink_link(self):
-        """Verify two linked traitlets can be unlinked and relinked."""
+    def test_unlink(self):
+        """Verify two linked traitlets can be unlinked."""
 
         # Create two simple classes with Int traitlets.
         class A(HasTraits):
@@ -1972,10 +1968,6 @@ class TestDirectionalLink(TestCase):
         # Change one of the values to make sure they don't stay in sync.
         a.value = 5
         self.assertNotEqual(a.value, b.value)
-        c.link()
-        self.assertEqual(a.value, b.value)
-        a.value += 1
-        self.assertEqual(a.value, b.value)
 
 class Pickleable(HasTraits):
 
@@ -1987,7 +1979,7 @@ class Pickleable(HasTraits):
         return commit['value']
 
     j = Int()
-
+    
     def __init__(self):
         with self.hold_trait_notifications():
             self.i = 1
@@ -2092,7 +2084,7 @@ def test_cache_modification():
 
 class OrderTraits(HasTraits):
     notified = Dict()
-
+    
     a = Unicode()
     b = Unicode()
     c = Unicode()
@@ -2105,10 +2097,10 @@ class OrderTraits(HasTraits):
     j = Unicode()
     k = Unicode()
     l = Unicode()
-
+    
     def _notify(self, name, old, new):
         """check the value of all traits when each trait change is triggered
-
+        
         This verifies that the values are not sensitive
         to dict ordering when loaded from kwargs
         """
@@ -2117,7 +2109,7 @@ class OrderTraits(HasTraits):
         self.notified[name] = {
             c: getattr(self, c) for c in 'abcdefghijkl'
         }
-
+    
     def __init__(self, **kwargs):
         self.on_trait_change(self._notify)
         super(OrderTraits, self).__init__(**kwargs)
@@ -2311,7 +2303,7 @@ def test_default_value_repr():
         n = Integer(0)
         lis = List()
         d = Dict()
-
+    
     assert C.t.default_value_repr() == "'traitlets.HasTraits'"
     assert C.t2.default_value_repr() == "'traitlets.traitlets.HasTraits'"
     assert C.n.default_value_repr() == '0'
@@ -2320,7 +2312,7 @@ def test_default_value_repr():
 
 
 class TransitionalClass(HasTraits):
-
+    
     d = Any()
     @default('d')
     def _d_default(self):
@@ -2328,19 +2320,19 @@ class TransitionalClass(HasTraits):
 
     parent_super = False
     calls_super = Integer(0)
-
+    
     @default('calls_super')
     def _calls_super_default(self):
         return -1
-
+    
     @observe('calls_super')
     @observe_compat
     def _calls_super_changed(self, change):
         self.parent_super = change
-
+    
     parent_override = False
     overrides = Integer(0)
-
+    
     @observe('overrides')
     @observe_compat
     def _overrides_changed(self, change):
@@ -2350,12 +2342,12 @@ class TransitionalClass(HasTraits):
 class SubClass(TransitionalClass):
     def _d_default(self):
         return SubClass
-
+    
     subclass_super = False
     def _calls_super_changed(self, name, old, new):
         self.subclass_super = True
         super(SubClass, self)._calls_super_changed(name, old, new)
-
+    
     subclass_override = False
     def _overrides_changed(self, name, old, new):
         self.subclass_override = True
@@ -2374,7 +2366,7 @@ def test_subclass_compat():
 
 class DefinesHandler(HasTraits):
     parent_called = False
-
+    
     trait = Integer()
     @observe('trait')
     def handler(self, change):
@@ -2383,7 +2375,7 @@ class DefinesHandler(HasTraits):
 
 class OverridesHandler(DefinesHandler):
     child_called = False
-
+    
     @observe('trait')
     def handler(self, change):
         self.child_called = True
@@ -2398,7 +2390,7 @@ def test_subclass_override_observer():
 
 class DoesntRegisterHandler(DefinesHandler):
     child_called = False
-
+    
     def handler(self, change):
         self.child_called = True
 
@@ -2413,7 +2405,7 @@ def test_subclass_override_not_registered():
 
 class AddsHandler(DefinesHandler):
     child_called = False
-
+    
     @observe('trait')
     def child_handler(self, change):
         self.child_called = True
@@ -2470,10 +2462,10 @@ def test_super_args():
         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')
     assert obj.i ==  5
     assert not hasattr(obj, 'b')
@@ -2484,7 +2476,7 @@ def test_super_args():
 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__']
@@ -2492,7 +2484,7 @@ def test_super_bad_args():
         w = ["Passing unrecoginized arguments"]
     with expected_warnings(w):
         obj = SuperHasTraits(a=1, b=2)
-    assert obj.a ==  1
+    assert obj.a ==  1 
     assert not hasattr(obj, 'b')