Repository: ipython/ipython

Issue:
`Config.__deepcopy__` barfs if it holds a `logging.Logger` that was acquired with `getLogger`.
Minimal repro config file for ipython_config.py:

```
c = get_config()  # noqa

import logging
c.Test.arglebargle = logging.getLogger('test')
```

This results in the following stack trace for me on Ubuntu 14.04, IPython 3.0, Python 2.7.6:

```
Traceback (most recent call last):
  File "/home/ssanderson/.virtualenvs/test/bin/ipython", line 11, in <module>
    sys.exit(start_ipython())
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/__init__.py", line 120, in start_ipython
    return launch_new_instance(argv=argv, **kwargs)
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/config/application.py", line 573, in launch_instance
    app.initialize(argv)
  File "<string>", line 2, in initialize
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/config/application.py", line 75, in catch_config_error
    return method(app, *args, **kwargs)
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/terminal/ipapp.py", line 321, in initialize
    super(TerminalIPythonApp, self).initialize(argv)
  File "<string>", line 2, in initialize
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/config/application.py", line 75, in catch_config_error
    return method(app, *args, **kwargs)
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/core/application.py", line 377, in initialize
    self.load_config_file()
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/core/application.py", line 241, in load_config_file
    path=self.config_file_paths
  File "<string>", line 2, in load_config_file
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/config/application.py", line 75, in catch_config_error
    return method(app, *args, **kwargs)
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/config/application.py", line 542, in load_config_file
    self.update_config(config)
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/config/application.py", line 391, in update_config
    newconfig.merge(config)
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/config/loader.py", line 186, in merge
    to_update[k] = copy.deepcopy(v)
  File "/usr/lib/python2.7/copy.py", line 174, in deepcopy
    y = copier(memo)
  File "/home/ssanderson/.virtualenvs/test/local/lib/python2.7/site-packages/IPython/config/loader.py", line 241, in __deepcopy__
    return type(self)(copy.deepcopy(list(self.items())))
  File "/usr/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python2.7/copy.py", line 230, in _deepcopy_list
    y.append(deepcopy(a, memo))
  File "/usr/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python2.7/copy.py", line 237, in _deepcopy_tuple
    y.append(deepcopy(a, memo))
  File "/usr/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python2.7/copy.py", line 230, in _deepcopy_list
    y.append(deepcopy(a, memo))
  File "/usr/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/lib/python2.7/copy.py", line 19  # noqa  # noqa

0, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/lib/python2.7/copy.py", line 334, in _reconstruct
    state = deepcopy(state, memo)
  File "/usr/lib/python2.7/copy.py", line 163, in deepcopy
    y = copier(x, memo)
  File "/usr/lib/python2.7/copy.py", line 257, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/usr/lib/python2.7/copy.py", line 190, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/usr/lib/python2.7/copy.py", line 329, in _reconstruct
    y = callable(*args)
  File "/home/ssanderson/.virtualenvs/test/lib/python2.7/copy_reg.py", line 93, in __newobj__
    return cls.__new__(cls, *args)
TypeError: object.__new__(thread.lock) is not safe, use thread.lock.__new__()

```

Interestingly, it doesn't barf on the following config file:

```
c = get_config()

import logging
c.Test.arglebargle = logging.Logger('test')
```



Discussion:
Also notable: this fails differently on Python 3.4.

