Package Gnumed :: Package timelinelib :: Package general :: Module immutable
[frames] | no frames]

Source Code for Module Gnumed.timelinelib.general.immutable

1 # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Rickard Lindberg, Roger Lindberg 2 # 3 # This file is part of Timeline. 4 # 5 # Timeline is free software: you can redistribute it and/or modify 6 # it under the terms of the GNU General Public License as published by 7 # the Free Software Foundation, either version 3 of the License, or 8 # (at your option) any later version. 9 # 10 # Timeline is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU General Public License for more details. 14 # 15 # You should have received a copy of the GNU General Public License 16 # along with Timeline. If not, see <http://www.gnu.org/licenses/>. 17 18 19 -class ImmutableDict(tuple):
20
21 - def __new__(cls, *args, **kwargs):
22 if (len(args) == 1 and 23 len(kwargs) == 0 and 24 isinstance(args[0], _AlreadyCopiedDict)): 25 d = args[0].value 26 else: 27 d = {} 28 for arg in args: 29 d.update(arg) 30 for key, value in kwargs.iteritems(): 31 d[key] = value 32 return tuple.__new__(cls, (d,))
33 34 @property
35 - def _internal(self):
36 return tuple.__getitem__(self, 0)
37
38 - def update(self, *args, **kwargs):
39 return self.__class__(self._internal, *args, **kwargs)
40
41 - def remove(self, key):
42 new = {} 43 new.update(self._internal) 44 del new[key] 45 return self.__class__(_AlreadyCopiedDict(new))
46
47 - def map(self, fn):
48 return self.__class__(_AlreadyCopiedDict({ 49 key: fn(value) 50 for key, value 51 in self._internal.iteritems() 52 }))
53
54 - def get(self, name, default=None):
55 return self._internal.get(name, default)
56
57 - def __len__(self):
58 return len(self._internal)
59
60 - def __contains__(self, item):
61 return item in self._internal
62
63 - def __getitem__(self, name):
64 return self._internal[name]
65
66 - def __iter__(self):
67 return self._internal.iteritems()
68
69 - def __eq__(self, other):
70 return ( 71 isinstance(other, self.__class__) and 72 self._internal == other._internal 73 )
74
75 - def __ne__(self, other):
76 return not self == other
77
78 - def __repr__(self):
79 items = [] 80 items.append(self.__class__.__name__) 81 items.append("({\n") 82 for key, value in self: 83 items.append(" ") 84 items.append(repr(key)) 85 items.append(": ") 86 for index, line in enumerate(repr(value).split("\n")): 87 if index > 0: 88 items.append("\n ") 89 items.append(line) 90 items.append(",\n") 91 items.append("})") 92 return "".join(items)
93
94 95 -class ImmutableRecordMeta(type):
96
97 - def __new__(cls, name, bases, attrs):
98 def create_property(name): 99 return property( 100 lambda self: self.get(name) 101 )
102 base_attributes = [] 103 for base in bases: 104 base_attributes.extend(dir(base)) 105 fields = {} 106 for key, value in list(attrs.iteritems()): 107 if isinstance(value, Field): 108 if key in base_attributes: 109 raise ValueError( 110 "{0!r} is a reserved field name".format(key) 111 ) 112 fields[key] = value 113 attrs[key] = create_property(key) 114 attrs["_immutable_record_fields"] = fields 115 return super(ImmutableRecordMeta, cls).__new__(cls, name, bases, attrs)
116
117 118 -class Field(object):
119
120 - def __init__(self, default=None):
121 self.default = default
122
123 124 -class ImmutableRecord(ImmutableDict):
125 126 __metaclass__ = ImmutableRecordMeta 127
128 - def __new__(cls, *args, **kwargs):
129 defaults = { 130 key: value.default 131 for key, value 132 in cls._immutable_record_fields.iteritems() 133 } 134 d = ImmutableDict.__new__(cls, defaults, *args, **kwargs) 135 for key, value in d: 136 if key not in cls._immutable_record_fields: 137 raise ValueError("{0!r} is not a valid field of {1}".format( 138 key, 139 cls.__name__ 140 )) 141 return d
142
143 144 -class _AlreadyCopiedDict(object):
145 146 """ 147 A special value that can be passed as the single value to the constructor 148 of ImmutableDict to prevent unnecessary copying. 149 """ 150
151 - def __init__(self, value):
152 self.value = value
153