Skip to content

Commit

Permalink
Added dict.fromkeys method (issue #779)
Browse files Browse the repository at this point in the history
Updated some __builtin__.js code to ES6 syntax
Added more dict autotests
Added autotests for min/max function exceptions
Updated Autotester.expectException to catch exceptions when running in browser
  • Loading branch information
JennaSys committed Jul 28, 2024
1 parent 32a4e3f commit 3021550
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,17 @@ def run (autoTester):
d5 = d4.copy()
autoTester.check(d5)

autoTester.check(dict.fromkeys(['b', 'c', 'a']))
autoTester.check(dict.fromkeys(['b', 'c', 'a'], '42'))
autoTester.check(dict.fromkeys('bca'))
autoTester.check(d1.fromkeys('bca'))
autoTester.check(d1.fromkeys(['b', 'c', 'a']))
autoTester.check(d1.fromkeys(['b', 'c', 'a'], '42'))
autoTester.check({}.fromkeys(['b', 'c', 'a']))

autoTester.check ("not iterable", autoTester.expectException ( lambda: dict.fromkeys(42) ))
autoTester.check ("missing argument", autoTester.expectException ( lambda: dict.fromkeys() ))

# Check pop of None value (issue 827)
a = {'hello': None}
value = a.pop('hello', '<DEFAULT>')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ def run (autoTester):
max([[5,6,7,8,9],[1,2,3,4]],default=[1,1,1],key=len),
max ([], default='zzz'),
)
# autoTester.check ('max', autoTester.expectException(lambda: max () ))
# autoTester.check ('max', autoTester.expectException(lambda: max (1,2,3,4, default=5) ))
# autoTester.check ('max', autoTester.expectException(lambda: max (default=5)))
# autoTester.check ('max', autoTester.expectException(lambda: max ([])))
# autoTester.check ('max', autoTester.expectException(lambda: max([5,6,7,8,9],[1,2,3,4],default=[1,1,1],key=len) ))
autoTester.check ('max', autoTester.expectException(lambda: max () ))
autoTester.check ('max', autoTester.expectException(lambda: max (1,2,3,4, default=5) ))
autoTester.check ('max', autoTester.expectException(lambda: max (default=5)))
autoTester.check ('max', autoTester.expectException(lambda: max ([])))
autoTester.check ('max', autoTester.expectException(lambda: max([5,6,7,8,9],[1,2,3,4],default=[1,1,1],key=len) ))
# autoTester.check ('max', autoTester.expectException(lambda: max ([4, 5, 'xyz', 'XYZ']) )) # exception not currently implemented

