xtquant.xtbson.bson36.son
Tools for creating and manipulating SON, the Serialized Ocument Notation.
Regular dictionaries can be used instead of SON objects, but not when the order of keys is important. A SON object can be used just like a normal Python dictionary.
1# Copyright 2009-present MongoDB, Inc. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Tools for creating and manipulating SON, the Serialized Ocument Notation. 16 17Regular dictionaries can be used instead of SON objects, but not when the order 18of keys is important. A SON object can be used just like a normal Python 19dictionary.""" 20 21import copy 22import re 23from collections.abc import Mapping as _Mapping 24 25# This sort of sucks, but seems to be as good as it gets... 26# This is essentially the same as re._pattern_type 27RE_TYPE = type(re.compile("")) 28 29 30class SON(dict): 31 """SON data. 32 33 A subclass of dict that maintains ordering of keys and provides a 34 few extra niceties for dealing with SON. SON provides an API 35 similar to collections.OrderedDict. 36 """ 37 38 def __init__(self, data=None, **kwargs): 39 self.__keys = [] 40 dict.__init__(self) 41 self.update(data) 42 self.update(kwargs) 43 44 def __new__(cls, *args, **kwargs): 45 instance = super(SON, cls).__new__(cls, *args, **kwargs) 46 instance.__keys = [] 47 return instance 48 49 def __repr__(self): 50 result = [] 51 for key in self.__keys: 52 result.append("(%r, %r)" % (key, self[key])) 53 return "SON([%s])" % ", ".join(result) 54 55 def __setitem__(self, key, value): 56 if key not in self.__keys: 57 self.__keys.append(key) 58 dict.__setitem__(self, key, value) 59 60 def __delitem__(self, key): 61 self.__keys.remove(key) 62 dict.__delitem__(self, key) 63 64 def copy(self): 65 other = SON() 66 other.update(self) 67 return other 68 69 # TODO this is all from UserDict.DictMixin. it could probably be made more 70 # efficient. 71 # second level definitions support higher levels 72 def __iter__(self): 73 for k in self.__keys: 74 yield k 75 76 def has_key(self, key): 77 return key in self.__keys 78 79 def iterkeys(self): 80 return self.__iter__() 81 82 # fourth level uses definitions from lower levels 83 def itervalues(self): 84 for _, v in self.items(): 85 yield v 86 87 def values(self): 88 return [v for _, v in self.items()] 89 90 def clear(self): 91 self.__keys = [] 92 super(SON, self).clear() 93 94 def setdefault(self, key, default=None): 95 try: 96 return self[key] 97 except KeyError: 98 self[key] = default 99 return default 100 101 def pop(self, key, *args): 102 if len(args) > 1: 103 raise TypeError("pop expected at most 2 arguments, got " + repr(1 + len(args))) 104 try: 105 value = self[key] 106 except KeyError: 107 if args: 108 return args[0] 109 raise 110 del self[key] 111 return value 112 113 def popitem(self): 114 try: 115 k, v = next(iter(self.items())) 116 except StopIteration: 117 raise KeyError("container is empty") 118 del self[k] 119 return (k, v) 120 121 def update(self, other=None, **kwargs): 122 # Make progressively weaker assumptions about "other" 123 if other is None: 124 pass 125 elif hasattr(other, "items"): 126 for k, v in other.items(): 127 self[k] = v 128 elif hasattr(other, "keys"): 129 for k in other.keys(): 130 self[k] = other[k] 131 else: 132 for k, v in other: 133 self[k] = v 134 if kwargs: 135 self.update(kwargs) 136 137 def get(self, key, default=None): 138 try: 139 return self[key] 140 except KeyError: 141 return default 142 143 def __eq__(self, other): 144 """Comparison to another SON is order-sensitive while comparison to a 145 regular dictionary is order-insensitive. 146 """ 147 if isinstance(other, SON): 148 return len(self) == len(other) and list(self.items()) == list(other.items()) 149 return self.to_dict() == other 150 151 def __ne__(self, other): 152 return not self == other 153 154 def __len__(self): 155 return len(self.__keys) 156 157 def to_dict(self): 158 """Convert a SON document to a normal Python dictionary instance. 159 160 This is trickier than just *dict(...)* because it needs to be 161 recursive. 162 """ 163 164 def transform_value(value): 165 if isinstance(value, list): 166 return [transform_value(v) for v in value] 167 elif isinstance(value, _Mapping): 168 return dict([(k, transform_value(v)) for k, v in value.items()]) 169 else: 170 return value 171 172 return transform_value(dict(self)) 173 174 def __deepcopy__(self, memo): 175 out = SON() 176 val_id = id(self) 177 if val_id in memo: 178 return memo.get(val_id) 179 memo[val_id] = out 180 for k, v in self.items(): 181 if not isinstance(v, RE_TYPE): 182 v = copy.deepcopy(v, memo) 183 out[k] = v 184 return out
31class SON(dict): 32 """SON data. 33 34 A subclass of dict that maintains ordering of keys and provides a 35 few extra niceties for dealing with SON. SON provides an API 36 similar to collections.OrderedDict. 37 """ 38 39 def __init__(self, data=None, **kwargs): 40 self.__keys = [] 41 dict.__init__(self) 42 self.update(data) 43 self.update(kwargs) 44 45 def __new__(cls, *args, **kwargs): 46 instance = super(SON, cls).__new__(cls, *args, **kwargs) 47 instance.__keys = [] 48 return instance 49 50 def __repr__(self): 51 result = [] 52 for key in self.__keys: 53 result.append("(%r, %r)" % (key, self[key])) 54 return "SON([%s])" % ", ".join(result) 55 56 def __setitem__(self, key, value): 57 if key not in self.__keys: 58 self.__keys.append(key) 59 dict.__setitem__(self, key, value) 60 61 def __delitem__(self, key): 62 self.__keys.remove(key) 63 dict.__delitem__(self, key) 64 65 def copy(self): 66 other = SON() 67 other.update(self) 68 return other 69 70 # TODO this is all from UserDict.DictMixin. it could probably be made more 71 # efficient. 72 # second level definitions support higher levels 73 def __iter__(self): 74 for k in self.__keys: 75 yield k 76 77 def has_key(self, key): 78 return key in self.__keys 79 80 def iterkeys(self): 81 return self.__iter__() 82 83 # fourth level uses definitions from lower levels 84 def itervalues(self): 85 for _, v in self.items(): 86 yield v 87 88 def values(self): 89 return [v for _, v in self.items()] 90 91 def clear(self): 92 self.__keys = [] 93 super(SON, self).clear() 94 95 def setdefault(self, key, default=None): 96 try: 97 return self[key] 98 except KeyError: 99 self[key] = default 100 return default 101 102 def pop(self, key, *args): 103 if len(args) > 1: 104 raise TypeError("pop expected at most 2 arguments, got " + repr(1 + len(args))) 105 try: 106 value = self[key] 107 except KeyError: 108 if args: 109 return args[0] 110 raise 111 del self[key] 112 return value 113 114 def popitem(self): 115 try: 116 k, v = next(iter(self.items())) 117 except StopIteration: 118 raise KeyError("container is empty") 119 del self[k] 120 return (k, v) 121 122 def update(self, other=None, **kwargs): 123 # Make progressively weaker assumptions about "other" 124 if other is None: 125 pass 126 elif hasattr(other, "items"): 127 for k, v in other.items(): 128 self[k] = v 129 elif hasattr(other, "keys"): 130 for k in other.keys(): 131 self[k] = other[k] 132 else: 133 for k, v in other: 134 self[k] = v 135 if kwargs: 136 self.update(kwargs) 137 138 def get(self, key, default=None): 139 try: 140 return self[key] 141 except KeyError: 142 return default 143 144 def __eq__(self, other): 145 """Comparison to another SON is order-sensitive while comparison to a 146 regular dictionary is order-insensitive. 147 """ 148 if isinstance(other, SON): 149 return len(self) == len(other) and list(self.items()) == list(other.items()) 150 return self.to_dict() == other 151 152 def __ne__(self, other): 153 return not self == other 154 155 def __len__(self): 156 return len(self.__keys) 157 158 def to_dict(self): 159 """Convert a SON document to a normal Python dictionary instance. 160 161 This is trickier than just *dict(...)* because it needs to be 162 recursive. 163 """ 164 165 def transform_value(value): 166 if isinstance(value, list): 167 return [transform_value(v) for v in value] 168 elif isinstance(value, _Mapping): 169 return dict([(k, transform_value(v)) for k, v in value.items()]) 170 else: 171 return value 172 173 return transform_value(dict(self)) 174 175 def __deepcopy__(self, memo): 176 out = SON() 177 val_id = id(self) 178 if val_id in memo: 179 return memo.get(val_id) 180 memo[val_id] = out 181 for k, v in self.items(): 182 if not isinstance(v, RE_TYPE): 183 v = copy.deepcopy(v, memo) 184 out[k] = v 185 return out
SON data.
A subclass of dict that maintains ordering of keys and provides a few extra niceties for dealing with SON. SON provides an API similar to collections.OrderedDict.
95 def setdefault(self, key, default=None): 96 try: 97 return self[key] 98 except KeyError: 99 self[key] = default 100 return default
Insert key with a value of default if key is not in the dictionary.
Return the value for key if key is in the dictionary, else default.
102 def pop(self, key, *args): 103 if len(args) > 1: 104 raise TypeError("pop expected at most 2 arguments, got " + repr(1 + len(args))) 105 try: 106 value = self[key] 107 except KeyError: 108 if args: 109 return args[0] 110 raise 111 del self[key] 112 return value
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
If the key is not found, return the default if given; otherwise, raise a KeyError.
114 def popitem(self): 115 try: 116 k, v = next(iter(self.items())) 117 except StopIteration: 118 raise KeyError("container is empty") 119 del self[k] 120 return (k, v)
Remove and return a (key, value) pair as a 2-tuple.
Pairs are returned in LIFO (last-in, first-out) order. Raises KeyError if the dict is empty.
122 def update(self, other=None, **kwargs): 123 # Make progressively weaker assumptions about "other" 124 if other is None: 125 pass 126 elif hasattr(other, "items"): 127 for k, v in other.items(): 128 self[k] = v 129 elif hasattr(other, "keys"): 130 for k in other.keys(): 131 self[k] = other[k] 132 else: 133 for k, v in other: 134 self[k] = v 135 if kwargs: 136 self.update(kwargs)
D.update([E, ]**F) -> None. Update D from dict/iterable E and F. If E is present and has a .keys() method, then does: for k in E: D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]
138 def get(self, key, default=None): 139 try: 140 return self[key] 141 except KeyError: 142 return default
Return the value for key if key is in the dictionary, else default.
158 def to_dict(self): 159 """Convert a SON document to a normal Python dictionary instance. 160 161 This is trickier than just *dict(...)* because it needs to be 162 recursive. 163 """ 164 165 def transform_value(value): 166 if isinstance(value, list): 167 return [transform_value(v) for v in value] 168 elif isinstance(value, _Mapping): 169 return dict([(k, transform_value(v)) for k, v in value.items()]) 170 else: 171 return value 172 173 return transform_value(dict(self))
Convert a SON document to a normal Python dictionary instance.
This is trickier than just dict(...) because it needs to be recursive.
Inherited Members
- builtins.dict
- keys
- items
- fromkeys