We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Fail to send class definitions from interactive session to engines namespaces
Here is a [sample notebook](http://nbviewer.ipython.org/4471180/) to demonstrate the issue.

Please note that I don't get any unpickling error message when calling:

```
rc[:]['AClass'] = AClass
```

While @minrk is reporting a `DummyModule` `AttributeError` in this [SO question](http://stackoverflow.com/questions/14184621/how-to-work-with-interactively-defined-classes-in-ipython-parallel).

I will see if I can come up with a pull request for a `can_class` / `uncan_class` along the lines of [this gist](https://gist.github.com/4470212).


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `IPython/utils/pickleutil.py`
Content:
```
1 # encoding: utf-8
2 
3 """Pickle related utilities. Perhaps this should be called 'can'."""
4 
5 __docformat__ = "restructuredtext en"
6 
7 #-------------------------------------------------------------------------------
8 #  Copyright (C) 2008-2011  The IPython Development Team
9 #
10 #  Distributed under the terms of the BSD License.  The full license is in
11 #  the file COPYING, distributed as part of this software.
12 #-------------------------------------------------------------------------------
13 
14 #-------------------------------------------------------------------------------
15 # Imports
16 #-------------------------------------------------------------------------------
17 
18 import copy
19 import logging
20 import sys
21 from types import FunctionType
22 
23 try:
24     import cPickle as pickle
25 except ImportError:
26     import pickle
27 
28 try:
29     import numpy
30 except:
31     numpy = None
32 
33 import codeutil
34 import py3compat
35 from importstring import import_item
36 
37 from IPython.config import Application
38 
39 if py3compat.PY3:
40     buffer = memoryview
41 
42 #-------------------------------------------------------------------------------
43 # Classes
44 #-------------------------------------------------------------------------------
45 
46 
47 class CannedObject(object):
48     def __init__(self, obj, keys=[]):
49         self.keys = keys
50         self.obj = copy.copy(obj)
51         for key in keys:
52             setattr(self.obj, key, can(getattr(obj, key)))
53         
54         self.buffers = []
55 
56     def get_object(self, g=None):
57         if g is None:
58             g = {}
59         for key in self.keys:
60             setattr(self.obj, key, uncan(getattr(self.obj, key), g))
61         return self.obj
62     
63 
64 class Reference(CannedObject):
65     """object for wrapping a remote reference by name."""
66     def __init__(self, name):
67         if not isinstance(name, basestring):
68             raise TypeError("illegal name: %r"%name)
69         self.name = name
70         self.buffers = []
71 
72     def __repr__(self):
73         return "<Reference: %r>"%self.name
74 
75     def get_object(self, g=None):
76         if g is None:
77             g = {}
78         
79         return eval(self.name, g)
80 
81 
82 class CannedFunction(CannedObject):
83 
84     def __init__(self, f):
85         self._check_type(f)
86         self.code = f.func_code
87         if f.func_defaults:
88             self.defaults = [ can(fd) for fd in f.func_defaults ]
89         else:
90             self.defaults = None
91         self.module = f.__module__ or '__main__'
92         self.__name__ = f.__name__
93         self.buffers = []
94 
95     def _check_type(self, obj):
96         assert isinstance(obj, FunctionType), "Not a function type"
97 
98     def get_object(self, g=None):
99         # try to load function back into its module:
100         if not self.module.startswith('__'):
101             __import__(self.module)
102             g = sys.modules[self.module].__dict__
103 
104         if g is None:
105             g = {}
106         if self.defaults:
107             defaults = tuple(uncan(cfd, g) for cfd in self.defaults)
108         else:
109             defaults = None
110         newFunc = FunctionType(self.code, g, self.__name__, defaults)
111         return newFunc
112 
113 
114 class CannedArray(CannedObject):
115     def __init__(self, obj):
116         self.shape = obj.shape
117         self.dtype = obj.dtype.descr if obj.dtype.fields else obj.dtype.str
118         if sum(obj.shape) == 0:
119             # just pickle it
120             self.buffers = [pickle.dumps(obj, -1)]
121         else:
122             # ensure contiguous
123             obj = numpy.ascontiguousarray(obj, dtype=None)
124             self.buffers = [buffer(obj)]
125     
126     def get_object(self, g=None):
127         data = self.buffers[0]
128         if sum(self.shape) == 0:
129             # no shape, we just pickled it
130             return pickle.loads(data)
131         else:
132             return numpy.frombuffer(data, dtype=self.dtype).reshape(self.shape)
133 
134 
135 class CannedBytes(CannedObject):
136     wrap = bytes
137     def __init__(self, obj):
138         self.buffers = [obj]
139     
140     def get_object(self, g=None):
141         data = self.buffers[0]
142         return self.wrap(data)
143 
144 def CannedBuffer(CannedBytes):
145     wrap = buffer
146 
147 #-------------------------------------------------------------------------------
148 # Functions
149 #-------------------------------------------------------------------------------
150 
151 def _logger():
152     """get the logger for the current Application
153     
154     the root logger will be used if no Application is running
155     """
156     if Application.initialized():
157         logger = Application.instance().log
158     else:
159         logger = logging.getLogger()
160         if not logger.handlers:
161             logging.basicConfig()
162     
163     return logger
164 
165 def _import_mapping(mapping, original=None):
166     """import any string-keys in a type mapping
167     
168     """
169     log = _logger()
170     log.debug("Importing canning map")
171     for key,value in mapping.items():
172         if isinstance(key, basestring):
173             try:
174                 cls = import_item(key)
175             except Exception:
176                 if original and key not in original:
177                     # only message on user-added classes
178                     log.error("cannning class not importable: %r", key, exc_info=True)
179                 mapping.pop(key)
180             else:
181                 mapping[cls] = mapping.pop(key)
182 
183 def can(obj):
184     """prepare an object for pickling"""
185     
186     import_needed = False
187     
188     for cls,canner in can_map.iteritems():
189         if isinstance(cls, basestring):
190             import_needed = True
191             break
192         elif isinstance(obj, cls):
193             return canner(obj)
194     
195     if import_needed:
196         # perform can_map imports, then try again
197         # this will usually only happen once
198         _import_mapping(can_map, _original_can_map)
199         return can(obj)
200     
201     return obj
202 
203 def can_dict(obj):
204     """can the *values* of a dict"""
205     if isinstance(obj, dict):
206         newobj = {}
207         for k, v in obj.iteritems():
208             newobj[k] = can(v)
209         return newobj
210     else:
211         return obj
212 
213 def can_sequence(obj):
214     """can the elements of a sequence"""
215     if isinstance(obj, (list, tuple)):
216         t = type(obj)
217         return t([can(i) for i in obj])
218     else:
219         return obj
220 
221 def uncan(obj, g=None):
222     """invert canning"""
223     
224     import_needed = False
225     for cls,uncanner in uncan_map.iteritems():
226         if isinstance(cls, basestring):
227             import_needed = True
228             break
229         elif isinstance(obj, cls):
230             return uncanner(obj, g)
231     
232     if import_needed:
233         # perform uncan_map imports, then try again
234         # this will usually only happen once
235         _import_mapping(uncan_map, _original_uncan_map)
236         return uncan(obj, g)
237     
238     return obj
239 
240 def uncan_dict(obj, g=None):
241     if isinstance(obj, dict):
242         newobj = {}
243         for k, v in obj.iteritems():
244             newobj[k] = uncan(v,g)
245         return newobj
246     else:
247         return obj
248 
249 def uncan_sequence(obj, g=None):
250     if isinstance(obj, (list, tuple)):
251         t = type(obj)
252         return t([uncan(i,g) for i in obj])
253     else:
254         return obj
255 
256 
257 #-------------------------------------------------------------------------------
258 # API dictionaries
259 #-------------------------------------------------------------------------------
260 
261 # These dicts can be extended for custom serialization of new objects
262 
263 can_map = {
264     'IPython.parallel.dependent' : lambda obj: CannedObject(obj, keys=('f','df')),
265     'numpy.ndarray' : CannedArray,
266     FunctionType : CannedFunction,
267     bytes : CannedBytes,
268     buffer : CannedBuffer,
269 }
270 
271 uncan_map = {
272     CannedObject : lambda obj, g: obj.get_object(g),
273 }
274 
275 # for use in _import_mapping:
276 _original_can_map = can_map.copy()
277 _original_uncan_map = uncan_map.copy()
278
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/IPython/utils/pickleutil.py b/IPython/utils/pickleutil.py
--- a/IPython/utils/pickleutil.py
+++ b/IPython/utils/pickleutil.py
@@ -38,6 +38,10 @@
 
 if py3compat.PY3:
     buffer = memoryview
+    class_type = type
+else:
+    from types import ClassType
+    class_type = (type, ClassType)
 
 #-------------------------------------------------------------------------------
 # Classes
@@ -110,6 +114,30 @@
         newFunc = FunctionType(self.code, g, self.__name__, defaults)
         return newFunc
 
+class CannedClass(CannedObject):
+
+    def __init__(self, cls):
+        self._check_type(cls)
+        self.name = cls.__name__
+        self.old_style = not isinstance(cls, type)
+        self._canned_dict = {}
+        for k,v in cls.__dict__.items():
+            if k not in ('__weakref__', '__dict__'):
+                self._canned_dict[k] = can(v)
+        if self.old_style:
+            mro = []
+        else:
+            mro = cls.mro()
+        
+        self.parents = [ can(c) for c in mro[1:] ]
+        self.buffers = []
+
+    def _check_type(self, obj):
+        assert isinstance(obj, class_type), "Not a class type"
+
+    def get_object(self, g=None):
+        parents = tuple(uncan(p, g) for p in self.parents)
+        return type(self.name, parents, uncan_dict(self._canned_dict, g=g))
 
 class CannedArray(CannedObject):
     def __init__(self, obj):
@@ -200,6 +228,12 @@
     
     return obj
 
+def can_class(obj):
+    if isinstance(obj, class_type) and obj.__module__ == '__main__':
+        return CannedClass(obj)
+    else:
+        return obj
+
 def can_dict(obj):
     """can the *values* of a dict"""
     if isinstance(obj, dict):
@@ -266,6 +300,7 @@
     FunctionType : CannedFunction,
     bytes : CannedBytes,
     buffer : CannedBuffer,
+    class_type : can_class,
 }
 
 uncan_map = {

{"golden_diff": "diff --git a/IPython/utils/pickleutil.py b/IPython/utils/pickleutil.py\n--- a/IPython/utils/pickleutil.py\n+++ b/IPython/utils/pickleutil.py\n@@ -38,6 +38,10 @@\n \n if py3compat.PY3:\n     buffer = memoryview\n+    class_type = type\n+else:\n+    from types import ClassType\n+    class_type = (type, ClassType)\n \n #-------------------------------------------------------------------------------\n # Classes\n@@ -110,6 +114,30 @@\n         newFunc = FunctionType(self.code, g, self.__name__, defaults)\n         return newFunc\n \n+class CannedClass(CannedObject):\n+\n+    def __init__(self, cls):\n+        self._check_type(cls)\n+        self.name = cls.__name__\n+        self.old_style = not isinstance(cls, type)\n+        self._canned_dict = {}\n+        for k,v in cls.__dict__.items():\n+            if k not in ('__weakref__', '__dict__'):\n+                self._canned_dict[k] = can(v)\n+        if self.old_style:\n+            mro = []\n+        else:\n+            mro = cls.mro()\n+        \n+        self.parents = [ can(c) for c in mro[1:] ]\n+        self.buffers = []\n+\n+    def _check_type(self, obj):\n+        assert isinstance(obj, class_type), \"Not a class type\"\n+\n+    def get_object(self, g=None):\n+        parents = tuple(uncan(p, g) for p in self.parents)\n+        return type(self.name, parents, uncan_dict(self._canned_dict, g=g))\n \n class CannedArray(CannedObject):\n     def __init__(self, obj):\n@@ -200,6 +228,12 @@\n     \n     return obj\n \n+def can_class(obj):\n+    if isinstance(obj, class_type) and obj.__module__ == '__main__':\n+        return CannedClass(obj)\n+    else:\n+        return obj\n+\n def can_dict(obj):\n     \"\"\"can the *values* of a dict\"\"\"\n     if isinstance(obj, dict):\n@@ -266,6 +300,7 @@\n     FunctionType : CannedFunction,\n     bytes : CannedBytes,\n     buffer : CannedBuffer,\n+    class_type : can_class,\n }\n \n uncan_map = {\n", "issue": "Fail to send class definitions from interactive session to engines namespaces\nHere is a [sample notebook](http://nbviewer.ipython.org/4471180/) to demonstrate the issue.\n\nPlease note that I don't get any unpickling error message when calling:\n\n```\nrc[:]['AClass'] = AClass\n```\n\nWhile @minrk is reporting a `DummyModule` `AttributeError` in this [SO question](http://stackoverflow.com/questions/14184621/how-to-work-with-interactively-defined-classes-in-ipython-parallel).\n\nI will see if I can come up with a pull request for a `can_class` / `uncan_class` along the lines of [this gist](https://gist.github.com/4470212).\n\n", "before_files": [{"content": "# encoding: utf-8\n\n\"\"\"Pickle related utilities. Perhaps this should be called 'can'.\"\"\"\n\n__docformat__ = \"restructuredtext en\"\n\n#-------------------------------------------------------------------------------\n#  Copyright (C) 2008-2011  The IPython Development Team\n#\n#  Distributed under the terms of the BSD License.  The full license is in\n#  the file COPYING, distributed as part of this software.\n#-------------------------------------------------------------------------------\n\n#-------------------------------------------------------------------------------\n# Imports\n#-------------------------------------------------------------------------------\n\nimport copy\nimport logging\nimport sys\nfrom types import FunctionType\n\ntry:\n    import cPickle as pickle\nexcept ImportError:\n    import pickle\n\ntry:\n    import numpy\nexcept:\n    numpy = None\n\nimport codeutil\nimport py3compat\nfrom importstring import import_item\n\nfrom IPython.config import Application\n\nif py3compat.PY3:\n    buffer = memoryview\n\n#-------------------------------------------------------------------------------\n# Classes\n#-------------------------------------------------------------------------------\n\n\nclass CannedObject(object):\n    def __init__(self, obj, keys=[]):\n        self.keys = keys\n        self.obj = copy.copy(obj)\n        for key in keys:\n            setattr(self.obj, key, can(getattr(obj, key)))\n        \n        self.buffers = []\n\n    def get_object(self, g=None):\n        if g is None:\n            g = {}\n        for key in self.keys:\n            setattr(self.obj, key, uncan(getattr(self.obj, key), g))\n        return self.obj\n    \n\nclass Reference(CannedObject):\n    \"\"\"object for wrapping a remote reference by name.\"\"\"\n    def __init__(self, name):\n        if not isinstance(name, basestring):\n            raise TypeError(\"illegal name: %r\"%name)\n        self.name = name\n        self.buffers = []\n\n    def __repr__(self):\n        return \"<Reference: %r>\"%self.name\n\n    def get_object(self, g=None):\n        if g is None:\n            g = {}\n        \n        return eval(self.name, g)\n\n\nclass CannedFunction(CannedObject):\n\n    def __init__(self, f):\n        self._check_type(f)\n        self.code = f.func_code\n        if f.func_defaults:\n            self.defaults = [ can(fd) for fd in f.func_defaults ]\n        else:\n            self.defaults = None\n        self.module = f.__module__ or '__main__'\n        self.__name__ = f.__name__\n        self.buffers = []\n\n    def _check_type(self, obj):\n        assert isinstance(obj, FunctionType), \"Not a function type\"\n\n    def get_object(self, g=None):\n        # try to load function back into its module:\n        if not self.module.startswith('__'):\n            __import__(self.module)\n            g = sys.modules[self.module].__dict__\n\n        if g is None:\n            g = {}\n        if self.defaults:\n            defaults = tuple(uncan(cfd, g) for cfd in self.defaults)\n        else:\n            defaults = None\n        newFunc = FunctionType(self.code, g, self.__name__, defaults)\n        return newFunc\n\n\nclass CannedArray(CannedObject):\n    def __init__(self, obj):\n        self.shape = obj.shape\n        self.dtype = obj.dtype.descr if obj.dtype.fields else obj.dtype.str\n        if sum(obj.shape) == 0:\n            # just pickle it\n            self.buffers = [pickle.dumps(obj, -1)]\n        else:\n            # ensure contiguous\n            obj = numpy.ascontiguousarray(obj, dtype=None)\n            self.buffers = [buffer(obj)]\n    \n    def get_object(self, g=None):\n        data = self.buffers[0]\n        if sum(self.shape) == 0:\n            # no shape, we just pickled it\n            return pickle.loads(data)\n        else:\n            return numpy.frombuffer(data, dtype=self.dtype).reshape(self.shape)\n\n\nclass CannedBytes(CannedObject):\n    wrap = bytes\n    def __init__(self, obj):\n        self.buffers = [obj]\n    \n    def get_object(self, g=None):\n        data = self.buffers[0]\n        return self.wrap(data)\n\ndef CannedBuffer(CannedBytes):\n    wrap = buffer\n\n#-------------------------------------------------------------------------------\n# Functions\n#-------------------------------------------------------------------------------\n\ndef _logger():\n    \"\"\"get the logger for the current Application\n    \n    the root logger will be used if no Application is running\n    \"\"\"\n    if Application.initialized():\n        logger = Application.instance().log\n    else:\n        logger = logging.getLogger()\n        if not logger.handlers:\n            logging.basicConfig()\n    \n    return logger\n\ndef _import_mapping(mapping, original=None):\n    \"\"\"import any string-keys in a type mapping\n    \n    \"\"\"\n    log = _logger()\n    log.debug(\"Importing canning map\")\n    for key,value in mapping.items():\n        if isinstance(key, basestring):\n            try:\n                cls = import_item(key)\n            except Exception:\n                if original and key not in original:\n                    # only message on user-added classes\n                    log.error(\"cannning class not importable: %r\", key, exc_info=True)\n                mapping.pop(key)\n            else:\n                mapping[cls] = mapping.pop(key)\n\ndef can(obj):\n    \"\"\"prepare an object for pickling\"\"\"\n    \n    import_needed = False\n    \n    for cls,canner in can_map.iteritems():\n        if isinstance(cls, basestring):\n            import_needed = True\n            break\n        elif isinstance(obj, cls):\n            return canner(obj)\n    \n    if import_needed:\n        # perform can_map imports, then try again\n        # this will usually only happen once\n        _import_mapping(can_map, _original_can_map)\n        return can(obj)\n    \n    return obj\n\ndef can_dict(obj):\n    \"\"\"can the *values* of a dict\"\"\"\n    if isinstance(obj, dict):\n        newobj = {}\n        for k, v in obj.iteritems():\n            newobj[k] = can(v)\n        return newobj\n    else:\n        return obj\n\ndef can_sequence(obj):\n    \"\"\"can the elements of a sequence\"\"\"\n    if isinstance(obj, (list, tuple)):\n        t = type(obj)\n        return t([can(i) for i in obj])\n    else:\n        return obj\n\ndef uncan(obj, g=None):\n    \"\"\"invert canning\"\"\"\n    \n    import_needed = False\n    for cls,uncanner in uncan_map.iteritems():\n        if isinstance(cls, basestring):\n            import_needed = True\n            break\n        elif isinstance(obj, cls):\n            return uncanner(obj, g)\n    \n    if import_needed:\n        # perform uncan_map imports, then try again\n        # this will usually only happen once\n        _import_mapping(uncan_map, _original_uncan_map)\n        return uncan(obj, g)\n    \n    return obj\n\ndef uncan_dict(obj, g=None):\n    if isinstance(obj, dict):\n        newobj = {}\n        for k, v in obj.iteritems():\n            newobj[k] = uncan(v,g)\n        return newobj\n    else:\n        return obj\n\ndef uncan_sequence(obj, g=None):\n    if isinstance(obj, (list, tuple)):\n        t = type(obj)\n        return t([uncan(i,g) for i in obj])\n    else:\n        return obj\n\n\n#-------------------------------------------------------------------------------\n# API dictionaries\n#-------------------------------------------------------------------------------\n\n# These dicts can be extended for custom serialization of new objects\n\ncan_map = {\n    'IPython.parallel.dependent' : lambda obj: CannedObject(obj, keys=('f','df')),\n    'numpy.ndarray' : CannedArray,\n    FunctionType : CannedFunction,\n    bytes : CannedBytes,\n    buffer : CannedBuffer,\n}\n\nuncan_map = {\n    CannedObject : lambda obj, g: obj.get_object(g),\n}\n\n# for use in _import_mapping:\n_original_can_map = can_map.copy()\n_original_uncan_map = uncan_map.copy()\n", "path": "IPython/utils/pickleutil.py"}], "after_files": [{"content": "# encoding: utf-8\n\n\"\"\"Pickle related utilities. Perhaps this should be called 'can'.\"\"\"\n\n__docformat__ = \"restructuredtext en\"\n\n#-------------------------------------------------------------------------------\n#  Copyright (C) 2008-2011  The IPython Development Team\n#\n#  Distributed under the terms of the BSD License.  The full license is in\n#  the file COPYING, distributed as part of this software.\n#-------------------------------------------------------------------------------\n\n#-------------------------------------------------------------------------------\n# Imports\n#-------------------------------------------------------------------------------\n\nimport copy\nimport logging\nimport sys\nfrom types import FunctionType\n\ntry:\n    import cPickle as pickle\nexcept ImportError:\n    import pickle\n\ntry:\n    import numpy\nexcept:\n    numpy = None\n\nimport codeutil\nimport py3compat\nfrom importstring import import_item\n\nfrom IPython.config import Application\n\nif py3compat.PY3:\n    buffer = memoryview\n    class_type = type\nelse:\n    from types import ClassType\n    class_type = (type, ClassType)\n\n#-------------------------------------------------------------------------------\n# Classes\n#-------------------------------------------------------------------------------\n\n\nclass CannedObject(object):\n    def __init__(self, obj, keys=[]):\n        self.keys = keys\n        self.obj = copy.copy(obj)\n        for key in keys:\n            setattr(self.obj, key, can(getattr(obj, key)))\n        \n        self.buffers = []\n\n    def get_object(self, g=None):\n        if g is None:\n            g = {}\n        for key in self.keys:\n            setattr(self.obj, key, uncan(getattr(self.obj, key), g))\n        return self.obj\n    \n\nclass Reference(CannedObject):\n    \"\"\"object for wrapping a remote reference by name.\"\"\"\n    def __init__(self, name):\n        if not isinstance(name, basestring):\n            raise TypeError(\"illegal name: %r\"%name)\n        self.name = name\n        self.buffers = []\n\n    def __repr__(self):\n        return \"<Reference: %r>\"%self.name\n\n    def get_object(self, g=None):\n        if g is None:\n            g = {}\n        \n        return eval(self.name, g)\n\n\nclass CannedFunction(CannedObject):\n\n    def __init__(self, f):\n        self._check_type(f)\n        self.code = f.func_code\n        if f.func_defaults:\n            self.defaults = [ can(fd) for fd in f.func_defaults ]\n        else:\n            self.defaults = None\n        self.module = f.__module__ or '__main__'\n        self.__name__ = f.__name__\n        self.buffers = []\n\n    def _check_type(self, obj):\n        assert isinstance(obj, FunctionType), \"Not a function type\"\n\n    def get_object(self, g=None):\n        # try to load function back into its module:\n        if not self.module.startswith('__'):\n            __import__(self.module)\n            g = sys.modules[self.module].__dict__\n\n        if g is None:\n            g = {}\n        if self.defaults:\n            defaults = tuple(uncan(cfd, g) for cfd in self.defaults)\n        else:\n            defaults = None\n        newFunc = FunctionType(self.code, g, self.__name__, defaults)\n        return newFunc\n\nclass CannedClass(CannedObject):\n\n    def __init__(self, cls):\n        self._check_type(cls)\n        self.name = cls.__name__\n        self.old_style = not isinstance(cls, type)\n        self._canned_dict = {}\n        for k,v in cls.__dict__.items():\n            if k not in ('__weakref__', '__dict__'):\n                self._canned_dict[k] = can(v)\n        if self.old_style:\n            mro = []\n        else:\n            mro = cls.mro()\n        \n        self.parents = [ can(c) for c in mro[1:] ]\n        self.buffers = []\n\n    def _check_type(self, obj):\n        assert isinstance(obj, class_type), \"Not a class type\"\n\n    def get_object(self, g=None):\n        parents = tuple(uncan(p, g) for p in self.parents)\n        return type(self.name, parents, uncan_dict(self._canned_dict, g=g))\n\nclass CannedArray(CannedObject):\n    def __init__(self, obj):\n        self.shape = obj.shape\n        self.dtype = obj.dtype.descr if obj.dtype.fields else obj.dtype.str\n        if sum(obj.shape) == 0:\n            # just pickle it\n            self.buffers = [pickle.dumps(obj, -1)]\n        else:\n            # ensure contiguous\n            obj = numpy.ascontiguousarray(obj, dtype=None)\n            self.buffers = [buffer(obj)]\n    \n    def get_object(self, g=None):\n        data = self.buffers[0]\n        if sum(self.shape) == 0:\n            # no shape, we just pickled it\n            return pickle.loads(data)\n        else:\n            return numpy.frombuffer(data, dtype=self.dtype).reshape(self.shape)\n\n\nclass CannedBytes(CannedObject):\n    wrap = bytes\n    def __init__(self, obj):\n        self.buffers = [obj]\n    \n    def get_object(self, g=None):\n        data = self.buffers[0]\n        return self.wrap(data)\n\ndef CannedBuffer(CannedBytes):\n    wrap = buffer\n\n#-------------------------------------------------------------------------------\n# Functions\n#-------------------------------------------------------------------------------\n\ndef _logger():\n    \"\"\"get the logger for the current Application\n    \n    the root logger will be used if no Application is running\n    \"\"\"\n    if Application.initialized():\n        logger = Application.instance().log\n    else:\n        logger = logging.getLogger()\n        if not logger.handlers:\n            logging.basicConfig()\n    \n    return logger\n\ndef _import_mapping(mapping, original=None):\n    \"\"\"import any string-keys in a type mapping\n    \n    \"\"\"\n    log = _logger()\n    log.debug(\"Importing canning map\")\n    for key,value in mapping.items():\n        if isinstance(key, basestring):\n            try:\n                cls = import_item(key)\n            except Exception:\n                if original and key not in original:\n                    # only message on user-added classes\n                    log.error(\"cannning class not importable: %r\", key, exc_info=True)\n                mapping.pop(key)\n            else:\n                mapping[cls] = mapping.pop(key)\n\ndef can(obj):\n    \"\"\"prepare an object for pickling\"\"\"\n    \n    import_needed = False\n    \n    for cls,canner in can_map.iteritems():\n        if isinstance(cls, basestring):\n            import_needed = True\n            break\n        elif isinstance(obj, cls):\n            return canner(obj)\n    \n    if import_needed:\n        # perform can_map imports, then try again\n        # this will usually only happen once\n        _import_mapping(can_map, _original_can_map)\n        return can(obj)\n    \n    return obj\n\ndef can_class(obj):\n    if isinstance(obj, class_type) and obj.__module__ == '__main__':\n        return CannedClass(obj)\n    else:\n        return obj\n\ndef can_dict(obj):\n    \"\"\"can the *values* of a dict\"\"\"\n    if isinstance(obj, dict):\n        newobj = {}\n        for k, v in obj.iteritems():\n            newobj[k] = can(v)\n        return newobj\n    else:\n        return obj\n\ndef can_sequence(obj):\n    \"\"\"can the elements of a sequence\"\"\"\n    if isinstance(obj, (list, tuple)):\n        t = type(obj)\n        return t([can(i) for i in obj])\n    else:\n        return obj\n\ndef uncan(obj, g=None):\n    \"\"\"invert canning\"\"\"\n    \n    import_needed = False\n    for cls,uncanner in uncan_map.iteritems():\n        if isinstance(cls, basestring):\n            import_needed = True\n            break\n        elif isinstance(obj, cls):\n            return uncanner(obj, g)\n    \n    if import_needed:\n        # perform uncan_map imports, then try again\n        # this will usually only happen once\n        _import_mapping(uncan_map, _original_uncan_map)\n        return uncan(obj, g)\n    \n    return obj\n\ndef uncan_dict(obj, g=None):\n    if isinstance(obj, dict):\n        newobj = {}\n        for k, v in obj.iteritems():\n            newobj[k] = uncan(v,g)\n        return newobj\n    else:\n        return obj\n\ndef uncan_sequence(obj, g=None):\n    if isinstance(obj, (list, tuple)):\n        t = type(obj)\n        return t([uncan(i,g) for i in obj])\n    else:\n        return obj\n\n\n#-------------------------------------------------------------------------------\n# API dictionaries\n#-------------------------------------------------------------------------------\n\n# These dicts can be extended for custom serialization of new objects\n\ncan_map = {\n    'IPython.parallel.dependent' : lambda obj: CannedObject(obj, keys=('f','df')),\n    'numpy.ndarray' : CannedArray,\n    FunctionType : CannedFunction,\n    bytes : CannedBytes,\n    buffer : CannedBuffer,\n    class_type : can_class,\n}\n\nuncan_map = {\n    CannedObject : lambda obj, g: obj.get_object(g),\n}\n\n# for use in _import_mapping:\n_original_can_map = can_map.copy()\n_original_uncan_map = uncan_map.copy()\n", "path": "IPython/utils/pickleutil.py"}]}