Permalink
Feb 1, 2020
Jul 21, 2020
Dec 28, 2020
Dec 28, 2020
Dec 28, 2020
May 17, 2019
Feb 1, 2020
Jan 15, 2018
Apr 3, 2019
Apr 3, 2019
Feb 1, 2020
Apr 3, 2019
Dec 13, 2018
Oct 5, 2020
Dec 10, 2018
Dec 10, 2018
Mar 7, 2018
Feb 26, 2018
Feb 1, 2020
Dec 10, 2018
Dec 10, 2018
Jan 29, 2021
Jul 30, 2020
Jul 14, 2020
Jul 31, 2018
Jul 31, 2018
Dec 10, 2018
Nov 2, 2018
Jul 31, 2018
Jun 11, 2020
Dec 10, 2018
Jun 11, 2020
Jun 11, 2020
May 27, 2018
Apr 18, 2020
Feb 1, 2020
Feb 3, 2018
Feb 1, 2020
Jul 4, 2020
Jul 4, 2020
Jul 30, 2020
Jul 30, 2020
Mar 7, 2018
Mar 7, 2018
Jul 24, 2021
Nov 9, 2015
May 17, 2019
Feb 26, 2018
Jul 21, 2020
Dec 28, 2020
Feb 26, 2018
Dec 28, 2020
Dec 13, 2018
Mar 7, 2018
Jan 29, 2021
Mar 7, 2018
Feb 26, 2018
Apr 14, 2019
Dec 13, 2018
May 17, 2019
Feb 26, 2018
Dec 28, 2020
Dec 1, 2018
Jun 29, 2020
Jun 28, 2018
May 16, 2020
May 16, 2020
Feb 1, 2020
Mar 7, 2018
Aug 2, 2018
Newer
100644
1406 lines (1268 sloc)
40.7 KB
3
/*
4
Implementation of Python dictionaries
5
6
We can't use Javascript's Map here, because the behaviour is not exactly the
7
same (eg with keys that are instances of classes with a __hash__ method...)
8
and because Map is much slower than regular Javascript objects.
9
10
A Python dictionary is implemented as a Javascript objects with these
11
attributes:
12
. $version: an integer with an initial value of 0, incremented at each
13
insertion
14
. $numeric_dict: for keys of type int
15
. $string_dict and $str_hash: for keys of type str
16
. $object_dict: for keys of other types
17
18
The value associated to a key in $numeric_dict and $string_dict is a pair
19
[value, rank] where "value" is the value associated with the key and "rank"
20
is the value of the dict attribute $version when the pair is inserted. This
21
is required to keep track of the insertion order, mandatory since Python 3.7.
22
23
For keys that are not str or int, their hash value is computed. Since several
33
var set_ops = ["eq", "le", "lt", "ge", "gt",
34
"sub", "rsub", "and", "or", "xor"]
35
36
// methods to compare non set-like views
37
function is_sublist(t1, t2){
38
// Return true if all elements of t1 are in t2
39
for(var i = 0, ilen = t1.length; i < ilen; i++){
40
var x = t1[i],
41
flag = false
42
for(var j = 0, jlen = t2.length; j < jlen; j++){
43
if($B.rich_comp("__eq__", x, t2[j])){
44
t2.splice(j, 1)
45
flag = true
46
break
47
}
48
}
49
if(! flag){
50
return false
51
}
52
}
53
return true
54
}
55
56
dict_view_op = {
57
__eq__: function(t1, t2){
58
return t1.length == t2.length && is_sublist(t1, t2)
59
},
60
__ne__: function(t1, t2){
61
return ! dict_view_op.__eq__(t1, t2)
62
},
63
__lt__: function(t1, t2){
64
return t1.length < t2.length && is_sublist(t1, t2)
65
},
66
__gt__: function(t1, t2){
67
return dict_view_op.__lt__(t2, t1)
68
},
69
__le__: function(t1, t2){
70
return t1.length <= t2.length && is_sublist(t1, t2)
71
},
72
__ge__: function(t1, t2){
73
return dict_view_op.__le__(t2, t1)
74
},
75
__and__: function(t1, t2){
76
var items = []
77
for(var i = 0, ilen = t1.length; i < ilen; i++){
78
var x = t1[i]
79
flag = false
80
for(var j = 0, jlen = t2.length; j < jlen; j++){
81
if($B.rich_comp("__eq__", x, t2[j])){
82
t2.splice(j, 1)
83
items.push(x)
84
break
85
}
86
}
87
}
88
return items
89
},
90
__or__: function(t1, t2){
91
var items = t1
92
for(var j = 0, jlen = t2.length; j < jlen; j++){
93
var y = t2[j],
94
flag = false
95
for(var i = 0, ilen = t1.length; i < ilen; i++){
96
if($B.rich_comp("__eq__", y, t1[i])){
97
t2.splice(j, 1)
98
flag = true
99
break
100
}
101
}
102
if(! flag){
103
items.push(y)
104
}
105
}
106
return items
107
}
124
for(var i = 0, len = set_ops.length; i < len; i++){
125
var op = "__" + set_ops[i] + "__"
126
klass[op] = (function(op){
127
return function(self, other){
128
// compare set of items to other
129
if(self.set_like){
130
return _b_.set[op](_b_.set.$factory(self),
131
_b_.set.$factory(other))
132
}else{
133
// Non-set like views can only be compared to
134
// instances of the same class
135
if(other.__class__ !== klass){
136
return false
138
var other_items = _b_.list.$factory(other)
139
return dict_view_op[op](self.items, other_items)
147
it.test_change = function(){
148
return self.dict.$version != self.dict_version
149
}
157
klass.__repr__ = function(self){
158
return klass.$infos.__name__ + '(' + _b_.repr(self.items) + ')'
159
}
160
177
dict.$to_obj = function(d){
178
// Function applied to dictionary that only have string keys,
179
// return a Javascript objects with the kays mapped to the value,
180
// excluding the insertion rank
181
var res = {}
182
for(var key in d.$string_dict){
183
res[key] = d.$string_dict[key][0]
184
}
185
return res
186
}
187
198
if(val === undefined){val = _b_.NotImplemented}
199
else if(val === null){val = $N}
204
for(var k in d.$numeric_dict){
205
items.push([parseFloat(k), d.$numeric_dict[k]])
206
}
212
for(var k in d.$object_dict){
213
d.$object_dict[k].forEach(function(item){
214
items.push(item)
215
})
216
}
218
// sort by insertion order
219
items.sort(function(a, b){
220
return a[1][1] - b[1][1]
221
})
222
items = items.map(function(item){return [item[0], item[1][0]]})
227
}else{
228
items.__class__ = _b_.tuple
229
return items.map(function(item){
230
item.__class__ = _b_.tuple; return item}
231
)
232
}
243
si(left, _l[i][0], _l[i][1])
244
if(right.$version != right_version){
245
throw _b_.RuntimeError.$factory("dict mutated during update")
246
}
247
}
250
function rank(self, hash, key){
251
// Search if object key, with hash = hash(key), is in
252
// self.$object_dict
253
var pairs = self.$object_dict[hash]
254
if(pairs !== undefined){
255
for(var i = 0, len = pairs.length; i < len; i++){
256
if($B.rich_comp("__eq__", key, pairs[i][0])){
257
return i
258
}
259
}
260
}
261
return -1
262
}
263
270
dict.__class_getitem__ = function(cls, item){
271
// PEP 585
272
// Set as a classmethod at the end of this script, after $B.set_func_names()
273
if(! Array.isArray(item)){
274
item = [item]
275
}
276
return $B.GenericAlias.$factory(cls, item)
277
}
278
280
var $ = $B.args("__contains__", 2, {self: null, key: null},
281
["self", "key"], arguments, {}, null, null),
293
return self.$numeric_dict[key] !== undefined
294
}
295
296
var hash = _b_.hash(key)
297
if(self.$str_hash[hash] !== undefined &&
310
var $ = $B.args("__eq__", 2, {self: null, arg: null},
311
["self", "arg"], arguments, {}, null, null),
320
switch(typeof arg){
321
case "string":
322
if(self.$string_dict[arg] === undefined){
342
if((ix = rank(self, hash, arg)) > -1){
343
self.$object_dict[hash].splice(ix, 1)
344
}else{
353
var $ = $B.args("__eq__", 2, {self: null, other: null},
354
["self", "other"], arguments, {}, null, null),
360
if(self.$jsobj){self = jsobj2dict(self.$jsobj)}
361
if(other.$jsobj){other = jsobj2dict(other.$jsobj)}
372
if(!$B.rich_comp("__eq__", other.$numeric_dict[k][0],
373
self.$numeric_dict[k][0])){
377
var pairs = other.$object_dict[k],
378
flag = false
379
for(var i = 0, len = pairs.length; i < len; i++){
380
if($B.rich_comp("__eq__", k, pairs[i][0]) &&
381
$B.rich_comp("__eq__", self.$numeric_dict[k],
382
pairs[i][1])){
383
flag = true
384
break
385
}
400
var pairs = self.$object_dict[hash]
401
// Get all (key, value) pairs in other that have the same hash
402
var other_pairs = []
403
if(other.$numeric_dict[hash] !== undefined){
404
other_pairs.push([hash, other.$numeric_dict[hash]])
405
}
407
other_pairs = other_pairs.concat(other.$object_dict[hash])
408
}
409
if(other_pairs.length == 0){
410
return false
411
}
412
for(var i = 0, len_i = pairs.length; i < len_i; i++){
413
var flag = false
414
var key = pairs[i][0],
416
for(var j = 0, len_j = other_pairs.length; j < len_j; j++){
417
if($B.rich_comp("__eq__", key, other_pairs[j][0]) &&
432
var $ = $B.args("__getitem__", 2, {self: null, arg: null},
433
["self", "arg"], arguments, {}, null, null),
442
if(self.$exclude && self.$exclude(arg)){
443
throw _b_.KeyError.$factory(arg)
444
}
466
break
467
}
468
469
// since the key is more complex use 'default' method of getting item
470
495
if(! ignore_missing){
496
if(self.__class__ !== dict && ! ignore_missing){
497
try{
520
if(item.length != 2){
521
throw _b_.ValueError.$factory("dictionary " +
522
`update sequence element #${i} has length 1; 2 is required`)
523
}
531
if(item[0] != 0 && item[0] != 1){
532
self.$numeric_dict[item[0]] = [item[1], self.$order++]
533
self.$version++
534
break
535
}
549
for(var key in first){
550
self.$string_dict[key] = [first[key], self.$order++]
551
}
552
return _b_.None
553
}else if(first.$jsobj){
554
self.$jsobj = {}
555
for(var attr in first.$jsobj){
556
self.$jsobj[attr] = first.$jsobj[attr]
566
arguments, {}, "first", "second")
567
var args = $.first
568
if(args.length > 1){
569
throw _b_.TypeError.$factory("dict expected at most 1 argument" +
570
", got 2")
571
}else if(args.length == 1){
572
args = args[0]
573
if(args.__class__ === dict){
574
['$string_dict', '$str_hash', '$numeric_dict', '$object_dict'].
575
forEach(function(d){
576
for(key in args[d]){self[d][key] = args[d][key]}
577
})
581
var keys = $B.$getattr(args, "keys", null)
582
if(keys !== null){
583
var gi = $B.$getattr(args, "__getitem__", null)
584
if(gi !== null){
585
// has keys and __getitem__ : it's a mapping, iterate on
586
// keys and values
587
gi = $B.$call(gi)
588
var kiter = _b_.iter($B.$call(keys)())
589
while(true){
590
try{
591
var key = _b_.next(kiter),
592
value = gi(key)
593
dict.__setitem__(self, key, value)
594
}catch(err){
595
if(err.__class__ === _b_.StopIteration){
596
break
597
}
598
throw err
599
}
600
}
601
return $N
602
}
603
}
604
if(! Array.isArray(args)){
605
args = _b_.list.$factory(args)
606
}
607
// Form "dict([[key1, value1], [key2,value2], ...])"
633
dict.__ior__ = function(self, other){
634
// PEP 584
635
dict.update(self, other)
636
return self
637
}
638
643
for(var attr in self.$jsobj){
644
if(attr.charAt(0) != "$" &&
645
((! self.$exclude) || ! self.$exclude(attr))){
646
_count++
647
}
648
}
652
for(var k in self.$numeric_dict){_count++}
653
for(var k in self.$string_dict){_count++}
654
for(var hash in self.$object_dict){
655
_count += self.$object_dict[hash].length
656
}
684
dict.__or__ = function(self, other){
685
// PEP 584
686
if(! _b_.isinstance(other, dict)){
687
return _b_.NotImplemented
688
}
689
var res = dict.copy(self)
690
dict.update(res, other)
691
return res
692
}
693
694
function __newobj__(){
695
// __newobj__ is called with a generator as only argument
696
var $ = $B.args('__newobj__', 0, {}, [], arguments, {}, 'args', null),
697
args = $.args
698
var res = $B.empty_dict()
699
res.__class__ = args[0]
700
return res
701
}
702
703
dict.__reduce_ex__ = function(self, protocol){
704
return $B.fast_tuple([
705
__newobj__,
706
$B.fast_tuple([self.__class__]),
707
_b_.None,
708
_b_.None,
709
dict.items(self)])
710
}
711
733
dict.__ror__ = function(self, other){
734
// PEP 584
735
if(! _b_.isinstance(other, dict)){
736
return _b_.NotImplemented
737
}
738
var res = dict.copy(other)
739
dict.update(res, self)
740
return res
741
}
742
745
["self", "key", "value"], arguments, {}, null, null)
746
return dict.$setitem($.self, $.key, $.value)
747
}
752
// If key is a string, set:
753
// - $string_dict[key] = [value, order] where "order" is an auto-increment
754
// unique id to keep track of insertion order
755
// - $str_hash[hash(key)] to key
756
//
757
// If key is a number, set $numeric_dict[key] = value
758
//
759
// If key is another object, compute its hash value:
760
// - if the hash is a key of $str_hash, and key == $str_hash[hash],
761
// replace $string_dict[$str_hash[hash]] by value
762
// - if the hash is a key of $numeric_dict, and hash == key, replace
763
// $numeric_dict[hash] by value
764
// - if the hash is a key of $object_dict: $object_dict[hash] is a list
765
// of [k, v] pairs. If key is equal to one of the "k", replace the
766
// matching v by value. Otherwise, add [key, value] to the list
767
// - else set $object_dict[hash] = [[key, value]]
768
//
769
// In all cases, increment attribute $version, used to detect dictionary
772
// Parameter $hash is only set if this method is called by setdefault.
773
// In this case the hash of key has already been computed and we
774
// know that the key is not present in the dictionary, so it's no
775
// use computing hash(key) again, nor testing equality of keys
784
// If class attribute __init__ or __new__ are reset,
785
// the factory function has to change
786
self.$jsobj.$factory = $B.$instance_creator(self.$jsobj)
787
}
788
}else{
799
if(self.$string_dict === undefined){
800
console.log("pas de string dict", self, key, value)
801
}
803
self.$string_dict[key][0] = value
804
}else{
805
self.$string_dict[key] = [value, self.$order++]
806
self.$str_hash[str_hash(key)] = key
807
self.$version++
808
}
811
if(self.$numeric_dict[key] !== undefined){
812
// existing key: preserve order
813
self.$numeric_dict[key][0] = value
814
}else{
815
// special case for 0 and 1 if True or False are keys
816
var done = false
817
if((key == 0 || key == 1) &&
818
self.$object_dict[key] !== undefined){
819
for(const item of self.$object_dict[key]){
820
if((key == 0 && item[0] === false) ||
821
(key == 1 && item[0] === true)){
822
// replace value
823
item[1][0] = value
824
done = true
825
}
826
}
827
}
828
if(! done){
829
// new key
830
self.$numeric_dict[key] = [value, self.$order++]
831
}
835
case "boolean":
836
// true replaces 1 and false replaces 0
837
var num = key ? 1 : 0
838
if(self.$numeric_dict[num] !== undefined){
839
var order = self.$numeric_dict[num][1] // preserve order
840
self.$numeric_dict[num] = [value, order]
841
return
842
}
843
if(self.$object_dict[num] !== undefined){
844
self.$object_dict[num].push([key, [value, self.$order++]])
845
}else{
846
self.$object_dict[num] = [[key, [value, self.$order++]]]
847
}
867
// If $setitem is called from setdefault, don't test equality of key
868
// with any object
869
if($hash){
870
if(self.$object_dict[$hash] !== undefined){
874
}
875
self.$version++
876
return $N
877
}
878
var ix = rank(self, hash, key)
879
if(ix > -1){
880
// reset value
931
var $ = $B.args("fromkeys", 3, {cls: null, keys: null, value: null},
932
["cls", "keys", "value"], arguments, {value: _b_.None}, null, null),
944
if(klass === dict){dict.$setitem(res, key, value)}
945
else{$B.$getattr(res, "__setitem__")(key, value)}
956
var $ = $B.args("get", 3, {self: null, key: null, _default: null},
957
["self", "key", "_default"], arguments, {_default: $N}, null, null)
959
try{
960
// call $getitem with ignore_missign set to true
961
return dict.$getitem($.self, $.key, true)
962
}catch(err){
963
if(_b_.isinstance(err, _b_.KeyError)){return $._default}
964
else{throw err}
965
}
966
}
967
968
var dict_items = $B.make_view("dict_items", true)
969
dict_items.$iterator = $B.make_iterator_class("dict_itemiterator")
973
var _len = arguments.length - 1,
974
_msg = "items() takes no arguments (" + _len + " given)"
977
var items = to_list(self),
978
set_like = true
979
// Check if all values are hashable
980
for(var i = 0, len = items.length; i < len; i++){
981
try{
982
_b_.hash(items[i][1])
983
}catch(err){
984
set_like = false
985
break
986
}
987
}
988
var values = to_list(self)
989
var it = dict_items.$factory(self, values, set_like)
990
it.dict_version = self.$version
1000
var _len = arguments.length - 1,
1001
_msg = "keys() takes no arguments (" + _len + " given)"
1004
var it = dict_keys.$factory(self, to_list(self, 0), true)
1005
it.dict_version = self.$version
1011
var missing = {},
1012
$ = $B.args("pop", 3, {self: null, key: null, _default: null},
1013
["self", "key", "_default"], arguments, {_default: missing}, null, null),
1045
var $ = $B.args("setdefault", 3, {self: null, key: null, _default: null},
1046
["self", "key", "_default"], arguments, {_default: $N}, null, null),
1050
try{
1051
// Pass 3rd argument to dict.$getitem to avoid using __missing__
1052
// Cf. issue #1598
1053
return dict.$getitem(self, key, true)
1054
}catch(err){
1059
var hash = key.$hash
1060
key.$hash = undefined
1061
dict.$setitem(self, key, _default, hash)
1068
var $ = $B.args("update", 1, {"self": null}, ["self"], arguments,
1069
{}, "args", "kw"),
1070
self = $.self,
1071
args = $.args,
1072
kw = $.kw
1073
if(args.length > 0){
1074
var o = args[0]
1081
var _keys = _b_.list.$factory($B.$call($B.$getattr(o, "keys"))())
1082
for(var i = 0, len = _keys.length; i < len; i++){
1084
dict.$setitem(self, _keys[i], _value)
1085
}
1086
}else{
1087
var it = _b_.iter(o),
1088
i = 0
1089
while(true){
1090
try{
1091
var item = _b_.next(it)
1092
}catch(err){
1093
if(err.__class__ === _b_.StopIteration){break}
1094
throw err
1095
}
1096
try{
1097
key_value = _b_.list.$factory(item)
1098
}catch(err){
1099
throw _b_.TypeError.$factory("cannot convert dictionary" +
1100
" update sequence element #" + i + " to a sequence")
1101
}
1102
if(key_value.length !== 2){
1103
throw _b_.ValueError.$factory("dictionary update " +
1104
"sequence element #" + i + " has length " +
1105
key_value.length + "; 2 is required")
1106
}
1107
dict.$setitem(self, key_value[0], key_value[1])
1108
i++
1117
var dict_values = $B.make_view("dict_values")
1118
dict_values.$iterator = $B.make_iterator_class("dict_valueiterator")
1122
var _len = arguments.length - 1,
1123
_msg = "values() takes no arguments (" + _len + " given)"
1127
var it = dict_values.$factory(self, values, false)
1128
it.dict_version = self.$version
1134
var args = [res]
1135
for(var i = 0, len = arguments.length; i < len ; i++){
1136
args.push(arguments[i])
1137
}
1138
dict.__init__.apply(null, args)
1148
$B.empty_dict = function(){
1149
return {
1150
__class__: dict,
1151
$numeric_dict : {},
1152
$object_dict : {},
1153
$string_dict : {},
1154
$str_hash: {},
1160
// This must be done after set_func_names, otherwise dict.fromkeys doesn't
1161
// have the attribute $infos
1162
dict.fromkeys = _b_.classmethod.$factory(dict.fromkeys)
1163
1164
$B.getset_descriptor = $B.make_class("getset_descriptor",
1165
function(klass, attr){
1166
return {
1167
__class__: $B.getset_descriptor,
1169
cls: klass,
1170
attr: attr
1171
}
1172
}
1173
)
1174
1175
$B.getset_descriptor.__repr__ = $B.getset_descriptor.__str__ = function(self){
1176
return `<attribute '${self.attr}' of '${self.cls.$infos.__name__}' objects>`
1177
}
1178
1179
$B.set_func_names($B.getset_descriptor, "builtins")
1180
1185
// obj is a dictionary, with $string_dict table such that
1186
// obj.$string_dict[key] = [value, rank]
1187
// Transform it into an object with attribute $jsobj such that
1188
// res.$jsobj[key] = value
1189
var res = $B.obj_dict(dict.$to_obj(obj))
1200
mappingproxy.__repr__ = function(){
1201
return '<mappingproxy object>'
1202
}
1203
1205
throw _b_.TypeError.$factory("'mappingproxy' object does not support " +
1206
"item assignment")
1209
for(var attr in dict){
1210
if(mappingproxy[attr] !== undefined ||
1211
["__class__", "__mro__", "__new__", "__init__", "__delitem__",
1212
"clear", "fromkeys", "pop", "popitem", "setdefault",
1213
"update"].indexOf(attr) > -1){
1214
continue
1215
}
1216
if(typeof dict[attr] == "function"){
1217
mappingproxy[attr] = (function(key){
1218
return function(){
1219
return dict[key].apply(null, arguments)
1220
}
1221
})(attr)
1222
}else{
1223
mappingproxy[attr] = dict[attr]
1224
}
1225
}
1226
1229
function jsobj2dict(x, exclude){
1230
exclude = exclude || function(){return false}
1259
// Wrapper around a JS object to handle it as a Python dictionary.
1260
// Some keys of the original object can be ignored by passing
1261
// the filtering function exclude().
1262
// Supports adding new keys.
1263
1264
var jsobj_as_pydict = $B.jsobj_as_pydict = $B.make_class('jsobj_as_pydict',
1265
function(jsobj, exclude){
1266
return {
1267
__class__: jsobj_as_pydict,
1268
obj: jsobj,
1269
exclude: exclude ? exclude : function(){return false},
1270
new_keys: []
1271
}
1272
}
1273
)
1274
1275
jsobj_as_pydict.__contains__ = function(self, key){
1276
if(self.new_keys.indexOf(key) > -1){
1277
return true
1278
}
1279
return ! (self.exclude(key) || self.obj[key] === undefined)
1280
}
1281
1282
jsobj_as_pydict.__delitem__ = function(self, key){
1283
jsobj_as_pydict.__getitem__(self, key) // raises KeyError if not present
1284
delete self.obj[key]
1285
var ix = self.new_keys.indexOf(key)
1286
if(ix > -1){
1287
self.new_keys.splice(ix, 1)
1288
}
1289
}
1290
1291
jsobj_as_pydict.__eq__ = function(self, other){
1292
if(other.__class__ !== jsobj_as_pydict){
1293
return _b_.NotImplemented
1294
}
1295
// create true Python dicts with the items in self and other
1296
var self1 = $B.empty_dict()
1297
other1 = $B.empty_dict()
1298
1299
dict.__init__(self1, jsobj_as_pydict.items(self))
1300
dict.__init__(other1, jsobj_as_pydict.items(other))
1301
1302
// Compare true Python dicts
1303
return dict.__eq__(self1, other1)
1304
}
1305
1306
jsobj_as_pydict.__getitem__ = function(self, key){
1307
if(jsobj_as_pydict.__contains__(self, key)){
1308
return self.obj[key]
1309
}
1310
throw _b_.KeyError.$factory(key)
1311
}
1312
1313
jsobj_as_pydict.__iter__ = function(self){
1314
return _b_.iter(jsobj_as_pydict.keys(self))
1315
}
1316
1317
jsobj_as_pydict.__len__ = function(self){
1318
var len = 0
1319
for(var key in self.obj){
1320
if(! self.exclude(key)){
1321
len++
1322
}
1323
}
1324
return len + self.new_keys.length
1325
}
1326
1327
jsobj_as_pydict.__repr__ = function(self){
1328
if($B.repr.enter(self)){
1329
return "{...}"
1330
}
1331
var res = [],
1332
items = _b_.list.$factory(jsobj_as_pydict.items(self))
1333
for(var item of items){
1334
res.push(_b_.repr(item[0]) + ": " + _b_.repr(item[1]))
1335
}
1336
$B.repr.leave(self)
1337
return "{" + res.join(", ") + "}"
1338
}
1339
1340
jsobj_as_pydict.__setitem__ = function(self, key, value){
1341
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1342
self.new_keys.push(key)
1343
}
1344
self.obj[key] = value
1345
}
1346
1347
jsobj_as_pydict.get = function(self, key, _default){
1348
_default = _default === undefined ? _b_.None : _default
1349
if(self.exclude(key) || self.obj[key] === undefined){
1350
return _default
1351
}
1352
return self.obj[key]
1353
}
1354
1355
jsobj_as_pydict.items = function(self){
1357
for(var key in self.obj){
1358
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1359
continue
1360
}
1361
items.push($B.fast_tuple([key, self.obj[key]]))
1362
}
1363
var set_like = true
1364
// Check if all values are hashable
1365
for(var item of items){
1366
try{
1367
_b_.hash(item[1])
1368
}catch(err){
1369
set_like = false
1370
break
1371
}
1373
var it = dict_items.$factory(self, items, set_like)
1374
it.dict_version = self.$version
1375
return it
1376
}
1377
1378
jsobj_as_pydict.keys = function(self){
1379
var lst = []
1380
for(var key in self.obj){
1381
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1382
continue
1383
}
1384
lst.push(key)
1385
}
1386
var it = dict_keys.$factory(self, lst, true)
1387
it.dict_version = self.$version
1388
return it
1393
for(var key in self.obj){
1394
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1395
continue
1396
}
1399
var it = dict_values.$factory(self, values, false)
1400
it.dict_version = self.$version
1401
return it