Set up virtualenv to use py2
[mediagoblin.git] / mediagoblin / db / extratypes.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
18 from sqlalchemy.ext.mutable import Mutable
19 from sqlalchemy.types import TypeDecorator, Unicode, TEXT
20 import json
21
22
23 class PathTupleWithSlashes(TypeDecorator):
24 "Represents a Tuple of strings as a slash separated string."
25
26 impl = Unicode
27
28 def process_bind_param(self, value, dialect):
29 if value is not None:
30 if len(value) == 0:
31 value = None
32 else:
33 value = '/'.join(value)
34 return value
35
36 def process_result_value(self, value, dialect):
37 if value is not None:
38 value = tuple(value.split('/'))
39 return value
40
41
42 # The following two classes and only these two classes is in very
43 # large parts based on example code from sqlalchemy.
44 #
45 # The original copyright notice and license follows:
46 # Copyright (C) 2005-2011 the SQLAlchemy authors and contributors <see AUTHORS file>
47 #
48 # This module is part of SQLAlchemy and is released under
49 # the MIT License: http://www.opensource.org/licenses/mit-license.php
50 #
51 class JSONEncoded(TypeDecorator):
52 "Represents an immutable structure as a json-encoded string."
53
54 impl = TEXT
55
56 def process_bind_param(self, value, dialect):
57 if value is not None:
58 value = json.dumps(value)
59 return value
60
61 def process_result_value(self, value, dialect):
62 if value is not None:
63 value = json.loads(value)
64 return value
65
66
67 class MutationDict(Mutable, dict):
68 @classmethod
69 def coerce(cls, key, value):
70 "Convert plain dictionaries to MutationDict."
71
72 if not isinstance(value, MutationDict):
73 if isinstance(value, dict):
74 return MutationDict(value)
75
76 # this call will raise ValueError
77 return Mutable.coerce(key, value)
78 else:
79 return value
80
81 def __setitem__(self, key, value):
82 "Detect dictionary set events and emit change events."
83
84 dict.__setitem__(self, key, value)
85 self.changed()
86
87 def __delitem__(self, key):
88 "Detect dictionary del events and emit change events."
89
90 dict.__delitem__(self, key)
91 self.changed()