]> granicus.if.org Git - python/commitdiff
Issue #6477: Merge with 3.3.
authorAlexandre Vassalotti <alexandre@peadrop.com>
Sun, 1 Dec 2013 00:21:20 +0000 (16:21 -0800)
committerAlexandre Vassalotti <alexandre@peadrop.com>
Sun, 1 Dec 2013 00:21:20 +0000 (16:21 -0800)
1  2 
Include/object.h
Lib/pickle.py
Lib/test/pickletester.py
Misc/NEWS
Modules/_pickle.c
Objects/object.c

Simple merge
diff --cc Lib/pickle.py
index cf8e2c5964d41f1637a817b2bbe94be476310ee4,386ffba7e2444791c83ab78eb8c112a3df7e386a..c57149a393565a74e41c686277f31b683af5023e
@@@ -954,9 -728,68 +954,18 @@@ class _Pickler
  
          self.memoize(obj)
  
+     def save_type(self, obj):
+         if obj is type(None):
+             return self.save_reduce(type, (None,), obj=obj)
+         elif obj is type(NotImplemented):
+             return self.save_reduce(type, (NotImplemented,), obj=obj)
+         elif obj is type(...):
+             return self.save_reduce(type, (...,), obj=obj)
+         return self.save_global(obj)
      dispatch[FunctionType] = save_global
-     dispatch[type] = save_global
 -    dispatch[BuiltinFunctionType] = save_global
+     dispatch[type] = save_type
  
 -# Pickling helpers
 -
 -def _keep_alive(x, memo):
 -    """Keeps a reference to the object x in the memo.
 -
 -    Because we remember objects by their id, we have
 -    to assure that possibly temporary objects are kept
 -    alive by referencing them.
 -    We store a reference at the id of the memo, which should
 -    normally not be used unless someone tries to deepcopy
 -    the memo itself...
 -    """
 -    try:
 -        memo[id(memo)].append(x)
 -    except KeyError:
 -        # aha, this is the first one :-)
 -        memo[id(memo)]=[x]
 -
 -
 -# A cache for whichmodule(), mapping a function object to the name of
 -# the module in which the function was found.
 -
 -classmap = {} # called classmap for backwards compatibility
 -
 -def whichmodule(func, funcname):
 -    """Figure out the module in which a function occurs.
 -
 -    Search sys.modules for the module.
 -    Cache in classmap.
 -    Return a module name.
 -    If the function cannot be found, return "__main__".
 -    """
 -    # Python functions should always get an __module__ from their globals.
 -    mod = getattr(func, "__module__", None)
 -    if mod is not None:
 -        return mod
 -    if func in classmap:
 -        return classmap[func]
 -
 -    for name, module in list(sys.modules.items()):
 -        if module is None:
 -            continue # skip dummy package entries
 -        if name != '__main__' and getattr(module, funcname, None) is func:
 -            break
 -    else:
 -        name = '__main__'
 -    classmap[func] = name
 -    return name
 -
  
  # Unpickling machinery
  