```
(jupyterhub)[~/quantopian/qexec]@(error_messages:77e951ab70)$ ipython --profile test
Traceback (most recent call last):
  File "/home/ssanderson/.virtualenvs/jupyterhub/bin/ipython", line 11, in <module>
    sys.exit(start_ipython())
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/__init__.py", line 120, in start_ipython
    return launch_new_instance(argv=argv, **kwargs)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/config/application.py", line 573, in launch_instance
    app.initialize(argv)
  File "<string>", line 2, in initialize
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/config/application.py", line 75, in catch_config_error
    return method(app, *args, **kwargs)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/terminal/ipapp.py", line 321, in initialize
    super(TerminalIPythonApp, self).initialize(argv)
  File "<string>", line 2, in initialize
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/config/application.py", line 75, in catch_config_error
    return method(app, *args, **kwargs)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/core/application.py", line 377, in initialize
    self.load_config_file()
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/core/application.py", line 241, in load_config_file
    path=self.config_file_paths
  File "<string>", line 2, in load_config_file
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/config/application.py", line 75, in catch_config_error
    return method(app, *args, **kwargs)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/config/application.py", line 542, in load_config_file
    self.update_config(config)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/config/application.py", line 391, in update_config
    newconfig.merge(config)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/config/loader.py", line 186, in merge
    to_update[k] = copy.deepcopy(v)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 166, in deepcopy
    y = copier(memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/site-packages/IPython/config/loader.py", line 241, in __deepcopy__
    return type(self)(copy.deepcopy(list(self.items())))
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 155, in deepcopy
    y = copier(x, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 219, in _deepcopy_list
    y.append(deepcopy(a, memo))
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 155, in deepcopy
    y = copier(x, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 226, in _deepcopy_tuple
    y.append(deepcopy(a, memo))
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 182, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 300, in _reconstruct
    state = deepcopy(state, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 155, in deepcopy
    y = copier(x, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 246, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 182, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 300, in _reconstruct
    state = deepcopy(state, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 155, in deepcopy
    y = copier(x, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 246, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 155, in deepcopy
    y = copier(x, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 246, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 182, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 300, in _reconstruct
    state = deepcopy(state, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 155, in deepcopy
    y = copier(x, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 246, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 155, in deepcopy
    y = copier(x, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 219, in _deepcopy_list
    y.append(deepcopy(a, memo))
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 182, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 300, in _reconstruct
    state = deepcopy(state, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 155, in deepcopy
    y = copier(x, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 246, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/home/ssanderson/.virtualenvs/jupyterhub/lib/python3.4/copy.py", line 174, in deepcopy
    rv = reductor(2)
TypeError: cannot serialize '_io.TextIOWrapper' object
```


Resolving patch:
diff --git a/IPython/config/loader.py b/IPython/config/loader.py
--- a/IPython/config/loader.py
+++ b/IPython/config/loader.py
@@ -233,13 +233,26 @@ def _has_section(self, key):
     
     def copy(self):
         return type(self)(dict.copy(self))
+        # copy nested config objects
+        for k, v in self.items():
+            if isinstance(v, Config):
+                new_config[k] = v.copy()
+        return new_config
 
     def __copy__(self):
         return self.copy()
 
     def __deepcopy__(self, memo):
-        import copy
-        return type(self)(copy.deepcopy(list(self.items())))
+        new_config = type(self)()
+        for key, value in self.items():
+            if isinstance(value, (Config, LazyConfigValue)):
+                # deep copy config objects
+                value = copy.deepcopy(value, memo)
+            elif type(value) in {dict, list, set, tuple}:
+                # shallow copy plain container traits
+                value = copy.copy(value)
+            new_config[key] = value
+        return new_config
     
     def __getitem__(self, key):
         try:


Test patch:
diff --git a/IPython/config/tests/test_loader.py b/IPython/config/tests/test_loader.py
--- a/IPython/config/tests/test_loader.py
+++ b/IPython/config/tests/test_loader.py
@@ -4,6 +4,8 @@
 # Copyright (c) IPython Development Team.
 # Distributed under the terms of the Modified BSD License.
 
+import copy
+import logging
 import os
 import pickle
 import sys
@@ -319,11 +321,15 @@ def test_deepcopy(self):
         c1.Foo.bam = 30
         c1.a = 'asdf'
         c1.b = range(10)
-        import copy
+        c1.Test.logger = logging.Logger('test')
+        c1.Test.get_logger = logging.getLogger('test')
         c2 = copy.deepcopy(c1)
         self.assertEqual(c1, c2)
         self.assertTrue(c1 is not c2)
         self.assertTrue(c1.Foo is not c2.Foo)
+        self.assertTrue(c1.Test is not c2.Test)
+        self.assertTrue(c1.Test.logger is c2.Test.logger)
+        self.assertTrue(c1.Test.get_logger is c2.Test.get_logger)
 
     def test_builtin(self):
         c1 = Config()