1############################################################################## 2# 3# Copyright (c) 2013 Zope Foundation and Contributors. 4# All Rights Reserved. 5# 6# This software is subject to the provisions of the Zope Public License, 7# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. 8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED 9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 11# FOR A PARTICULAR PURPOSE 12# 13############################################################################## 14import sys 15from six import PY3 16 17IS_JYTHON = sys.platform.startswith('java') 18 19_protocol = 3 20from zodbpickle import binary 21 22if not PY3: 23 # Python 2.x 24 # PyPy's cPickle doesn't have noload, and noload is broken in Python 2.7, 25 # so we need zodbpickle. 26 # Get the fastest working version we can (PyPy has no fastpickle) 27 try: 28 import zodbpickle.fastpickle as cPickle 29 except ImportError: 30 import zodbpickle.pickle as cPickle 31 Pickler = cPickle.Pickler 32 Unpickler = cPickle.Unpickler 33 dump = cPickle.dump 34 dumps = cPickle.dumps 35 loads = cPickle.loads 36 HIGHEST_PROTOCOL = cPickle.HIGHEST_PROTOCOL 37 IMPORT_MAPPING = {} 38 NAME_MAPPING = {} 39 FILESTORAGE_MAGIC = b"FS21" 40else: 41 # Python 3.x: can't use stdlib's pickle because 42 # http://bugs.python.org/issue6784 43 import zodbpickle.pickle 44 HIGHEST_PROTOCOL = 3 45 from _compat_pickle import IMPORT_MAPPING, NAME_MAPPING 46 47 class Pickler(zodbpickle.pickle.Pickler): 48 def __init__(self, f, protocol=None): 49 super(Pickler, self).__init__(f, protocol) 50 51 class Unpickler(zodbpickle.pickle.Unpickler): 52 def __init__(self, f): 53 super(Unpickler, self).__init__(f) 54 55 # Py3: Python 3 doesn't allow assignments to find_global, 56 # instead, find_class can be overridden 57 58 find_global = None 59 60 def find_class(self, modulename, name): 61 if self.find_global is None: 62 return super(Unpickler, self).find_class(modulename, name) 63 return self.find_global(modulename, name) 64 65 def dump(o, f, protocol=None): 66 return zodbpickle.pickle.dump(o, f, protocol) 67 68 def dumps(o, protocol=None): 69 return zodbpickle.pickle.dumps(o, protocol) 70 71 def loads(s): 72 return zodbpickle.pickle.loads(s, encoding='ASCII', errors='bytes') 73 FILESTORAGE_MAGIC = b"FS30" 74 75 76def PersistentPickler(persistent_id, *args, **kwargs): 77 """ 78 Returns a :class:`Pickler` that will use the given ``persistent_id`` 79 to get persistent IDs. The remainder of the arguments are passed to the 80 Pickler itself. 81 82 This covers the differences between Python 2 and 3 and PyPy/zodbpickle. 83 """ 84 p = Pickler(*args, **kwargs) 85 if not PY3: 86 p.inst_persistent_id = persistent_id 87 88 # PyPy uses a python implementation of cPickle/zodbpickle in both Python 2 89 # and Python 3. We can't really detect inst_persistent_id as its 90 # a magic attribute that's not readable, but it doesn't hurt to 91 # simply always assign to persistent_id also 92 p.persistent_id = persistent_id 93 return p 94 95def PersistentUnpickler(find_global, load_persistent, *args, **kwargs): 96 """ 97 Returns a :class:`Unpickler` that will use the given `find_global` function 98 to locate classes, and the given `load_persistent` function to load 99 objects from a persistent id. 100 101 This covers the differences between Python 2 and 3 and PyPy/zodbpickle. 102 """ 103 unpickler = Unpickler(*args, **kwargs) 104 if find_global is not None: 105 unpickler.find_global = find_global 106 try: 107 unpickler.find_class = find_global # PyPy, zodbpickle, the non-c-accelerated version 108 except AttributeError: 109 pass 110 if load_persistent is not None: 111 unpickler.persistent_load = load_persistent 112 113 return unpickler 114 115 116try: 117 # XXX: why not just import BytesIO from io? 118 from cStringIO import StringIO as BytesIO 119except ImportError: 120 # Python 3.x 121 from io import BytesIO 122 123 124try: 125 # Python 3.x 126 from base64 import decodebytes, encodebytes 127except ImportError: 128 # Python 2.x 129 from base64 import decodestring as decodebytes, encodestring as encodebytes 130 131 132# Python 3.x: ``hasattr()`` swallows only AttributeError. 133def py2_hasattr(obj, name): 134 try: 135 getattr(obj, name) 136 except: 137 return False 138 return True 139 140 141try: 142 # Py2: simply reexport the builtin 143 long = long 144except NameError: 145 # Py3 146 long = int 147 INT_TYPES = (int,) 148else: 149 INT_TYPES = (int, long) 150 151 152try: 153 TEXT = unicode 154except NameError: #pragma NO COVER Py3k 155 TEXT = str 156 157def ascii_bytes(x): 158 if isinstance(x, TEXT): 159 x = x.encode('ascii') 160 return x 161