index 12b6c8f64191c128788571b49eb101e3151d38ca,86d668ef6f012de02c053d0a9cdb98b2fd8e78ae..999eab0d5cbb81973efb0dab27b1525a45ab15f4
@@@ -802,8 -766,17 +802,17 @@@ class AbstractPickleTests(unittest.Test
          for proto in protocols:
              s = self.dumps(NotImplemented, proto)
              u = self.loads(s)
 -            self.assertEqual(NotImplemented, u)
 +            self.assertIs(NotImplemented, u)
  
+     def test_singleton_types(self):
+         # Issue #6477: Test that types of built-in singletons can be pickled.
+         singletons = [None, ..., NotImplemented]
+         for singleton in singletons:
+             for proto in protocols:
+                 s = self.dumps(type(singleton), proto)
+                 u = self.loads(s)
+                 self.assertIs(type(singleton), u)
      # Tests for protocol 2
  
      def test_proto(self):
diff --cc Misc/NEWS
index 660980a9c4312e199eac16cbaa0336803fc1161a,0acbafd600b02072359f89a4b7b0685532961ddf..7bfce3ff77cc8d2fdcba48ff97446b9d5bebf4aa
+++ b/Misc/NEWS
@@@ -33,10 -24,9 +33,13 @@@ Librar
  - Fixed _pickle.Unpickler to not fail when loading empty strings as
    persistent IDs.
  
+ - Issue #6477: Added support for pickling the types of built-in singletons
+   (i.e., Ellipsis, NotImplemented, None).
 +- ssl.create_default_context() sets OP_NO_COMPRESSION to prevent CRIME.
 +
 +- Issue #19802: Add socket.SO_PRIORITY.
 +
  - Issue #11508: Fixed uuid.getnode() and uuid.uuid1() on environment with
    virtual interface.  Original patch by Kent Frazier.
  
index a83687b0cda8c0988fadc2b1041db0392ff3822a,ba192fb78d43c192f62314c18b19ea2732770ba5..64452381ea602bc6869f5b7801813da75d4a5fcf
@@@ -3287,6 -2811,60 +3287,36 @@@ save_global(PicklerObject *self, PyObje
      return status;
  }
  
 -static int
 -save_ellipsis(PicklerObject *self, PyObject *obj)
 -{
 -    PyObject *str = PyUnicode_FromString("Ellipsis");
 -    int res;
 -    if (str == NULL)
 -        return -1;
 -    res = save_global(self, Py_Ellipsis, str);
 -    Py_DECREF(str);
 -    return res;
 -}
 -
 -static int
 -save_notimplemented(PicklerObject *self, PyObject *obj)
 -{
 -    PyObject *str = PyUnicode_FromString("NotImplemented");
 -    int res;
 -    if (str == NULL)
 -        return -1;
 -    res = save_global(self, Py_NotImplemented, str);
 -    Py_DECREF(str);
 -    return res;
 -}
 -
+ static int
+ save_singleton_type(PicklerObject *self, PyObject *obj, PyObject *singleton)
+ {
+     PyObject *reduce_value;
+     int status;
+     reduce_value = Py_BuildValue("O(O)", &PyType_Type, singleton);
+     if (reduce_value == NULL) {
+         return -1;
+     }
+     status = save_reduce(self, reduce_value, obj);
+     Py_DECREF(reduce_value);
+     return status;
+ }
+ static int
+ save_type(PicklerObject *self, PyObject *obj)
+ {
+     if (obj == (PyObject *)&PyNone_Type) {
+         return save_singleton_type(self, obj, Py_None);
+     }
+     else if (obj == (PyObject *)&PyEllipsis_Type) {
+         return save_singleton_type(self, obj, Py_Ellipsis);
+     }
+     else if (obj == (PyObject *)&PyNotImplemented_Type) {
+         return save_singleton_type(self, obj, Py_NotImplemented);
+     }
+     return save_global(self, obj, NULL);
+ }
  static int
  save_pers(PicklerObject *self, PyObject *obj, PyObject *func)
  {
@@@ -3696,10 -3219,20 +3726,10 @@@ save(PicklerObject *self, PyObject *obj
          goto done;
      }
      else if (type == &PyType_Type) {
-         status = save_global(self, obj, NULL);
+         status = save_type(self, obj);
          goto done;
      }
 -    else if (type == &PyFunction_Type) {
 -        status = save_global(self, obj, NULL);
 -        if (status < 0 && PyErr_ExceptionMatches(PickleError)) {
 -            /* fall back to reduce */
 -            PyErr_Clear();
 -        }
 -        else {
 -            goto done;
 -        }
 -    }
 -    else if (type == &PyCFunction_Type) {
 +    else if (type == &PyFunction_Type) {
          status = save_global(self, obj, NULL);
          goto done;
      }
index 11718aaae2b61744a522ebb071a1c763aba415a4,83da6a4ff070fcf181b639857a736d2b190cd76c..8ccc91cd4b9def460abcc14090bf05a735c8748e
@@@ -1485,16 -1524,7 +1485,16 @@@ notimplemented_new(PyTypeObject *type, 
      Py_RETURN_NOTIMPLEMENTED;
  }
  
- static PyTypeObject PyNotImplemented_Type = {
 +static void
 +notimplemented_dealloc(PyObject* ignore)
 +{
 +    /* This should never get called, but we also don't want to SEGV if
 +     * we accidentally decref NotImplemented out of existence.
 +     */
 +    Py_FatalError("deallocating NotImplemented");
 +}
 +
+ PyTypeObject PyNotImplemented_Type = {
      PyVarObject_HEAD_INIT(&PyType_Type, 0)
      "NotImplementedType",
      0,