Skip to content
Permalink
Newer
Older
100644 1392 lines (1255 sloc) 40.2 KB
Sep 5, 2014
1
;(function($B){
2
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
24
keys with the same hash can be stored in a dictionary, $object_dict[hash] is a
25
list of [key, [value, rank]] lists.
26
*/
27
28
var _b_ = $B.builtins
30
var str_hash = _b_.str.__hash__,
Sep 5, 2014
32
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
}
109
}
110
111
$B.make_view = function(name){
112
var klass = $B.make_class(name, function(d, items, set_like){
113
return {
114
__class__: klass,
119
len: items.length,
120
set_like: set_like
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)
145
klass.__iter__ = function(self){
146
var it = klass.$iterator.$factory(self.items)
147
it.test_change = function(){
148
return self.dict.$version != self.dict_version
149
}
152
153
klass.__len__ = function(self){
154
return self.len
155
}
157
klass.__repr__ = function(self){
158
return klass.$infos.__name__ + '(' + _b_.repr(self.items) + ')'
159
}
160
161
$B.set_func_names(klass, "builtins")
Feb 11, 2018
165
var dict = {
Feb 11, 2018
166
__class__: _b_.type,
168
$infos: {
169
__module__: "builtins",
170
__name__: "dict"
171
},
Feb 11, 2018
172
$is_class: true,
173
$native: true,
174
$match_mapping_pattern: true // for pattern matching (PEP 634)
Sep 5, 2014
175
}
176
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
188
function to_list(d, ix){
189
var items = [],
190
item
192
if(d.$jsobj){
Mar 7, 2018
195
if(attr.charAt(0) != "$"){
196
var val = d.$jsobj[attr]
197
if(val === undefined){val = _b_.NotImplemented}
198
else if(val === null){val = $N}
202
}else if(_b_.isinstance(d, _b_.dict)){
203
for(var k in d.$numeric_dict){
204
items.push([parseFloat(k), d.$numeric_dict[k]])
205
}
207
for(var k in d.$string_dict){
208
items.push([k, d.$string_dict[k]])
209
}
211
for(var k in d.$object_dict){
212
d.$object_dict[k].forEach(function(item){
213
items.push(item)
214
})
215
}
217
// sort by insertion order
218
items.sort(function(a, b){
219
return a[1][1] - b[1][1]
220
})
221
items = items.map(function(item){return [item[0], item[1][0]]})
224
res = items.map(function(item){return item[ix]})
225
return res
226
}else{
227
items.__class__ = _b_.tuple
228
return items.map(function(item){
229
item.__class__ = _b_.tuple; return item}
230
)
231
}
Feb 9, 2015
233
234
$B.dict_to_list = to_list // used in py_types.js
235
236
var $copy_dict = function(left, right){
238
si = dict.$setitem
239
right.$version = right.$version || 0
240
var right_version = right.$version || 0
241
for(var i = 0, len = _l.length; i < len; i++){
242
si(left, _l[i][0], _l[i][1])
243
if(right.$version != right_version){
244
throw _b_.RuntimeError.$factory("dict mutated during update")
245
}
246
}
249
function rank(self, hash, key){
250
// Search if object key, with hash = hash(key), is in
251
// self.$object_dict
252
var pairs = self.$object_dict[hash]
253
if(pairs !== undefined){
254
for(var i = 0, len = pairs.length; i < len; i++){
255
if($B.rich_comp("__eq__", key, pairs[i][0])){
256
return i
257
}
258
}
259
}
260
return -1
261
}
262
Feb 11, 2018
263
dict.__bool__ = function () {
Mar 7, 2018
264
var $ = $B.args("__bool__", 1, {self: null}, ["self"],
265
arguments, {}, null, null)
Feb 11, 2018
266
return dict.__len__($.self) > 0
269
dict.__class_getitem__ = function(cls, item){
270
// PEP 585
271
// Set as a classmethod at the end of this script, after $B.set_func_names()
272
if(! Array.isArray(item)){
273
item = [item]
274
}
275
return $B.GenericAlias.$factory(cls, item)
276
}
277
Feb 11, 2018
278
dict.__contains__ = function(){
279
var $ = $B.args("__contains__", 2, {self: null, key: null},
280
["self", "key"], arguments, {}, null, null),
281
self = $.self,
284
if(self.$jsobj){
285
return self.$jsobj[key] !== undefined
286
}
288
switch(typeof key) {
290
return self.$string_dict[key] !== undefined
292
return self.$numeric_dict[key] !== undefined
293
}
294
295
var hash = _b_.hash(key)
296
if(self.$str_hash[hash] !== undefined &&
297
$B.rich_comp("__eq__", key, self.$str_hash[hash])){
298
return true
299
}
300
if(self.$numeric_dict[hash] !== undefined &&
301
$B.rich_comp("__eq__", key, hash)){
302
return true
303
}
304
return rank(self, hash, key) > -1
Sep 5, 2014
305
}
306
Feb 11, 2018
307
dict.__delitem__ = function(){
Nov 21, 2015
308
309
var $ = $B.args("__eq__", 2, {self: null, arg: null},
310
["self", "arg"], arguments, {}, null, null),
311
self = $.self,
Nov 21, 2015
313
314
if(self.$jsobj){
315
if(self.$jsobj[arg] === undefined){throw _b_.KeyError.$factory(arg)}
316
delete self.$jsobj[arg]
319
switch(typeof arg){
320
case "string":
321
if(self.$string_dict[arg] === undefined){
322
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
323
}
324
delete self.$string_dict[arg]
325
delete self.$str_hash[str_hash(arg)]
327
return $N
328
case "number":
329
if(self.$numeric_dict[arg] === undefined){
330
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
332
delete self.$numeric_dict[arg]
336
// go with defaults
337
338
var hash = _b_.hash(arg),
339
ix
341
if((ix = rank(self, hash, arg)) > -1){
342
self.$object_dict[hash].splice(ix, 1)
343
}else{
344
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
Sep 5, 2014
349
}
350
Feb 11, 2018
351
dict.__eq__ = function(){
Mar 7, 2018
352
var $ = $B.args("__eq__", 2, {self: null, other: null},
353
["self", "other"], arguments, {}, null, null),
354
self = $.self,
355
other = $.other
357
if(! _b_.isinstance(other, dict)){return false}
359
if(self.$jsobj){self = jsobj2dict(self.$jsobj)}
360
if(other.$jsobj){other = jsobj2dict(other.$jsobj)}
361
if(dict.__len__(self) != dict.__len__(other)){
362
return false
363
}
365
if(self.$string_dict.length != other.$string_dict.length){
369
for(var k in self.$numeric_dict){
370
if(other.$numeric_dict.hasOwnProperty(k)){
371
if(!$B.rich_comp("__eq__", other.$numeric_dict[k][0],
372
self.$numeric_dict[k][0])){
373
return false
374
}
375
}else if(other.$object_dict.hasOwnProperty(k)){
376
var pairs = other.$object_dict[k],
377
flag = false
378
for(var i = 0, len = pairs.length; i < len; i++){
379
if($B.rich_comp("__eq__", k, pairs[i][0]) &&
380
$B.rich_comp("__eq__", self.$numeric_dict[k],
381
pairs[i][1])){
382
flag = true
383
break
384
}
386
if(! flag){return false}
Nov 21, 2015
389
}
390
}
391
for(var k in self.$string_dict){
392
if(!other.$string_dict.hasOwnProperty(k) ||
393
!$B.rich_comp("__eq__", other.$string_dict[k][0],
394
self.$string_dict[k][0])){
Nov 21, 2015
396
}
397
}
398
for(var hash in self.$object_dict){
399
var pairs = self.$object_dict[hash]
400
// Get all (key, value) pairs in other that have the same hash
401
var other_pairs = []
402
if(other.$numeric_dict[hash] !== undefined){
403
other_pairs.push([hash, other.$numeric_dict[hash]])
404
}
405
if(other.$object_dict[hash] !== undefined){
406
other_pairs = other_pairs.concat(other.$object_dict[hash])
407
}
408
if(other_pairs.length == 0){
409
return false
410
}
411
for(var i = 0, len_i = pairs.length; i < len_i; i++){
412
var flag = false
413
var key = pairs[i][0],
414
value = pairs[i][1][0]
415
for(var j = 0, len_j = other_pairs.length; j < len_j; j++){
416
if($B.rich_comp("__eq__", key, other_pairs[j][0]) &&
417
$B.rich_comp("__eq__", value, other_pairs[j][1][0])){
418
flag = true
419
break
425
}
426
}
427
return true
Sep 5, 2014
428
}
429
Feb 11, 2018
430
dict.__getitem__ = function(){
431
var $ = $B.args("__getitem__", 2, {self: null, arg: null},
432
["self", "arg"], arguments, {}, null, null),
433
self = $.self,
435
return dict.$getitem(self, arg)
436
}
437
438
dict.$getitem = function(self, arg, ignore_missing){
439
// ignore_missing is set in dict.get and dict.setdefault
440
if(self.$jsobj){
441
if(self.$jsobj[arg] === undefined){
442
if(self.$jsobj.hasOwnProperty &&
443
self.$jsobj.hasOwnProperty(arg)){
445
}
446
throw _b_.KeyError.$factory(arg)
447
}
448
return self.$jsobj[arg]
450
451
switch(typeof arg){
452
case "string":
453
var x = self.$string_dict[arg]
454
if(x !== undefined){
455
return x[0]
457
break
458
case "number":
459
if(self.$numeric_dict[arg] !== undefined){
460
return self.$numeric_dict[arg][0]
462
break
463
}
464
465
// since the key is more complex use 'default' method of getting item
466
467
var hash = _b_.hash(arg),
468
_eq = function(other){return $B.rich_comp("__eq__", arg, other)}
469
470
if(typeof arg == "object"){
471
arg.$hash = hash // cache for setdefault
472
}
473
var sk = self.$str_hash[hash]
474
if(sk !== undefined && _eq(sk)){
475
return self.$string_dict[sk][0]
477
if(self.$numeric_dict[hash] !== undefined && _eq(hash)){
478
return self.$numeric_dict[hash][0]
480
if(_b_.isinstance(arg, _b_.str)){
481
// string subclass
482
var res = self.$string_dict[arg.valueOf()]
483
if(res !== undefined){return res[0]}
486
var ix = rank(self, hash, arg)
487
if(ix > -1){
488
return self.$object_dict[hash][ix][1][0]
491
if(! ignore_missing){
492
if(self.__class__ !== dict && ! ignore_missing){
493
try{
494
var missing_method = $B.$getattr(self.__class__,
495
"__missing__", _b_.None)
496
}catch(err){
497
console.log(err)
499
}
500
if(missing_method !== _b_.None){
501
return missing_method(self, arg)
502
}
505
throw _b_.KeyError.$factory(arg)
Sep 5, 2014
506
}
507
508
dict.__hash__ = _b_.None
Sep 5, 2014
509
510
function init_from_list(self, args){
511
var i = -1,
512
stop = args.length - 1,
513
si = dict.__setitem__
514
while(i++ < stop){
515
var item = args[i]
516
if(item.length != 2){
517
throw _b_.ValueError.$factory("dictionary " +
518
`update sequence element #${i} has length 1; 2 is required`)
519
}
520
switch(typeof item[0]) {
521
case 'string':
522
self.$string_dict[item[0]] = [item[1], self.$order++]
523
self.$str_hash[str_hash(item[0])] = item[0]
524
self.$version++
525
break
526
case 'number':
527
if(item[0] != 0 && item[0] != 1){
528
self.$numeric_dict[item[0]] = [item[1], self.$order++]
529
self.$version++
530
break
531
}
532
default:
533
si(self, item[0], item[1])
534
break
535
}
536
}
537
}
538
539
dict.__init__ = function(self, first, second){
540
if(first === undefined){
541
return $N
542
}
544
if(first.$nat != 'kw' && $B.get_class(first) === $B.JSObj){
545
for(var key in first){
546
self.$string_dict[key] = [first[key], self.$order++]
547
}
548
return _b_.None
549
}else if(first.$jsobj){
550
self.$jsobj = {}
551
for(var attr in first.$jsobj){
552
self.$jsobj[attr] = first.$jsobj[attr]
555
}else if(Array.isArray(first)){
556
init_from_list(self, first)
557
return $N
Sep 5, 2014
558
}
561
var $ = $B.args("dict", 1, {self:null}, ["self"],
562
arguments, {}, "first", "second")
563
var args = $.first
564
if(args.length > 1){
565
throw _b_.TypeError.$factory("dict expected at most 1 argument" +
566
", got 2")
567
}else if(args.length == 1){
568
args = args[0]
569
if(args.__class__ === dict){
570
['$string_dict', '$str_hash', '$numeric_dict', '$object_dict'].
571
forEach(function(d){
572
for(key in args[d]){self[d][key] = args[d][key]}
573
})
574
}else if(_b_.isinstance(args, dict)){
577
var keys = $B.$getattr(args, "keys", null)
578
if(keys !== null){
579
var gi = $B.$getattr(args, "__getitem__", null)
580
if(gi !== null){
581
// has keys and __getitem__ : it's a mapping, iterate on
582
// keys and values
583
gi = $B.$call(gi)
584
var kiter = _b_.iter($B.$call(keys)())
585
while(true){
586
try{
587
var key = _b_.next(kiter),
588
value = gi(key)
589
dict.__setitem__(self, key, value)
590
}catch(err){
591
if(err.__class__ === _b_.StopIteration){
592
break
593
}
594
throw err
595
}
596
}
597
return $N
598
}
599
}
600
if(! Array.isArray(args)){
601
args = _b_.list.$factory(args)
602
}
603
// Form "dict([[key1, value1], [key2,value2], ...])"
604
init_from_list(self, args)
Sep 5, 2014
605
}
607
var kw = $.second.$string_dict
608
for(var attr in kw){
609
switch(typeof attr){
610
case "string":
611
self.$string_dict[attr] = [kw[attr][0], self.$order++]
612
self.$str_hash[str_hash(attr)] = attr
613
break
614
case "number":
615
self.$numeric_dict[attr] = [kw[attr][0], self.$order++]
618
si(self, attr, kw[attr][0])
Sep 5, 2014
623
}
624
625
dict.__iter__ = function(self){
626
return _b_.iter(dict.keys(self))
Sep 5, 2014
627
}
628
629
dict.__ior__ = function(self, other){
630
// PEP 584
631
dict.update(self, other)
632
return self
633
}
634
Feb 11, 2018
635
dict.__len__ = function(self) {
638
if(self.$jsobj){
Mar 7, 2018
639
for(var attr in self.$jsobj){if(attr.charAt(0) != "$"){_count++}}
640
return _count
641
}
643
for(var k in self.$numeric_dict){_count++}
644
for(var k in self.$string_dict){_count++}
645
for(var hash in self.$object_dict){
646
_count += self.$object_dict[hash].length
647
}
Sep 5, 2014
651
652
dict.__ne__ = function(self, other){
653
return ! dict.__eq__(self, other)
654
}
Sep 5, 2014
655
Feb 11, 2018
656
dict.__new__ = function(cls){
657
if(cls === undefined){
Mar 7, 2018
658
throw _b_.TypeError.$factory("int.__new__(): not enough arguments")
660
var instance = {
662
$numeric_dict : {},
663
$object_dict : {},
666
$version: 0,
667
$order: 0
669
if(cls !== dict){
670
instance.__dict__ = $B.empty_dict()
671
}
672
return instance
675
dict.__or__ = function(self, other){
676
// PEP 584
677
if(! _b_.isinstance(other, dict)){
678
return _b_.NotImplemented
679
}
680
var res = dict.copy(self)
681
dict.update(res, other)
682
return res
683
}
684
685
function __newobj__(){
686
// __newobj__ is called with a generator as only argument
687
var $ = $B.args('__newobj__', 0, {}, [], arguments, {}, 'args', null),
688
args = $.args
689
var res = $B.empty_dict()
690
res.__class__ = args[0]
691
return res
692
}
693
694
dict.__reduce_ex__ = function(self, protocol){
695
return $B.fast_tuple([
696
__newobj__,
697
$B.fast_tuple([self.__class__]),
698
_b_.None,
699
_b_.None,
700
dict.items(self)])
701
}
702
Feb 11, 2018
703
dict.__repr__ = function(self){
704
$B.builtins_repr_check(dict, arguments) // in brython_builtins.js
705
if(self.$jsobj){ // wrapper around Javascript object
Feb 11, 2018
706
return dict.__repr__(jsobj2dict(self.$jsobj))
708
if($B.repr.enter(self)){
709
return "{...}"
710
}
711
var res = [],
713
items.forEach(function(item){
715
res.push(_b_.repr(item[0]) + ": " + _b_.repr(item[1]))
716
}catch(err){
717
throw err
718
}
720
$B.repr.leave(self)
Mar 7, 2018
721
return "{" + res.join(", ") + "}"
Sep 5, 2014
722
}
723
724
dict.__ror__ = function(self, other){
725
// PEP 584
726
if(! _b_.isinstance(other, dict)){
727
return _b_.NotImplemented
728
}
729
var res = dict.copy(other)
730
dict.update(res, self)
731
return res
732
}
733
734
dict.__setitem__ = function(self, key, value){
Mar 7, 2018
735
var $ = $B.args("__setitem__", 3, {self: null, key: null, value: null},
736
["self", "key", "value"], arguments, {}, null, null)
737
return dict.$setitem($.self, $.key, $.value)
738
}
Nov 21, 2015
739
740
dict.$setitem = function(self, key, value, $hash){
741
// Set a dictionary item mapping key and value.
742
//
743
// If key is a string, set:
744
// - $string_dict[key] = [value, order] where "order" is an auto-increment
745
// unique id to keep track of insertion order
746
// - $str_hash[hash(key)] to key
747
//
748
// If key is a number, set $numeric_dict[key] = value
749
//
750
// If key is another object, compute its hash value:
751
// - if the hash is a key of $str_hash, and key == $str_hash[hash],
752
// replace $string_dict[$str_hash[hash]] by value
753
// - if the hash is a key of $numeric_dict, and hash == key, replace
754
// $numeric_dict[hash] by value
755
// - if the hash is a key of $object_dict: $object_dict[hash] is a list
756
// of [k, v] pairs. If key is equal to one of the "k", replace the
757
// matching v by value. Otherwise, add [key, value] to the list
758
// - else set $object_dict[hash] = [[key, value]]
759
//
760
// In all cases, increment attribute $version, used to detect dictionary
761
// changes during an iteration.
763
// Parameter $hash is only set if this method is called by setdefault.
764
// In this case the hash of key has already been computed and we
765
// know that the key is not present in the dictionary, so it's no
766
// use computing hash(key) again, nor testing equality of keys
768
if(self.$from_js){
769
// dictionary created by method to_dict of JSObj instances
770
value = $B.pyobj2jsobj(value)
771
}
772
if(self.$jsobj.__class__ === _b_.type){
773
self.$jsobj[key] = value
774
if(key == "__init__" || key == "__new__"){
775
// If class attribute __init__ or __new__ are reset,
776
// the factory function has to change
777
self.$jsobj.$factory = $B.$instance_creator(self.$jsobj)
778
}
779
}else{
780
self.$jsobj[key] = value
784
if(key instanceof String){
785
key = key.valueOf()
786
}
788
switch(typeof key){
789
case "string":
790
if(self.$string_dict === undefined){
791
console.log("pas de string dict", self, key, value)
792
}
793
if(self.$string_dict[key] !== undefined){
794
self.$string_dict[key][0] = value
795
}else{
796
self.$string_dict[key] = [value, self.$order++]
797
self.$str_hash[str_hash(key)] = key
798
self.$version++
799
}
800
return $N
801
case "number":
802
if(self.$numeric_dict[key] !== undefined){
803
// existing key: preserve order
804
self.$numeric_dict[key][0] = value
805
}else{
806
// special case for 0 and 1 if True or False are keys
807
var done = false
808
if((key == 0 || key == 1) &&
809
self.$object_dict[key] !== undefined){
810
for(const item of self.$object_dict[key]){
811
if((key == 0 && item[0] === false) ||
812
(key == 1 && item[0] === true)){
813
// replace value
814
item[1][0] = value
815
done = true
816
}
817
}
818
}
819
if(! done){
820
// new key
821
self.$numeric_dict[key] = [value, self.$order++]
822
}
825
return $N
826
case "boolean":
827
// true replaces 1 and false replaces 0
828
var num = key ? 1 : 0
829
if(self.$numeric_dict[num] !== undefined){
830
var order = self.$numeric_dict[num][1] // preserve order
831
self.$numeric_dict[num] = [value, order]
832
return
833
}
834
if(self.$object_dict[num] !== undefined){
835
self.$object_dict[num].push([key, [value, self.$order++]])
836
}else{
837
self.$object_dict[num] = [[key, [value, self.$order++]]]
838
}
841
// if we got here the key is more complex, use default method
842
843
var hash = $hash === undefined ? _b_.hash(key) : $hash,
844
_eq = function(other){return $B.rich_comp("__eq__", key, other)}
845
846
if(self.$numeric_dict[hash] !== undefined && _eq(hash)){
847
self.$numeric_dict[hash] = [value, self.$numeric_dict[hash][1]]
851
var sk = self.$str_hash[hash]
852
if(sk !== undefined && _eq(sk)){
853
self.$string_dict[sk] = [value, self.$string_dict[sk][1]]
858
// If $setitem is called from setdefault, don't test equality of key
859
// with any object
860
if($hash){
861
if(self.$object_dict[$hash] !== undefined){
862
self.$object_dict[$hash].push([key, [value, self.$order++]])
864
self.$object_dict[$hash] = [[key, [value, self.$order++]]]
865
}
866
self.$version++
867
return $N
868
}
869
var ix = rank(self, hash, key)
870
if(ix > -1){
871
// reset value
872
self.$object_dict[hash][ix][1] = [value,
873
self.$object_dict[hash][ix][1][1]]
874
return $N
875
}else if(self.$object_dict.hasOwnProperty(hash)){
876
self.$object_dict[hash].push([key, [value, self.$order++]])
878
self.$object_dict[hash] = [[key, [value, self.$order++]]]
Sep 5, 2014
882
}
883
884
// add "reflected" methods
Feb 11, 2018
885
$B.make_rmethods(dict)
Sep 5, 2014
886
Feb 11, 2018
887
dict.clear = function(){
Sep 5, 2014
888
// Remove all items from the dictionary.
Mar 7, 2018
889
var $ = $B.args("clear", 1, {self: null}, ["self"], arguments, {},
890
null, null),
891
self = $.self
893
self.$numeric_dict = {}
894
self.$string_dict = {}
895
self.$str_hash = {}
896
self.$object_dict = {}
898
if(self.$jsobj){
899
for(var attr in self.$jsobj){
Mar 7, 2018
900
if(attr.charAt(0) !== "$" && attr !== "__class__"){
901
delete self.$jsobj[attr]
902
}
903
}
904
}
Sep 5, 2014
908
}
909
Feb 11, 2018
910
dict.copy = function(self){
Sep 5, 2014
911
// Return a shallow copy of the dictionary
Mar 7, 2018
912
var $ = $B.args("copy", 1, {self: null},["self"], arguments,{},
913
null, null),
914
self = $.self,
Sep 5, 2014
917
return res
918
}
919
Feb 11, 2018
920
dict.fromkeys = function(){
Nov 21, 2015
921
Mar 7, 2018
922
var $ = $B.args("fromkeys", 3, {cls: null, keys: null, value: null},
923
["cls", "keys", "value"], arguments, {value: _b_.None}, null, null),
924
keys = $.keys,
925
value = $.value
Sep 5, 2014
927
// class method
928
var klass = $.cls,
Sep 5, 2014
932
while(1){
933
try{
934
var key = _b_.next(keys_iter)
935
if(klass === dict){dict.$setitem(res, key, value)}
936
else{$B.$getattr(res, "__setitem__")(key, value)}
Sep 5, 2014
937
}catch(err){
938
if($B.is_exc(err, [_b_.StopIteration])){
Sep 5, 2014
939
return res
940
}
941
throw err
942
}
943
}
944
}
945
Feb 11, 2018
946
dict.get = function(){
Mar 7, 2018
947
var $ = $B.args("get", 3, {self: null, key: null, _default: null},
948
["self", "key", "_default"], arguments, {_default: $N}, null, null)
950
try{
951
// call $getitem with ignore_missign set to true
952
return dict.$getitem($.self, $.key, true)
953
}catch(err){
954
if(_b_.isinstance(err, _b_.KeyError)){return $._default}
955
else{throw err}
956
}
957
}
958
959
var dict_items = $B.make_view("dict_items", true)
960
dict_items.$iterator = $B.make_iterator_class("dict_itemiterator")
961
Feb 11, 2018
962
dict.items = function(self){
Mar 23, 2018
963
if(arguments.length > 1){
964
var _len = arguments.length - 1,
965
_msg = "items() takes no arguments (" + _len + " given)"
966
throw _b_.TypeError.$factory(_msg)
967
}
968
var items = to_list(self),
969
set_like = true
970
// Check if all values are hashable
971
for(var i = 0, len = items.length; i < len; i++){
972
try{
973
_b_.hash(items[i][1])
974
}catch(err){
975
set_like = false
976
break
977
}
978
}
979
var values = to_list(self)
980
var it = dict_items.$factory(self, values, set_like)
981
it.dict_version = self.$version
983
}
984
986
var dict_keys = $B.make_view("dict_keys")
987
dict_keys.$iterator = $B.make_iterator_class("dict_keyiterator")
Nov 21, 2015
988
989
dict.keys = function(self){
Mar 23, 2018
990
if(arguments.length > 1){
991
var _len = arguments.length - 1,
992
_msg = "keys() takes no arguments (" + _len + " given)"
993
throw _b_.TypeError.$factory(_msg)
Nov 21, 2015
994
}
995
var it = dict_keys.$factory(self, to_list(self, 0), true)
996
it.dict_version = self.$version
Nov 21, 2015
998
}
999
Feb 11, 2018
1000
dict.pop = function(){
Nov 21, 2015
1001
1002
var missing = {},
1003
$ = $B.args("pop", 3, {self: null, key: null, _default: null},
1004
["self", "key", "_default"], arguments, {_default: missing}, null, null),
1005
self = $.self,
1006
key = $.key,
1007
_default = $._default
Nov 21, 2015
1008
Sep 5, 2014
1009
try{
1010
var res = dict.__getitem__(self, key)
1011
dict.__delitem__(self, key)
Sep 5, 2014
1012
return res
1013
}catch(err){
1014
if(err.__class__ === _b_.KeyError){
1015
if(_default !== missing){return _default}
Sep 5, 2014
1016
throw err
1017
}
1018
throw err
1019
}
1020
}
1021
Feb 11, 2018
1022
dict.popitem = function(self){
1024
var itm = _b_.next(_b_.iter(dict.items(self)))
1025
dict.__delitem__(self, itm[0])
Feb 11, 2018
1026
return _b_.tuple.$factory(itm)
1028
if (err.__class__ == _b_.StopIteration) {
1029
throw _b_.KeyError.$factory("'popitem(): dictionary is empty'")
Sep 5, 2014
1032
}
1033
Feb 11, 2018
1034
dict.setdefault = function(){
Nov 21, 2015
1035
Mar 7, 2018
1036
var $ = $B.args("setdefault", 3, {self: null, key: null, _default: null},
1037
["self", "key", "_default"], arguments, {_default: $N}, null, null),
1038
self = $.self,
1039
key = $.key,
1040
_default = $._default
1041
try{
1042
// Pass 3rd argument to dict.$getitem to avoid using __missing__
1043
// Cf. issue #1598
1044
return dict.$getitem(self, key, true)
1045
}catch(err){
1046
if(err.__class__ !== _b_.KeyError){
1047
throw err
1048
}
1049
if(_default === undefined){_default = $N}
1050
var hash = key.$hash
1051
key.$hash = undefined
1052
dict.$setitem(self, key, _default, hash)
Sep 5, 2014
1053
return _default
1054
}
1055
}
1056
Feb 11, 2018
1057
dict.update = function(self){
Nov 21, 2015
1058
Mar 7, 2018
1059
var $ = $B.args("update", 1, {"self": null}, ["self"], arguments,
1060
{}, "args", "kw"),
1061
self = $.self,
1062
args = $.args,
1063
kw = $.kw
1064
if(args.length > 0){
1065
var o = args[0]
1067
if(o.$jsobj){
1068
o = jsobj2dict(o.$jsobj)
1069
}
1071
}else if(_b_.hasattr(o, "keys")){
1072
var _keys = _b_.list.$factory($B.$call($B.$getattr(o, "keys"))())
1073
for(var i = 0, len = _keys.length; i < len; i++){
1074
var _value = $B.$getattr(o, "__getitem__")(_keys[i])
1075
dict.$setitem(self, _keys[i], _value)
1076
}
1077
}else{
1078
var it = _b_.iter(o),
1079
i = 0
1080
while(true){
1081
try{
1082
var item = _b_.next(it)
1083
}catch(err){
1084
if(err.__class__ === _b_.StopIteration){break}
1085
throw err
1086
}
1087
try{
1088
key_value = _b_.list.$factory(item)
1089
}catch(err){
1090
throw _b_.TypeError.$factory("cannot convert dictionary" +
1091
" update sequence element #" + i + " to a sequence")
1092
}
1093
if(key_value.length !== 2){
1094
throw _b_.ValueError.$factory("dictionary update " +
1095
"sequence element #" + i + " has length " +
1096
key_value.length + "; 2 is required")
1097
}
1098
dict.$setitem(self, key_value[0], key_value[1])
1099
i++
Sep 5, 2014
1102
}
Sep 5, 2014
1106
}
1107
1108
var dict_values = $B.make_view("dict_values")
1109
dict_values.$iterator = $B.make_iterator_class("dict_valueiterator")
Nov 21, 2015
1110
Feb 11, 2018
1111
dict.values = function(self){
Mar 23, 2018
1112
if(arguments.length > 1){
1113
var _len = arguments.length - 1,
1114
_msg = "values() takes no arguments (" + _len + " given)"
1115
throw _b_.TypeError.$factory(_msg)
Nov 21, 2015
1116
}
1117
var values = to_list(self, 1)
1118
var it = dict_values.$factory(self, values, false)
1119
it.dict_version = self.$version
Nov 21, 2015
1121
}
1122
1123
dict.$factory = function(){
1124
var res = dict.__new__(dict)
1125
var args = [res]
1126
for(var i = 0, len = arguments.length; i < len ; i++){
1127
args.push(arguments[i])
1128
}
1129
dict.__init__.apply(null, args)
Sep 5, 2014
1130
return res
1131
}
Sep 5, 2014
1133
_b_.dict = dict
Feb 11, 2018
1135
$B.set_func_names(dict, "builtins")
1136
1137
dict.__class_getitem__ = _b_.classmethod.$factory(dict.__class_getitem__)
1138
1139
$B.empty_dict = function(){
1140
return {
1141
__class__: dict,
1142
$numeric_dict : {},
1143
$object_dict : {},
1144
$string_dict : {},
1145
$str_hash: {},
1146
$version: 0,
1147
$order: 0
1151
// This must be done after set_func_names, otherwise dict.fromkeys doesn't
1152
// have the attribute $infos
1153
dict.fromkeys = _b_.classmethod.$factory(dict.fromkeys)
1154
1155
$B.getset_descriptor = $B.make_class("getset_descriptor",
1156
function(klass, attr){
1157
return {
1158
__class__: $B.getset_descriptor,
1159
__doc__: _b_.None,
1160
cls: klass,
1161
attr: attr
1162
}
1163
}
1164
)
1165
1166
$B.getset_descriptor.__repr__ = $B.getset_descriptor.__str__ = function(self){
1167
return `<attribute '${self.attr}' of '${self.cls.$infos.__name__}' objects>`
1168
}
1169
1170
$B.set_func_names($B.getset_descriptor, "builtins")
1171
1172
// Class for attribute __dict__ of classes
1173
var mappingproxy = $B.mappingproxy = $B.make_class("mappingproxy",
Feb 12, 2018
1174
function(obj){
1175
if(_b_.isinstance(obj, dict)){
1176
// obj is a dictionary, with $string_dict table such that
1177
// obj.$string_dict[key] = [value, rank]
1178
// Transform it into an object with attribute $jsobj such that
1179
// res.$jsobj[key] = value
1180
var res = $B.obj_dict(dict.$to_obj(obj))
1181
}else{
1182
var res = $B.obj_dict(obj)
1183
}
Feb 12, 2018
1184
res.__class__ = mappingproxy
1185
return res
1186
}
1187
)
1189
mappingproxy.$match_mapping_pattern = true // for pattern matching (PEP 634)
1190
Feb 12, 2018
1191
mappingproxy.__setitem__ = function(){
Mar 7, 2018
1192
throw _b_.TypeError.$factory("'mappingproxy' object does not support " +
1193
"item assignment")
1196
for(var attr in dict){
1197
if(mappingproxy[attr] !== undefined ||
1198
["__class__", "__mro__", "__new__", "__init__", "__delitem__",
1199
"clear", "fromkeys", "pop", "popitem", "setdefault",
1200
"update"].indexOf(attr) > -1){
1201
continue
1202
}
1203
if(typeof dict[attr] == "function"){
1204
mappingproxy[attr] = (function(key){
1205
return function(){
1206
return dict[key].apply(null, arguments)
1207
}
1208
})(attr)
1209
}else{
1210
mappingproxy[attr] = dict[attr]
1211
}
1212
}
1213
Feb 12, 2018
1214
$B.set_func_names(mappingproxy, "builtins")
Mar 7, 2018
1219
if(attr.charAt(0) != "$" && attr !== "__class__"){
1220
if(x[attr] === null){
1221
d.$string_dict[attr] = [_b_.None, d.$order++]
1222
}else if(x[attr] === undefined){
1223
continue
1224
}else if(x[attr].$jsobj === x){
1225
d.$string_dict[attr] = [d, d.$order++]
1227
d.$string_dict[attr] = [$B.$JS2Py(x[attr]), d.$order++]
1229
}
1230
}
1231
return d
1232
}
1234
$B.obj_dict = function(obj, from_js){
1235
var klass = obj.__class__ || $B.get_class(obj)
1236
if(klass !== undefined && klass.$native){
1237
throw $B.attr_error("__dict__", obj)
1238
}
1240
res.$jsobj = obj
1241
res.$from_js = from_js
1242
return res
1243
}
1244
1245
// Wrapper around a JS object to handle it as a Python dictionary.
1246
// Some keys of the original object can be ignored by passing
1247
// the filtering function exclude().
1248
// Supports adding new keys.
1249
1250
var jsobj_as_pydict = $B.jsobj_as_pydict = $B.make_class('jsobj_as_pydict',
1251
function(jsobj, exclude){
1252
return {
1253
__class__: jsobj_as_pydict,
1254
obj: jsobj,
1255
exclude: exclude ? exclude : function(){return false},
1256
new_keys: []
1257
}
1258
}
1259
)
1260
1261
jsobj_as_pydict.__contains__ = function(self, key){
1262
if(self.new_keys.indexOf(key) > -1){
1263
return true
1264
}
1265
return ! (self.exclude(key) || self.obj[key] === undefined)
1266
}
1267
1268
jsobj_as_pydict.__delitem__ = function(self, key){
1269
jsobj_as_pydict.__getitem__(self, key) // raises KeyError if not present
1270
delete self.obj[key]
1271
var ix = self.new_keys.indexOf(key)
1272
if(ix > -1){
1273
self.new_keys.splice(ix, 1)
1274
}
1275
}
1276
1277
jsobj_as_pydict.__eq__ = function(self, other){
1278
if(other.__class__ !== jsobj_as_pydict){
1279
return _b_.NotImplemented
1280
}
1281
// create true Python dicts with the items in self and other
1282
var self1 = $B.empty_dict()
1283
other1 = $B.empty_dict()
1284
1285
dict.__init__(self1, jsobj_as_pydict.items(self))
1286
dict.__init__(other1, jsobj_as_pydict.items(other))
1287
1288
// Compare true Python dicts
1289
return dict.__eq__(self1, other1)
1290
}
1291
1292
jsobj_as_pydict.__getitem__ = function(self, key){
1293
if(jsobj_as_pydict.__contains__(self, key)){
1294
return self.obj[key]
1295
}
1296
throw _b_.KeyError.$factory(key)
1297
}
1298
1299
jsobj_as_pydict.__iter__ = function(self){
1300
return _b_.iter(jsobj_as_pydict.keys(self))
1301
}
1302
1303
jsobj_as_pydict.__len__ = function(self){
1304
var len = 0
1305
for(var key in self.obj){
1306
if(! self.exclude(key)){
1307
len++
1308
}
1309
}
1310
return len + self.new_keys.length
1311
}
1312
1313
jsobj_as_pydict.__repr__ = function(self){
1314
if($B.repr.enter(self)){
1315
return "{...}"
1316
}
1317
var res = [],
1318
items = _b_.list.$factory(jsobj_as_pydict.items(self))
1319
for(var item of items){
1320
res.push(_b_.repr(item[0]) + ": " + _b_.repr(item[1]))
1321
}
1322
$B.repr.leave(self)
1323
return "{" + res.join(", ") + "}"
1324
}
1325
1326
jsobj_as_pydict.__setitem__ = function(self, key, value){
1327
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1328
self.new_keys.push(key)
1329
}
1330
self.obj[key] = value
1331
}
1332
1333
jsobj_as_pydict.get = function(self, key, _default){
1334
_default = _default === undefined ? _b_.None : _default
1335
if(self.exclude(key) || self.obj[key] === undefined){
1336
return _default
1337
}
1338
return self.obj[key]
1339
}
1340
1341
jsobj_as_pydict.items = function(self){
1342
var items = []
1343
for(var key in self.obj){
1344
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1345
continue
1346
}
1347
items.push($B.fast_tuple([key, self.obj[key]]))
1348
}
1349
var set_like = true
1350
// Check if all values are hashable
1351
for(var item of items){
1352
try{
1353
_b_.hash(item[1])
1354
}catch(err){
1355
set_like = false
1356
break
1357
}
1359
var it = dict_items.$factory(self, items, set_like)
1360
it.dict_version = self.$version
1361
return it
1362
}
1363
1364
jsobj_as_pydict.keys = function(self){
1365
var lst = []
1366
for(var key in self.obj){
1367
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1368
continue
1369
}
1370
lst.push(key)
1371
}
1372
var it = dict_keys.$factory(self, lst, true)
1373
it.dict_version = self.$version
1374
return it
1375
}
1376
1377
jsobj_as_pydict.values = function(self){
1378
var values = []
1379
for(var key in self.obj){
1380
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1381
continue
1382
}
1383
values.push(self.obj[key])
1385
var it = dict_values.$factory(self, values, false)
1386
it.dict_version = self.$version
1387
return it
1388
}
1389
1390
$B.set_func_names(jsobj_as_pydict, 'builtins')
1391
Sep 5, 2014
1392
})(__BRYTHON__)