source: mailjam/mailjam/storage.py

Last change on this file was 18:40ba502fe87e, checked in by Borja Lopez <borja@…>, 12 years ago

Fixed a bug in the code that loads python objects from json dumps.

This bug was raising TypeError exceptions when the dumped object contained
more attributes defined in the init method than the arguments accepted
by the init method itself.

(You can reproduce this error in previous revisions of the code by dumping
a mailjam.models.MailingList object and then trying to load it from the
json dump).

File size: 3.2 KB
Line 
1# -*- coding: utf-8 -*-
2
3"""
4The mailjam project - storage.py
5
6This file is released under the BSD license, see LICENSE for
7more information.
8
9Francisco de Borja Lopez Rio - <borja@codigo23.net>
10Soluciones Informaticas Codigo23 S.L.U. - http://codigo23.net
11"""
12
13import os, errno, json, inspect
14
15
16class JsonStorage():
17
18 """
19 Json-based storage.
20 """
21
22 def __init__(self, path='storage.json'):
23 if os.path.isdir(path):
24 raise IOError(path, ' is a directory, exiting')
25 self.path = path
26
27 def exists(self):
28 return os.path.exists(self.path)
29
30 def create(self):
31 """
32 Ensure all the subdirectories in the path to the storage file
33 exist
34 """
35 try:
36 os.makedirs(os.path.dirname(self.path))
37 except OSError, e:
38 # If the dir already exists do not complain, if it is
39 # any other error, raise the exception
40 if e.errno != errno.EEXIST:
41 raise
42
43 def jsonize(self, obj):
44 """
45 Convert objects to a dictionary of their representation
46 Based on the exmplaes from Doyg Hellmann:
47 http://www.doughellmann.com/PyMOTW/json/#working-with-your-own-types
48 """
49 jobj = { '__class__':obj.__class__.__name__,
50 '__module__':obj.__module__,
51 }
52 jobj.update(obj.__dict__)
53 return jobj
54
55 def dejsonize(self, jobj):
56 """
57 Convert some data that has been "jsonized" to the original
58 python object. Again, based on the examples from Doug Hellmann
59 """
60 if '__class__' in jobj:
61 class_name = jobj.pop('__class__')
62 module_name = jobj.pop('__module__')
63 module = __import__(module_name)
64 class_ = getattr(module, class_name)
65 # inspect the class __init__ method, getting a list of
66 # accepted/valid arguments.
67 valid_args = inspect.getargspec(class_.__init__)
68 # then, only accepted parameters will be deserialized
69 args = dict((key.encode('ascii'), value) \
70 for key, value in jobj.items() if key in valid_args[0])
71 return class_(**args)
72 return jobj
73
74 def write(self, data):
75 if not self.exists():
76 # ensure the path to the storage file exists
77 self.create()
78 with open(self.path, 'w') as storage:
79 json.dump(data, storage, sort_keys=True, indent=4,
80 default=self.jsonize)
81 return True
82 return False
83
84 def read(self):
85 with open(self.path, 'r') as storage:
86 try:
87 data = json.load(storage,object_hook=self.dejsonize)
88 except ValueError:
89 # if no json data could be imported, the file could be
90 # damaged or perhaps it does not containg json-encoded
91 # data, simply return an empty string
92 #
93 # FIXME: we should notify the user about the problem
94 return ''
95 return data
96
97 def delete(self):
98 """
99 Remove the storage file
100 """
101 if self.exists():
102 os.remove(self.path)
103 return True
104 return False
Note: See TracBrowser for help on using the repository browser.