Skip to content
Permalink
Newer
Older
100644 1397 lines (1259 sloc) 40.4 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){
195
if((! attr.startsWith("$")) &&
196
((! d.$exclude) || ! d.$exclude(attr))){
197
var val = d.$jsobj[attr]
198
if(val === undefined){val = _b_.NotImplemented}
199
else if(val === null){val = $N}
203
}else if(_b_.isinstance(d, _b_.dict)){
204
for(var k in d.$numeric_dict){
205
items.push([parseFloat(k), d.$numeric_dict[k]])
206
}
208
for(var k in d.$string_dict){
209
items.push([k, d.$string_dict[k]])
210
}
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]]})
225
res = items.map(function(item){return item[ix]})
226
return res
227
}else{
228
items.__class__ = _b_.tuple
229
return items.map(function(item){
230
item.__class__ = _b_.tuple; return item}
231
)
232
}
Feb 9, 2015
234
235
$B.dict_to_list = to_list // used in py_types.js
236
237
var $copy_dict = function(left, right){
239
si = dict.$setitem
240
right.$version = right.$version || 0
241
var right_version = right.$version || 0
242
for(var i = 0, len = _l.length; i < len; i++){
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
Feb 11, 2018
264
dict.__bool__ = function () {
Mar 7, 2018
265
var $ = $B.args("__bool__", 1, {self: null}, ["self"],
266
arguments, {}, null, null)
Feb 11, 2018
267
return dict.__len__($.self) > 0
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
Feb 11, 2018
279
dict.__contains__ = function(){
280
var $ = $B.args("__contains__", 2, {self: null, key: null},
281
["self", "key"], arguments, {}, null, null),
282
self = $.self,
285
if(self.$jsobj){
286
return self.$jsobj[key] !== undefined
287
}
289
switch(typeof key) {
291
return self.$string_dict.hasOwnProperty(key)
293
return self.$numeric_dict[key] !== undefined
294
}
295
296
var hash = _b_.hash(key)
297
if(self.$str_hash[hash] !== undefined &&
298
$B.rich_comp("__eq__", key, self.$str_hash[hash])){
299
return true
300
}
301
if(self.$numeric_dict[hash] !== undefined &&
302
$B.rich_comp("__eq__", key, hash)){
303
return true
304
}
305
return rank(self, hash, key) > -1
Sep 5, 2014
306
}
307
Feb 11, 2018
308
dict.__delitem__ = function(){
Nov 21, 2015
309
310
var $ = $B.args("__eq__", 2, {self: null, arg: null},
311
["self", "arg"], arguments, {}, null, null),
312
self = $.self,
Nov 21, 2015
314
315
if(self.$jsobj){
316
if(self.$jsobj[arg] === undefined){throw _b_.KeyError.$factory(arg)}
317
delete self.$jsobj[arg]
320
switch(typeof arg){
321
case "string":
322
if(self.$string_dict[arg] === undefined){
323
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
324
}
325
delete self.$string_dict[arg]
326
delete self.$str_hash[str_hash(arg)]
328
return $N
329
case "number":
330
if(self.$numeric_dict[arg] === undefined){
331
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
333
delete self.$numeric_dict[arg]
337
// go with defaults
338
339
var hash = _b_.hash(arg),
340
ix
342
if((ix = rank(self, hash, arg)) > -1){
343
self.$object_dict[hash].splice(ix, 1)
344
}else{
345
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
Sep 5, 2014
350
}
351
Feb 11, 2018
352
dict.__eq__ = function(){
Mar 7, 2018
353
var $ = $B.args("__eq__", 2, {self: null, other: null},
354
["self", "other"], arguments, {}, null, null),
355
self = $.self,
356
other = $.other
358
if(! _b_.isinstance(other, dict)){return false}
360
if(self.$jsobj){self = jsobj2dict(self.$jsobj)}
361
if(other.$jsobj){other = jsobj2dict(other.$jsobj)}
362
if(dict.__len__(self) != dict.__len__(other)){
363
return false
364
}
366
if(self.$string_dict.length != other.$string_dict.length){
370
for(var k in self.$numeric_dict){
371
if(other.$numeric_dict.hasOwnProperty(k)){
372
if(!$B.rich_comp("__eq__", other.$numeric_dict[k][0],
373
self.$numeric_dict[k][0])){
374
return false
375
}
376
}else if(other.$object_dict.hasOwnProperty(k)){
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
}
387
if(! flag){return false}
Nov 21, 2015
390
}
391
}
392
for(var k in self.$string_dict){
393
if(!other.$string_dict.hasOwnProperty(k) ||
394
!$B.rich_comp("__eq__", other.$string_dict[k][0],
395
self.$string_dict[k][0])){
Nov 21, 2015
397
}
398
}
399
for(var hash in self.$object_dict){
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
}
406
if(other.$object_dict[hash] !== undefined){
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],
415
value = pairs[i][1][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]) &&
418
$B.rich_comp("__eq__", value, other_pairs[j][1][0])){
419
flag = true
420
break
426
}
427
}
428
return true
Sep 5, 2014
429
}
430
Feb 11, 2018
431
dict.__getitem__ = function(){
432
var $ = $B.args("__getitem__", 2, {self: null, arg: null},
433
["self", "arg"], arguments, {}, null, null),
434
self = $.self,
436
return dict.$getitem(self, arg)
437
}
438
439
dict.$getitem = function(self, arg, ignore_missing){
440
// ignore_missing is set in dict.get and dict.setdefault
441
if(self.$jsobj){
442
if(self.$exclude && self.$exclude(arg)){
443
throw _b_.KeyError.$factory(arg)
444
}
445
if(self.$jsobj[arg] === undefined){
446
if(self.$jsobj.hasOwnProperty &&
447
self.$jsobj.hasOwnProperty(arg)){
449
}
450
throw _b_.KeyError.$factory(arg)
451
}
452
return self.$jsobj[arg]
454
455
switch(typeof arg){
456
case "string":
457
if(self.$string_dict.hasOwnProperty(arg)){
458
return self.$string_dict[arg][0]
460
break
461
case "number":
462
if(self.$numeric_dict[arg] !== undefined){
463
return self.$numeric_dict[arg][0]
465
break
466
}
467
468
// since the key is more complex use 'default' method of getting item
469
470
var hash = _b_.hash(arg),
471
_eq = function(other){return $B.rich_comp("__eq__", arg, other)}
472
473
if(typeof arg == "object"){
474
arg.$hash = hash // cache for setdefault
475
}
476
var sk = self.$str_hash[hash]
477
if(sk !== undefined && _eq(sk)){
478
return self.$string_dict[sk][0]
480
if(self.$numeric_dict[hash] !== undefined && _eq(hash)){
481
return self.$numeric_dict[hash][0]
483
if(_b_.isinstance(arg, _b_.str)){
485
if(self.$string_dict.hasOwnProperty(arg.valueOf())){
486
return self.$string_dict[arg.valueOf()][0]
487
}
490
var ix = rank(self, hash, arg)
491
if(ix > -1){
492
return self.$object_dict[hash][ix][1][0]
495
if(! ignore_missing){
496
if(self.__class__ !== dict && ! ignore_missing){
497
try{
498
var missing_method = $B.$getattr(self.__class__,
499
"__missing__", _b_.None)
500
}catch(err){
501
console.log(err)
503
}
504
if(missing_method !== _b_.None){
505
return missing_method(self, arg)
506
}
509
throw _b_.KeyError.$factory(arg)
Sep 5, 2014
510
}
511
512
dict.__hash__ = _b_.None
Sep 5, 2014
513
514
function init_from_list(self, args){
515
var i = -1,
516
stop = args.length - 1,
517
si = dict.__setitem__
518
while(i++ < stop){
519
var item = args[i]
520
if(item.length != 2){
521
throw _b_.ValueError.$factory("dictionary " +
522
`update sequence element #${i} has length 1; 2 is required`)
523
}
524
switch(typeof item[0]) {
525
case 'string':
526
self.$string_dict[item[0]] = [item[1], self.$order++]
527
self.$str_hash[str_hash(item[0])] = item[0]
528
self.$version++
529
break
530
case 'number':
531
if(item[0] != 0 && item[0] != 1){
532
self.$numeric_dict[item[0]] = [item[1], self.$order++]
533
self.$version++
534
break
535
}
536
default:
537
si(self, item[0], item[1])
538
break
539
}
540
}
541
}
542
543
dict.__init__ = function(self, first, second){
544
if(first === undefined){
545
return $N
546
}
548
if(first.$nat != 'kw' && $B.get_class(first) === $B.JSObj){
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]
559
}else if(Array.isArray(first)){
560
init_from_list(self, first)
561
return $N
Sep 5, 2014
562
}
565
var $ = $B.args("dict", 1, {self:null}, ["self"],
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
})
578
}else if(_b_.isinstance(args, dict)){
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], ...])"
608
init_from_list(self, args)
Sep 5, 2014
609
}
611
var kw = $.second.$string_dict
612
for(var attr in kw){
613
switch(typeof attr){
614
case "string":
615
self.$string_dict[attr] = [kw[attr][0], self.$order++]
616
self.$str_hash[str_hash(attr)] = attr
617
break
618
case "number":
619
self.$numeric_dict[attr] = [kw[attr][0], self.$order++]
622
si(self, attr, kw[attr][0])
Sep 5, 2014
627
}
628
629
dict.__iter__ = function(self){
630
return _b_.iter(dict.keys(self))
Sep 5, 2014
631
}
632
633
dict.__ior__ = function(self, other){
634
// PEP 584
635
dict.update(self, other)
636
return self
637
}
638
Feb 11, 2018
639
dict.__len__ = function(self) {
642
if(self.$jsobj){
643
for(var attr in self.$jsobj){
644
if(attr.charAt(0) != "$" &&
645
((! self.$exclude) || ! self.$exclude(attr))){
646
_count++
647
}
648
}
649
return _count
650
}
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
}
Sep 5, 2014
660
661
dict.__ne__ = function(self, other){
662
return ! dict.__eq__(self, other)
663
}
Sep 5, 2014
664
Feb 11, 2018
665
dict.__new__ = function(cls){
666
if(cls === undefined){
Mar 7, 2018
667
throw _b_.TypeError.$factory("int.__new__(): not enough arguments")
669
var instance = {
671
$numeric_dict : {},
672
$object_dict : {},
675
$version: 0,
676
$order: 0
678
if(cls !== dict){
679
instance.__dict__ = $B.empty_dict()
680
}
681
return instance
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
Feb 11, 2018
712
dict.__repr__ = function(self){
713
$B.builtins_repr_check(dict, arguments) // in brython_builtins.js
714
if(self.$jsobj){ // wrapper around Javascript object
715
return dict.__repr__(jsobj2dict(self.$jsobj, self.$exclude))
717
if($B.repr.enter(self)){
718
return "{...}"
719
}
720
var res = [],
722
items.forEach(function(item){
724
res.push(_b_.repr(item[0]) + ": " + _b_.repr(item[1]))
725
}catch(err){
726
throw err
727
}
729
$B.repr.leave(self)
Mar 7, 2018
730
return "{" + res.join(", ") + "}"
Sep 5, 2014
731
}
732
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
743
dict.__setitem__ = function(self, key, value){
Mar 7, 2018
744
var $ = $B.args("__setitem__", 3, {self: null, key: null, value: null},
745
["self", "key", "value"], arguments, {}, null, null)
746
return dict.$setitem($.self, $.key, $.value)
747
}
Nov 21, 2015
748
749
dict.$setitem = function(self, key, value, $hash){
750
// Set a dictionary item mapping key and value.
751
//
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
770
// changes during an iteration.
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
777
if(self.$from_js){
778
// dictionary created by method to_dict of JSObj instances
779
value = $B.pyobj2jsobj(value)
780
}
781
if(self.$jsobj.__class__ === _b_.type){
782
self.$jsobj[key] = value
783
if(key == "__init__" || key == "__new__"){
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{
789
self.$jsobj[key] = value
793
if(key instanceof String){
794
key = key.valueOf()
795
}
797
switch(typeof key){
798
case "string":
799
if(self.$string_dict === undefined){
800
console.log("pas de string dict", self, key, value)
801
}
802
if(self.$string_dict.hasOwnProperty(key)){
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
}
809
return $N
810
case "number":
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
}
834
return $N
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
}
850
// if we got here the key is more complex, use default method
851
852
var hash = $hash === undefined ? _b_.hash(key) : $hash,
853
_eq = function(other){return $B.rich_comp("__eq__", key, other)}
854
855
if(self.$numeric_dict[hash] !== undefined && _eq(hash)){
856
self.$numeric_dict[hash] = [value, self.$numeric_dict[hash][1]]
860
var sk = self.$str_hash[hash]
861
if(sk !== undefined && _eq(sk)){
862
self.$string_dict[sk] = [value, self.$string_dict[sk][1]]
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){
871
self.$object_dict[$hash].push([key, [value, self.$order++]])
873
self.$object_dict[$hash] = [[key, [value, self.$order++]]]
874
}
875
self.$version++
876
return $N
877
}
878
var ix = rank(self, hash, key)
879
if(ix > -1){
880
// reset value
881
self.$object_dict[hash][ix][1] = [value,
882
self.$object_dict[hash][ix][1][1]]
883
return $N
884
}else if(self.$object_dict.hasOwnProperty(hash)){
885
self.$object_dict[hash].push([key, [value, self.$order++]])
887
self.$object_dict[hash] = [[key, [value, self.$order++]]]
Sep 5, 2014
891
}
892
893
// add "reflected" methods
Feb 11, 2018
894
$B.make_rmethods(dict)
Sep 5, 2014
895
Feb 11, 2018
896
dict.clear = function(){
Sep 5, 2014
897
// Remove all items from the dictionary.
Mar 7, 2018
898
var $ = $B.args("clear", 1, {self: null}, ["self"], arguments, {},
899
null, null),
900
self = $.self
902
self.$numeric_dict = {}
903
self.$string_dict = {}
904
self.$str_hash = {}
905
self.$object_dict = {}
907
if(self.$jsobj){
908
for(var attr in self.$jsobj){
Mar 7, 2018
909
if(attr.charAt(0) !== "$" && attr !== "__class__"){
910
delete self.$jsobj[attr]
911
}
912
}
913
}
Sep 5, 2014
917
}
918
Feb 11, 2018
919
dict.copy = function(self){
Sep 5, 2014
920
// Return a shallow copy of the dictionary
Mar 7, 2018
921
var $ = $B.args("copy", 1, {self: null},["self"], arguments,{},
922
null, null),
923
self = $.self,
Sep 5, 2014
926
return res
927
}
928
Feb 11, 2018
929
dict.fromkeys = function(){
Nov 21, 2015
930
Mar 7, 2018
931
var $ = $B.args("fromkeys", 3, {cls: null, keys: null, value: null},
932
["cls", "keys", "value"], arguments, {value: _b_.None}, null, null),
933
keys = $.keys,
934
value = $.value
Sep 5, 2014
936
// class method
937
var klass = $.cls,
Sep 5, 2014
941
while(1){
942
try{
943
var key = _b_.next(keys_iter)
944
if(klass === dict){dict.$setitem(res, key, value)}
945
else{$B.$getattr(res, "__setitem__")(key, value)}
Sep 5, 2014
946
}catch(err){
947
if($B.is_exc(err, [_b_.StopIteration])){
Sep 5, 2014
948
return res
949
}
950
throw err
951
}
952
}
953
}
954
Feb 11, 2018
955
dict.get = function(){
Mar 7, 2018
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")
970
Feb 11, 2018
971
dict.items = function(self){
972
var $ = $B.args('items', 1, {self: null}, ['self'], arguments,
973
{}, null, null)
974
var items = to_list(self),
975
set_like = true
976
// Check if all values are hashable
977
for(var i = 0, len = items.length; i < len; i++){
978
try{
979
_b_.hash(items[i][1])
980
}catch(err){
981
set_like = false
982
break
983
}
984
}
985
var values = to_list(self)
986
var it = dict_items.$factory(self, values, set_like)
987
it.dict_version = self.$version
989
}
990
992
var dict_keys = $B.make_view("dict_keys")
993
dict_keys.$iterator = $B.make_iterator_class("dict_keyiterator")
Nov 21, 2015
994
995
dict.keys = function(self){
996
var $ = $B.args('keys', 1, {self: null}, ['self'], arguments,
997
{}, null, null)
998
var it = dict_keys.$factory(self, to_list(self, 0), true)
999
it.dict_version = self.$version
Nov 21, 2015
1001
}
1002
Feb 11, 2018
1003
dict.pop = function(){
Nov 21, 2015
1004
1005
var missing = {},
1006
$ = $B.args("pop", 3, {self: null, key: null, _default: null},
1007
["self", "key", "_default"], arguments, {_default: missing}, null, null),
1008
self = $.self,
1009
key = $.key,
1010
_default = $._default
Nov 21, 2015
1011
Sep 5, 2014
1012
try{
1013
var res = dict.__getitem__(self, key)
1014
dict.__delitem__(self, key)
Sep 5, 2014
1015
return res
1016
}catch(err){
1017
if(err.__class__ === _b_.KeyError){
1018
if(_default !== missing){return _default}
Sep 5, 2014
1019
throw err
1020
}
1021
throw err
1022
}
1023
}
1024
Feb 11, 2018
1025
dict.popitem = function(self){
1027
var itm = _b_.next(_b_.iter(dict.items(self)))
1028
dict.__delitem__(self, itm[0])
Feb 11, 2018
1029
return _b_.tuple.$factory(itm)
1031
if (err.__class__ == _b_.StopIteration) {
1032
throw _b_.KeyError.$factory("'popitem(): dictionary is empty'")
Sep 5, 2014
1035
}
1036
Feb 11, 2018
1037
dict.setdefault = function(){
Nov 21, 2015
1038
Mar 7, 2018
1039
var $ = $B.args("setdefault", 3, {self: null, key: null, _default: null},
1040
["self", "key", "_default"], arguments, {_default: $N}, null, null),
1041
self = $.self,
1042
key = $.key,
1043
_default = $._default
1044
try{
1045
// Pass 3rd argument to dict.$getitem to avoid using __missing__
1046
// Cf. issue #1598
1047
return dict.$getitem(self, key, true)
1048
}catch(err){
1049
if(err.__class__ !== _b_.KeyError){
1050
throw err
1051
}
1052
if(_default === undefined){_default = $N}
1053
var hash = key.$hash
1054
key.$hash = undefined
1055
dict.$setitem(self, key, _default, hash)
Sep 5, 2014
1056
return _default
1057
}
1058
}
1059
Feb 11, 2018
1060
dict.update = function(self){
Nov 21, 2015
1061
Mar 7, 2018
1062
var $ = $B.args("update", 1, {"self": null}, ["self"], arguments,
1063
{}, "args", "kw"),
1064
self = $.self,
1065
args = $.args,
1066
kw = $.kw
1067
if(args.length > 0){
1068
var o = args[0]
1070
if(o.$jsobj){
1071
o = jsobj2dict(o.$jsobj)
1072
}
1074
}else if(_b_.hasattr(o, "keys")){
1075
var _keys = _b_.list.$factory($B.$call($B.$getattr(o, "keys"))())
1076
for(var i = 0, len = _keys.length; i < len; i++){
1077
var _value = $B.$getattr(o, "__getitem__")(_keys[i])
1078
dict.$setitem(self, _keys[i], _value)
1079
}
1080
}else{
1081
var it = _b_.iter(o),
1082
i = 0
1083
while(true){
1084
try{
1085
var item = _b_.next(it)
1086
}catch(err){
1087
if(err.__class__ === _b_.StopIteration){break}
1088
throw err
1089
}
1090
try{
1091
key_value = _b_.list.$factory(item)
1092
}catch(err){
1093
throw _b_.TypeError.$factory("cannot convert dictionary" +
1094
" update sequence element #" + i + " to a sequence")
1095
}
1096
if(key_value.length !== 2){
1097
throw _b_.ValueError.$factory("dictionary update " +
1098
"sequence element #" + i + " has length " +
1099
key_value.length + "; 2 is required")
1100
}
1101
dict.$setitem(self, key_value[0], key_value[1])
1102
i++
Sep 5, 2014
1105
}
Sep 5, 2014
1109
}
1110
1111
var dict_values = $B.make_view("dict_values")
1112
dict_values.$iterator = $B.make_iterator_class("dict_valueiterator")
Nov 21, 2015
1113
Feb 11, 2018
1114
dict.values = function(self){
1115
var $ = $B.args('values', 1, {self: null}, ['self'], arguments,
1116
{}, null, null)
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
1191
mappingproxy.__repr__ = function(){
1192
return '<mappingproxy object>'
1193
}
1194
Feb 12, 2018
1195
mappingproxy.__setitem__ = function(){
Mar 7, 2018
1196
throw _b_.TypeError.$factory("'mappingproxy' object does not support " +
1197
"item assignment")
1200
for(var attr in dict){
1201
if(mappingproxy[attr] !== undefined ||
1202
["__class__", "__mro__", "__new__", "__init__", "__delitem__",
1203
"clear", "fromkeys", "pop", "popitem", "setdefault",
1204
"update"].indexOf(attr) > -1){
1205
continue
1206
}
1207
if(typeof dict[attr] == "function"){
1208
mappingproxy[attr] = (function(key){
1209
return function(){
1210
return dict[key].apply(null, arguments)
1211
}
1212
})(attr)
1213
}else{
1214
mappingproxy[attr] = dict[attr]
1215
}
1216
}
1217
Feb 12, 2018
1218
$B.set_func_names(mappingproxy, "builtins")
1220
function jsobj2dict(x, exclude){
1221
exclude = exclude || function(){return false}
1224
if(attr.charAt(0) != "$" && ! exclude(attr)){
1225
if(x[attr] === null){
1226
d.$string_dict[attr] = [_b_.None, d.$order++]
1227
}else if(x[attr] === undefined){
1228
continue
1229
}else if(x[attr].$jsobj === x){
1230
d.$string_dict[attr] = [d, d.$order++]
1232
d.$string_dict[attr] = [$B.$JS2Py(x[attr]), d.$order++]
1234
}
1235
}
1236
return d
1237
}
1239
$B.obj_dict = function(obj, exclude){
1240
var klass = obj.__class__ || $B.get_class(obj)
1241
if(klass !== undefined && klass.$native){
1242
throw $B.attr_error("__dict__", obj)
1243
}
1245
res.$jsobj = obj
1246
res.$exclude = exclude || function(){return false}
1247
return res
1248
}
1249
1250
// Wrapper around a JS object to handle it as a Python dictionary.
1251
// Some keys of the original object can be ignored by passing
1252
// the filtering function exclude().
1253
// Supports adding new keys.
1254
1255
var jsobj_as_pydict = $B.jsobj_as_pydict = $B.make_class('jsobj_as_pydict',
1256
function(jsobj, exclude){
1257
return {
1258
__class__: jsobj_as_pydict,
1259
obj: jsobj,
1260
exclude: exclude ? exclude : function(){return false},
1261
new_keys: []
1262
}
1263
}
1264
)
1265
1266
jsobj_as_pydict.__contains__ = function(self, key){
1267
if(self.new_keys.indexOf(key) > -1){
1268
return true
1269
}
1270
return ! (self.exclude(key) || self.obj[key] === undefined)
1271
}
1272
1273
jsobj_as_pydict.__delitem__ = function(self, key){
1274
jsobj_as_pydict.__getitem__(self, key) // raises KeyError if not present
1275
delete self.obj[key]
1276
var ix = self.new_keys.indexOf(key)
1277
if(ix > -1){
1278
self.new_keys.splice(ix, 1)
1279
}
1280
}
1281
1282
jsobj_as_pydict.__eq__ = function(self, other){
1283
if(other.__class__ !== jsobj_as_pydict){
1284
return _b_.NotImplemented
1285
}
1286
// create true Python dicts with the items in self and other
1287
var self1 = $B.empty_dict()
1288
other1 = $B.empty_dict()
1289
1290
dict.__init__(self1, jsobj_as_pydict.items(self))
1291
dict.__init__(other1, jsobj_as_pydict.items(other))
1292
1293
// Compare true Python dicts
1294
return dict.__eq__(self1, other1)
1295
}
1296
1297
jsobj_as_pydict.__getitem__ = function(self, key){
1298
if(jsobj_as_pydict.__contains__(self, key)){
1299
return self.obj[key]
1300
}
1301
throw _b_.KeyError.$factory(key)
1302
}
1303
1304
jsobj_as_pydict.__iter__ = function(self){
1305
return _b_.iter(jsobj_as_pydict.keys(self))
1306
}
1307
1308
jsobj_as_pydict.__len__ = function(self){
1309
var len = 0
1310
for(var key in self.obj){
1311
if(! self.exclude(key)){
1312
len++
1313
}
1314
}
1315
return len + self.new_keys.length
1316
}
1317
1318
jsobj_as_pydict.__repr__ = function(self){
1319
if($B.repr.enter(self)){
1320
return "{...}"
1321
}
1322
var res = [],
1323
items = _b_.list.$factory(jsobj_as_pydict.items(self))
1324
for(var item of items){
1325
res.push(_b_.repr(item[0]) + ": " + _b_.repr(item[1]))
1326
}
1327
$B.repr.leave(self)
1328
return "{" + res.join(", ") + "}"
1329
}
1330
1331
jsobj_as_pydict.__setitem__ = function(self, key, value){
1332
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1333
self.new_keys.push(key)
1334
}
1335
self.obj[key] = value
1336
}
1337
1338
jsobj_as_pydict.get = function(self, key, _default){
1339
_default = _default === undefined ? _b_.None : _default
1340
if(self.exclude(key) || self.obj[key] === undefined){
1341
return _default
1342
}
1343
return self.obj[key]
1344
}
1345
1346
jsobj_as_pydict.items = function(self){
1347
var items = []
1348
for(var key in self.obj){
1349
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1350
continue
1351
}
1352
items.push($B.fast_tuple([key, self.obj[key]]))
1353
}
1354
var set_like = true
1355
// Check if all values are hashable
1356
for(var item of items){
1357
try{
1358
_b_.hash(item[1])
1359
}catch(err){
1360
set_like = false
1361
break
1362
}
1364
var it = dict_items.$factory(self, items, set_like)
1365
it.dict_version = self.$version
1366
return it
1367
}
1368
1369
jsobj_as_pydict.keys = function(self){
1370
var lst = []
1371
for(var key in self.obj){
1372
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1373
continue
1374
}
1375
lst.push(key)
1376
}
1377
var it = dict_keys.$factory(self, lst, true)
1378
it.dict_version = self.$version
1379
return it
1380
}
1381
1382
jsobj_as_pydict.values = function(self){
1383
var values = []
1384
for(var key in self.obj){
1385
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1386
continue
1387
}
1388
values.push(self.obj[key])
1390
var it = dict_values.$factory(self, values, false)
1391
it.dict_version = self.$version
1392
return it
1393
}
1394
1395
$B.set_func_names(jsobj_as_pydict, 'builtins')
1396
Sep 5, 2014
1397
})(__BRYTHON__)