1

How can I serialize hash objects?, I'm using shelve to store a lot of objects.

Hierarchy:

- user
    - client
    - friend

user.py:

import time
import hashlib
from localfile import localfile

class user(object):
    _id = 0
    _ip = "127.0.0.1"
    _nick = "Unnamed"
    _files = {}
    def __init__(self, ip="127.0.0.1", nick="Unnamed"):
        self._id = hashlib.sha1(str(time.time()))
        self._ip = ip
        self._nick = nick
    def add_file(self, localfile):
        self._files[localfile.hash] = localfile
    def delete_file(self, localfile):
        del self._files[localfile.hash]

if __name__ == "__main__":
    pass

client.py:

from user import user
from friend import friend

class client(user):
    _friends = []
    def __init__(self, ip="127.0.0.1", nick="Unnamed"):
        user.__init__(self, ip, nick)
    @property
    def friends(self):
        return self._friends
    @friends.setter
    def friends(self, value):
        self._friends = value
    def add_friend(self, client):
        self._friends.append(client)
    def delete_friend(self, client):
        self._friends.remove(client)

if __name__ == "__main__":
    import shelve

    x = shelve.open("localfile", 'c')

    cliente = client()
    cliente.add_friend(friend("127.0.0.1", "Amigo1"))
    cliente.add_friend(friend("127.0.0.1", "Amigo2"))

    x["client"] = cliente
    print x["client"].friends

    x.close()

Errors:

facon@facon-E1210:~/Documentos/workspace/test$ python client.py
Traceback (most recent call last):
  File "client.py", line 28, in <module>
    x["client"] = cliente
  File "/usr/lib/python2.7/shelve.py", line 132, in __setitem__
    p.dump(value)
  File "/usr/lib/python2.7/copy_reg.py", line 70, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle HASH objects

EDITED

Added user.py.

Facon
  • 679
  • 2
  • 7
  • 21

2 Answers2

4

Since you can't serialize HASH objects with shelve, you would have to provide the same information in a different way. For example, you could only save the digest of the hash.

Gandaro
  • 3,427
  • 1
  • 17
  • 19
  • I need both things, keys (strings) and elements (objects that can be pickled). I'm thinking in putting both elements in 2 lists, one for keys and the other one for elements. But I don't know if later I can join lists correctly. – Facon Jan 22 '12 at 18:37
  • Then use a dictionary or list of tuples with 2 elements. – Gandaro Jan 22 '12 at 18:47
  • Omg!, I'm a fool, I only need to change this like you said: self._id = hashlib.sha1(str(time.time())) to self._id = hashlib.sha1(str(time.time())).hexdigest() then the object can be pickled. I thought that the hash was already a string. Thanks!!!! – Facon Jan 22 '12 at 19:07
  • `:)` Typical. You could also use the `digest()` method of `HASH` objects. The result of `hexdigest()` requires twice as much bytes (40 instead of 20), but it contains the same information. Unless you want to print out the hash, you probably could do this... But it's totally your choice. – Gandaro Jan 22 '12 at 19:37
0

Something in cliente, the instance of client class, is not picklable. Here is a list of those types which are picklable.

The code you've posted does not show what cliente contains which is not picklable. But you can solve the problem by either removing the unpicklable attribute if it is not needed, or by defining __getstate__ and __setstate to make client picklable.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • I posted the class that inherits from client which likely contains that "hash element", user, check now please. I also accept any criticism to improve my code. – Facon Jan 22 '12 at 17:44