autoTester.check ('abs', abs (-1), abs (1), abs (0), abs (-0.1), abs (0.1))
Expand Down
42 changes: 30 additions & 12 deletions transcrypt/modules/org/transcrypt/__builtin__.js
Original file line number Diff line number Diff line change
Expand Up @@ -1924,12 +1924,28 @@ function __update__ (aDict) {

function __copy__ () {
let dNew = {};
for (var attrib in this) {
for (let attrib in this) {
dNew[attrib] = this[attrib];
}
return dict(dNew);
}

function __fromkeys__ (iterable, defVal) {
if(iterable === undefined){
throw TypeError("fromkeys expected at least 1 argument, got 0")
}
if ( !(['[object Array]', '[object String]'].includes(Object.prototype.toString.call(iterable))) ) {
throw TypeError("object is not iterable", new Error());
}

if(defVal === undefined) defVal = null;
let dNew = {};
for (let idx= 0; idx < iterable.length; idx++) {
dNew[iterable[idx]] = defVal;
}
return dict(dNew);
}

function __values__ () {
var values = [];
for (var attrib in this) {
Expand All @@ -1950,19 +1966,19 @@ function __dsetitem__ (aKey, aValue) {
}

export function dict (objectOrPairs) {
var instance = {};
let instance = {};
if (!objectOrPairs || objectOrPairs instanceof Array) { // It's undefined or an array of pairs
if (objectOrPairs) {
for (var index = 0; index < objectOrPairs.length; index++) {
var pair = objectOrPairs [index];
if ( !(pair instanceof Array) || pair.length != 2) {
for (let index = 0; index < objectOrPairs.length; index++) {
const pair = objectOrPairs [index];
if ( !(pair instanceof Array) || pair.length !== 2) {
throw ValueError(
"dict update sequence element #" + index +
" has length " + pair.length +
"; 2 is required", new Error());
}
var key = pair [0];
var val = pair [1];
const key = pair [0];
let val = pair [1];
if (!(objectOrPairs instanceof Array) && objectOrPairs instanceof Object) {
// User can potentially pass in an object
// that has a hierarchy of objects. This
Expand All @@ -1980,14 +1996,14 @@ export function dict (objectOrPairs) {
}
else {
if (isinstance (objectOrPairs, dict)) {
// Passed object is a dict already so we need to be a little careful
// Passed object is a dict already, so we need to be a little careful
// N.B. - this is a shallow copy per python std - so
// it is assumed that children have already become
// python objects at some point.

var aKeys = objectOrPairs.py_keys ();
for (var index = 0; index < aKeys.length; index++ ) {
var key = aKeys [index];
const aKeys = objectOrPairs.py_keys ();
for (let index = 0; index < aKeys.length; index++ ) {
const key = aKeys [index];
instance [key] = objectOrPairs [key];
}
} else if (objectOrPairs instanceof Object) {
Expand All @@ -2002,7 +2018,7 @@ export function dict (objectOrPairs) {
}
}

// Trancrypt interprets e.g. {aKey: 'aValue'} as a Python dict literal rather than a JavaScript object literal
// Transcrypt interprets e.g. {aKey: 'aValue'} as a Python dict literal rather than a JavaScript object literal
// So dict literals rather than bare Object literals will be passed to JavaScript libraries
// Some JavaScript libraries call all enumerable callable properties of an object that's passed to them
// So the properties of a dict should be non-enumerable
Expand All @@ -2021,13 +2037,15 @@ export function dict (objectOrPairs) {
__setproperty__ (instance, 'py_update', {value: __update__, enumerable: false});
__setproperty__ (instance, 'py_copy', {value: __copy__, enumerable: false});
__setproperty__ (instance, 'py_values', {value: __values__, enumerable: false});
__setproperty__ (instance, 'py_fromkeys', {value: __fromkeys__, enumerable: false});
__setproperty__ (instance, '__getitem__', {value: __dgetitem__, enumerable: false}); // Needed since compound keys necessarily
__setproperty__ (instance, '__setitem__', {value: __dsetitem__, enumerable: false}); // trigger overloading to deal with slices
return instance;
}

dict.__name__ = 'dict';
dict.__bases__ = [object];
dict.py_fromkeys = __fromkeys__

// Docstring setter

Expand Down
4 changes: 3 additions & 1 deletion transcrypt/modules/org/transcrypt/autotester/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,9 @@ def expectException(self, func):
try:
func()
return("no exception")
except Exception as exc:
except Exception:
return("exception")
except object: # required to catch some JS exceptions in the browser
return("exception")

def throwToError(self, func):
Expand Down
5 changes: 3 additions & 2 deletions transcrypt/modules/org/transcrypt/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,9 +577,10 @@ def __init__ (self, module):
('type', 'py_metatype'), ('js_type', 'type'), # Only for the type metaclass, the type operator is dealt with separately in visit_Call
('TypeError', 'py_TypeError'), ('js_TypeError', 'TypeError'),
('update', 'py_update'), ('js_update', 'update'),
('copy', 'py_copy'),
('deepcopy', 'py_deepcopy'),
('copy', 'py_copy'), ('js_copy', 'copy'),
('deepcopy', 'py_deepcopy'), ('js_deepcopy', 'deepcopy'),
('values', 'py_values'), ('js_values', 'values'),
('fromkeys', 'py_fromkeys'),
('reversed', 'py_reversed'), ('js_reversed', 'reversed'),
('setdefault', 'py_setdefault'), ('js_setdefault', 'setdefault'),
('js_super', 'super'),
Expand Down

0 comments on commit 3021550

Please sign in to comment.