TranscryptOrg / Transcrypt

Python 3.9 to JavaScript compiler - Lean, fast, open!
https://www.transcrypt.org
Apache License 2.0
2.82k stars 215 forks source link

Transcrypt's future module model will likely become entirely and exclusively based upon the JS6 module model. #498

Open JdeH opened 6 years ago

JdeH commented 6 years ago

Starting with JS 6 JavaScript has a decent module model (it's about time...).

In reaction to some issues I've been looking into using this to somehow implement Python modules. My conclusion is that it's feasible to merge the two.

As an example I've taken the following application from the current TS distro:

https://github.com/QQuick/Transcrypt/tree/master/transcrypt/development/manual_tests/units/animals

and manually converted the generated code to the code below. By using JS' native module mechanism it lacks a lot of overhead and complexity. Each Python/Transcrypt module translates to exactly one JS module. Modules aren't merged, there's no separate unit system needed. Modules can loaded separately and dynamically. The runtime is needed only once per page. Versioning of the runtime is simple. I believe this is the way to go.

Apart from simplicity and compactness it will lead to a completely seamless blending of the Transcrypt/Python and the JS world. TS modules will be first class citizens in the JS world and vice versa.

So in the future TS apps won't be monoliths anymore. They will be built up just like Python apps, from modules. To keep things simple (the main benefit of Python over JS) this mechanism, if it all works out as planned, will supersede monolithic Trancrypt apps as well as unit'ized apps. Some minor incompatibilities may result but they should be easily resolved. Note that the internals of compiled TS files will change, they will be simpler.

Also the sourcemap mechanism will need to be adapted. If that proves a problem, generating monoliths may still be allowed for debugging purposes. Currently the JS community hasn't laid an egg on module sourcemaps a.f.i.k.

This is not a very shortterm thing. Development on TS as is goes on. But at some point this transition very probably will be made. It should have minimal consequences for user code, as long as it doesn't depend upon TS' internal file structure. The .mod.js files will be more important, they will indeed by JS modules. And of course current and older versions of Transcrypt are planned to remain available for download.

To minimize disruption for developers, it may be a good idea to have this transition coincide with the transition to Python 3.7. Also that may be the right time to say goodbye to es5 mode (no problem in older browsers, since Google Closure already provides polyfills).

Some special attention will have to be paid to not creating a JS version of MS' wellknown DLL Hell. Sharing modules can create very hard versioning problems. This is something to be taken into account from the start. One solution would be to allow generation of an application container. An application container is a separate entity with all needed versions of all recursively imported libraries packed together. Packing may be denoted by using separate subdirs or by using unique prefixes.

Another point of attention is the fact the same import in different applications may refer to different modules (that are local to the app and happen to have the same name). This problem can probably best be solved in combination with the versioning problem.

animals.html

<html>
    <head>
        <script type="module">
            import * as animals from "./__javascript__/animals.mod.js"; window.animals = animals;
            import * as cats from "./__javascript__/cats.mod.js"; window.cats = cats;
            import * as dogs from "./__javascript__/dogs.mod.js"; window.dogs = dogs;
       </script>
        <style>button {width:200px;}</style>
    </head>
    <body>  
        <div id = "Felix">...</div>
        <button onclick="cats.Cat ('Felix');">Create cat Felix</button><br/>
        <button onclick="animals.find ('Felix') .feed ();">Feed cat Felix</button><br/>
        <button onclick="animals.find ('Felix') .greet ();">Greet cat Felix</button><br/>
        <br/>

        <div id = "Tiger">...</div>
        <button onclick="cats.Cat ('Tiger');">Create cat Tiger</button><br>
        <button onclick="animals.find ('Tiger') .feed ();">Feed cat Tiger</button><br/>
        <button onclick="animals.find ('Tiger') .greet ();">Greet cat Tiger</button><br/>
        <br/>

        <div id = "Pluto">...</div>
        <button onclick="dogs.Dog ('Pluto');">Create dog Pluto</button><br>
        <button onclick="animals.find ('Pluto') .feed ();">Feed dog Pluto</button><br/>
        <button onclick="animals.find ('Pluto') .greet ();">Greet dog Pluto</button><br/>
    </body>
</html>

animals.mod.js

"use strict";
// Transcrypt'ed from Python, 2018-03-09 13:41:41

import {__class__, __get__, __pragma__, dict, object, __super__} from './__transcrypt_runtime_3_6_101__.mod.js';
import * as asm from './animals_submodule.mod.js';

export var __name__ = 'animals';
console.log (__name__);

export var _individuals = dict ({});

export var find = function (py_name) {
    return _individuals [py_name];
};

export var Animal = __class__ ('Animal', [object], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, py_name, food, sound) {
        _individuals [py_name] = self;
        self.py_name = py_name;
        self.food = food;
        self.sound = sound;
        self.fed = false;
        document.getElementById (self.py_name).innerHTML = self.speak ('I was born just now! My kingdom is: {}. My species is {}'.format (asm.getTaxoTag (), self.species));
    });},
    get speak () {return __get__ (this, function (self, text) {
        return '{} says: '.format (self.py_name) + text;
    });},
    get feed () {return __get__ (this, function (self) {
        document.getElementById (self.py_name).innerHTML = self.speak ((self.fed ? 'No thanks, I first want to greet you with {}!'.format (self.sound) : 'Thanks a lot, I am now eating {}!'.format (self.food)));
        self.fed = true;
    });},
    get greet () {return __get__ (this, function (self) {
        document.getElementById (self.py_name).innerHTML = self.speak ((self.fed ? '{}, {}, {}!'.format (self.sound, self.sound, self.sound) : 'Sorry, I want to eat {} first!'.format (self.food)));
        self.fed = false;
    });}
});

cats.mod.js

"use strict";
// Transcrypt'ed from Python, 2018-03-09 13:41:41

import {__class__, __get__, __pragma__, dict, object, __super__} from './__transcrypt_runtime_3_6_101__.mod.js';
import {Animal} from './animals.mod.js';
import * as csm from './cats_submodule.mod.js';

export var __name__ = 'cats';
console.log (__name__);

export var Cat = __class__ ('Cat', [Animal], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, py_name) {
        self.species = csm.getTaxoTag ();
        __super__ (Cat, '__init__') (self, py_name, 'fish', 'mraaaw');
    });}
});

dogs.mod.js

"use strict";
// Transcrypt'ed from Python, 2018-03-09 13:41:41

import {__class__, __get__, __pragma__, dict, object, __super__} from './__transcrypt_runtime_3_6_101__.mod.js';
import {Animal} from './animals.mod.js';
import * as dsm from './dogs_submodule.mod.js';

export var __name__ = 'dogs';
console.log (__name__);

export var Dog = __class__ ('Dog', [Animal], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, py_name) {
        self.species = dsm.getTaxoTag ();
        __super__ (Dog, '__init__') (self, py_name, 'meat', 'wooof');
    });}
});

animals_submodule.mod.js

"use strict";
// Transcrypt'ed from Python, 2018-03-09 13:41:41

import {__class__, __get__, __pragma__, dict, object, __super__} from './__transcrypt_runtime_3_6_101__.mod.js';

export var __name__ = 'animals_submodule';
console.log (__name__);

export function getTaxoTag () {
    return 'animal';
};

cats_submodule.mod.js

"use strict";
// Transcrypt'ed from Python, 2018-03-09 13:41:41

import {__class__, __get__, __pragma__, dict, object, __super__} from './__transcrypt_runtime_3_6_101__.mod.js';

export var __name__ = 'cats_submodule';
console.log (__name__);

export function getTaxoTag() {
    return 'cat';
};

dogs_submodule.mod.js

"use strict";
// Transcrypt'ed from Python, 2018-03-09 13:41:41

import {__class__, __get__, __pragma__, dict, object, __super__} from './__transcrypt_runtime_3_6_101__.mod.js';

export var __name__ = 'dogs_submodule';    
console.log (__name__);

export function getTaxoTag () {
    return 'dog';
};

__transcrypt___runtime_3.6.101)).mod.js

"use strict";
// Transcrypt'ed from Python, 2018-03-09 13:41:41

var __name__ = '__rt__'

export var __symbols__ = ['./__runit__', '__py3.6__', '__esv5__'];
export var __nest__ = function (headObject, tailNames, value) {
    var current = headObject;
    if (tailNames != '') {
        var tailChain = tailNames.split ('.');
        var firstNewIndex = tailChain.length;
        for (var index = 0; index < tailChain.length; index++) {
            if (!current.hasOwnProperty (tailChain [index])) {
                firstNewIndex = index;
                break;
            }
            current = current [tailChain [index]];
        }
        for (var index = firstNewIndex; index < tailChain.length; index++) {
            current [tailChain [index]] = {};
            current = current [tailChain [index]];
        }
    }
    for (var attrib in value) {
        current [attrib] = value [attrib];
    }
};
export function init (module) {
    if (!module.__inited__) {
        module.__all__.__init__ (module.__all__);
        module.__inited__ = true;
    }
    return module.__all__;
};
export function __get__ (self, func, quotedFuncName) {
    if (self) {
        if (self.hasOwnProperty ('__class__') || typeof self == 'string' || self instanceof String) {
            if (quotedFuncName) {
                Object.defineProperty (self, quotedFuncName, {
                    value: function () {
                        var args = [] .slice.apply (arguments);
                        return func.apply (null, [self] .concat (args));
                    },
                    writable: true,
                    enumerable: true,
                    configurable: true
                });
            }
            return function () {
                var args = [] .slice.apply (arguments);
                return func.apply (null, [self] .concat (args));
            };
        }
        else {
            return func;
        }
    }
    else {
        return func;
    }
}
export function __getcm__ (self, func, quotedFuncName) {
    if (self.hasOwnProperty ('__class__')) {
        return function () {
            var args = [] .slice.apply (arguments);
            return func.apply (null, [self.__class__] .concat (args));
        };
    }
    else {
        return function () {
            var args = [] .slice.apply (arguments);
            return func.apply (null, [self] .concat (args));
        };
    }
}
export function __getsm__ (self, func, quotedFuncName) {
    return func;
}
export var py_metatype = {
    __name__: 'type',
    __bases__: [],
    __new__: function (meta, name, bases, attribs) {
        var cls = function () {
            var args = [] .slice.apply (arguments);
            return cls.__new__ (args);
        };
        for (var index = bases.length - 1; index >= 0; index--) {
            var base = bases [index];
            for (var attrib in base) {
                var descrip = Object.getOwnPropertyDescriptor (base, attrib);
                Object.defineProperty (cls, attrib, descrip);
            }
        }
        cls.__metaclass__ = meta;
        cls.__name__ = name.startsWith ('py_') ? name.slice (3) : name;
        cls.__bases__ = bases;
        for (var attrib in attribs) {
            var descrip = Object.getOwnPropertyDescriptor (attribs, attrib);
            Object.defineProperty (cls, attrib, descrip);
        }
        return cls;
    }
};
py_metatype.__metaclass__ = py_metatype;
export var object = {
    __init__: function (self) {},
    __metaclass__: py_metatype,
    __name__: 'object',
    __bases__: [],
    __new__: function (args) {
        var instance = Object.create (this, {__class__: {value: this, enumerable: true}});
        this.__init__.apply (null, [instance] .concat (args));
        return instance;
    }
};
export function __class__ (name, bases, attribs, meta) {
    if (meta === undefined) {
        meta = bases [0] .__metaclass__;
    }
    return meta.__new__ (meta, name, bases, attribs);
}
export function __pragma__ () {};
// __base__
export var __Envir__ = __class__ ('__Envir__', [object], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self) {
        self.interpreter_name = 'python';
        self.transpiler_name = 'transcrypt';
        self.transpiler_version = '3.6.101';
        self.target_subdir = '__javascript__';
    });}
});
export var __envir__ = __Envir__ ();
// end __base__
// __standard__
export var Exception = __class__ ('Exception', [object], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self) {
        var kwargs = dict ();
        if (arguments.length) {
            var __ilastarg0__ = arguments.length - 1;
            if (arguments [__ilastarg0__] && arguments [__ilastarg0__].hasOwnProperty ("__kwargtrans__")) {
                var __allkwargs0__ = arguments [__ilastarg0__--];
                for (var __attrib0__ in __allkwargs0__) {
                    switch (__attrib0__) {
                        case 'self': var self = __allkwargs0__ [__attrib0__]; break;
                        default: kwargs [__attrib0__] = __allkwargs0__ [__attrib0__];
                    }
                }
                delete kwargs.__kwargtrans__;
            }
            var args = tuple ([].slice.apply (arguments).slice (1, __ilastarg0__ + 1));
        }
        else {
            var args = tuple ();
        }
        self.__args__ = args;
        try {
            self.stack = kwargs.error.stack;
        }
        catch (__except0__) {
            self.stack = 'No stack trace available';
        }
    });},
    get __repr__ () {return __get__ (this, function (self) {
        if (len (self.__args__)) {
            return '{}{}'.format (self.__class__.__name__, repr (tuple (self.__args__)));
        }
        else {
            return '{}()'.format (self.__class__.__name__);
        }
    });},
    get __str__ () {return __get__ (this, function (self) {
        if (len (self.__args__) > 1) {
            return str (tuple (self.__args__));
        }
        else if (len (self.__args__)) {
            return str (self.__args__ [0]);
        }
        else {
            return '';
        }
    });}
});
export var IterableError = __class__ ('IterableError', [Exception], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, error) {
        Exception.__init__ (self, "Can't iterate over non-iterable", __kwargtrans__ ({error: error}));
    });}
});
export var StopIteration = __class__ ('StopIteration', [Exception], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, error) {
        Exception.__init__ (self, 'Iterator exhausted', __kwargtrans__ ({error: error}));
    });}
});
export var ValueError = __class__ ('ValueError', [Exception], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, message, error) {
        Exception.__init__ (self, message, __kwargtrans__ ({error: error}));
    });}
});
export var KeyError = __class__ ('KeyError', [Exception], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, message, error) {
        Exception.__init__ (self, message, __kwargtrans__ ({error: error}));
    });}
});
export var AssertionError = __class__ ('AssertionError', [Exception], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, message, error) {
        if (message) {
            Exception.__init__ (self, message, __kwargtrans__ ({error: error}));
        }
        else {
            Exception.__init__ (self, __kwargtrans__ ({error: error}));
        }
    });}
});
export var NotImplementedError = __class__ ('NotImplementedError', [Exception], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, message, error) {
        Exception.__init__ (self, message, __kwargtrans__ ({error: error}));
    });}
});
export var IndexError = __class__ ('IndexError', [Exception], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, message, error) {
        Exception.__init__ (self, message, __kwargtrans__ ({error: error}));
    });}
});
export var AttributeError = __class__ ('AttributeError', [Exception], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, message, error) {
        Exception.__init__ (self, message, __kwargtrans__ ({error: error}));
    });}
});
export var py_TypeError = __class__ ('py_TypeError', [Exception], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self, message, error) {
        Exception.__init__ (self, message, __kwargtrans__ ({error: error}));
    });}
});
export var Warning = __class__ ('Warning', [Exception], {
    __module__: __name__,
});
export var UserWarning = __class__ ('UserWarning', [Warning], {
    __module__: __name__,
});
export var DeprecationWarning = __class__ ('DeprecationWarning', [Warning], {
    __module__: __name__,
});
export var RuntimeWarning = __class__ ('RuntimeWarning', [Warning], {
    __module__: __name__,
});
export var __sort__ = function (iterable, key, reverse) {
    if (typeof key == 'undefined' || (key != null && key .hasOwnProperty ("__kwargtrans__"))) {;
        var key = null;
    };
    if (typeof reverse == 'undefined' || (reverse != null && reverse .hasOwnProperty ("__kwargtrans__"))) {;
        var reverse = false;
    };
    if (arguments.length) {
        var __ilastarg0__ = arguments.length - 1;
        if (arguments [__ilastarg0__] && arguments [__ilastarg0__].hasOwnProperty ("__kwargtrans__")) {
            var __allkwargs0__ = arguments [__ilastarg0__--];
            for (var __attrib0__ in __allkwargs0__) {
                switch (__attrib0__) {
                    case 'iterable': var iterable = __allkwargs0__ [__attrib0__]; break;
                    case 'key': var key = __allkwargs0__ [__attrib0__]; break;
                    case 'reverse': var reverse = __allkwargs0__ [__attrib0__]; break;
                }
            }
        }
    }
    else {
    }
    if (key) {
        iterable.sort ((function __lambda__ (a, b) {
            if (arguments.length) {
                var __ilastarg0__ = arguments.length - 1;
                if (arguments [__ilastarg0__] && arguments [__ilastarg0__].hasOwnProperty ("__kwargtrans__")) {
                    var __allkwargs0__ = arguments [__ilastarg0__--];
                    for (var __attrib0__ in __allkwargs0__) {
                        switch (__attrib0__) {
                            case 'a': var a = __allkwargs0__ [__attrib0__]; break;
                            case 'b': var b = __allkwargs0__ [__attrib0__]; break;
                        }
                    }
                }
            }
            else {
            }
            return (key (a) > key (b) ? 1 : -(1));
        }));
    }
    else {
        iterable.sort ();
    }
    if (reverse) {
        iterable.reverse ();
    }
};
export var sorted = function (iterable, key, reverse) {
    if (typeof key == 'undefined' || (key != null && key .hasOwnProperty ("__kwargtrans__"))) {;
        var key = null;
    };
    if (typeof reverse == 'undefined' || (reverse != null && reverse .hasOwnProperty ("__kwargtrans__"))) {;
        var reverse = false;
    };
    if (arguments.length) {
        var __ilastarg0__ = arguments.length - 1;
        if (arguments [__ilastarg0__] && arguments [__ilastarg0__].hasOwnProperty ("__kwargtrans__")) {
            var __allkwargs0__ = arguments [__ilastarg0__--];
            for (var __attrib0__ in __allkwargs0__) {
                switch (__attrib0__) {
                    case 'iterable': var iterable = __allkwargs0__ [__attrib0__]; break;
                    case 'key': var key = __allkwargs0__ [__attrib0__]; break;
                    case 'reverse': var reverse = __allkwargs0__ [__attrib0__]; break;
                }
            }
        }
    }
    else {
    }
    if (py_typeof (iterable) == dict) {
        var result = copy (iterable.py_keys ());
    }
    else {
        var result = copy (iterable);
    }
    __sort__ (result, key, reverse);
    return result;
};
export var map = function (func, iterable) {
    return (function () {
        var __accu0__ = [];
        var __iterable0__ = iterable;
        for (var __index0__ = 0; __index0__ < len (__iterable0__); __index0__++) {
            var item = __iterable0__ [__index0__];
            __accu0__.append (func (item));
        }
        return __accu0__;
    }) ();
};
export var filter = function (func, iterable) {
    if (func == null) {
        var func = bool;
    }
    return (function () {
        var __accu0__ = [];
        var __iterable0__ = iterable;
        for (var __index0__ = 0; __index0__ < len (__iterable0__); __index0__++) {
            var item = __iterable0__ [__index0__];
            if (func (item)) {
                __accu0__.append (item);
            }
        }
        return __accu0__;
    }) ();
};
export var __Terminal__ = __class__ ('__Terminal__', [object], {
    __module__: __name__,
    get __init__ () {return __get__ (this, function (self) {
        self.buffer = '';
        try {
            self.element = document.getElementById ('__terminal__');
        }
        catch (__except0__) {
            self.element = null;
        }
        if (self.element) {
            self.element.style.overflowX = 'auto';
            self.element.style.boxSizing = 'border-box';
            self.element.style.padding = '5px';
            self.element.innerHTML = '_';
        }
    });},
    get print () {return __get__ (this, function (self) {
        var sep = ' ';
        var end = '\n';
        if (arguments.length) {
            var __ilastarg0__ = arguments.length - 1;
            if (arguments [__ilastarg0__] && arguments [__ilastarg0__].hasOwnProperty ("__kwargtrans__")) {
                var __allkwargs0__ = arguments [__ilastarg0__--];
                for (var __attrib0__ in __allkwargs0__) {
                    switch (__attrib0__) {
                        case 'self': var self = __allkwargs0__ [__attrib0__]; break;
                        case 'sep': var sep = __allkwargs0__ [__attrib0__]; break;
                        case 'end': var end = __allkwargs0__ [__attrib0__]; break;
                    }
                }
            }
            var args = tuple ([].slice.apply (arguments).slice (1, __ilastarg0__ + 1));
        }
        else {
            var args = tuple ();
        }
        self.buffer = '{}{}{}'.format (self.buffer, sep.join ((function () {
            var __accu0__ = [];
            var __iterable0__ = args;
            for (var __index0__ = 0; __index0__ < len (__iterable0__); __index0__++) {
                var arg = __iterable0__ [__index0__];
                __accu0__.append (str (arg));
            }
            return __accu0__;
        }) ()), end).__getslice__ (-(4096), null, 1);
        if (self.element) {
            self.element.innerHTML = self.buffer.py_replace ('\n', '<br>').py_replace (' ', '&nbsp');
            self.element.scrollTop = self.element.scrollHeight;
        }
        else {
            console.log (sep.join ((function () {
                var __accu0__ = [];
                var __iterable0__ = args;
                for (var __index0__ = 0; __index0__ < len (__iterable0__); __index0__++) {
                    var arg = __iterable0__ [__index0__];
                    __accu0__.append (str (arg));
                }
                return __accu0__;
            }) ()));
        }
    });},
    get input () {return __get__ (this, function (self, question) {
        if (arguments.length) {
            var __ilastarg0__ = arguments.length - 1;
            if (arguments [__ilastarg0__] && arguments [__ilastarg0__].hasOwnProperty ("__kwargtrans__")) {
                var __allkwargs0__ = arguments [__ilastarg0__--];
                for (var __attrib0__ in __allkwargs0__) {
                    switch (__attrib0__) {
                        case 'self': var self = __allkwargs0__ [__attrib0__]; break;
                        case 'question': var question = __allkwargs0__ [__attrib0__]; break;
                    }
                }
            }
        }
        else {
        }
        self.print ('{}'.format (question), __kwargtrans__ ({end: ''}));
        var answer = window.prompt ('\n'.join (self.buffer.py_split ('\n').__getslice__ (-(16), null, 1)));
        self.print (answer);
        return answer;
    });}
});
// end __standard__
export function __call__ (/* <callee>, <this>, <params>* */) {
    var args = [] .slice.apply (arguments);
    if (typeof args [0] == 'object' && '__call__' in args [0]) {
        return args [0] .__call__ .apply (args [1], args.slice (2));
    }
    else {
        return args [0] .apply (args [1], args.slice (2));
    }
};
__envir__.executor_name = __envir__.transpiler_name;
export var __main__ = {__file__: ''};
export var __except__ = null;
export function __kwargtrans__ (anObject) {
    anObject.__kwargtrans__ = null;
    anObject.constructor = Object;
    return anObject;
};
export function __globals__ (anObject) {
    if (isinstance (anObject, dict)) {
        return anObject;
    }
    else {
        return dict (anObject)
    }
};
export function __super__ (aClass, methodName) {
    for (var index = 0; index < aClass.__bases__.length; index++) {
        var base = aClass.__bases__ [index];
        if (methodName in base) {
           return base [methodName];
        }
    }
    throw new Exception ('Superclass method not found');
};
export function property (getter, setter) {
    if (!setter) {
        setter = function () {};
    }
    return {get: function () {return getter (this)}, set: function (value) {setter (this, value)}, enumerable: true};
};
export function __setProperty__ (anObject, name, descriptor) {
    if (!anObject.hasOwnProperty (name)) {
        Object.defineProperty (anObject, name, descriptor);
    }
};
export function assert (condition, message) {
    if (!condition) {
        throw AssertionError (message, new Error ());
    }
};
export function __merge__ (object0, object1) {
    var result = {};
    for (var attrib in object0) {
        result [attrib] = object0 [attrib];
    }
    for (var attrib in object1) {
        result [attrib] = object1 [attrib];
    }
    return result;
};
export function dir (obj) {
    var aList = [];
    for (var aKey in obj) {
        aList.push (aKey.startsWith ('py_') ? aKey.slice (3) : aKey);
    }
    aList.sort ();
    return aList;
};
export function setattr (obj, name, value) {
    obj [name] = value;
};
export function getattr (obj, name) {
    return name in obj ? obj [name] : obj ['py_' + name];
};
export function hasattr (obj, name) {
    try {
        return name in obj || 'py_' + name in obj;
    }
    catch (exception) {
        return false;
    }
};
export function delattr (obj, name) {
    if (name in obj) {
        delete obj [name];
    }
    else {
        delete obj ['py_' + name];
    }
};
export function __in__ (element, container) {
    if (container === undefined || container === null) {
        return false;
    }
    if (container.__contains__ instanceof Function) {
        return container.__contains__ (element);
    }
    else {
        return (
            container.indexOf ?
            container.indexOf (element) > -1 :
            container.hasOwnProperty (element)
        );
    }
};
export function __specialattrib__ (attrib) {
    return (attrib.startswith ('__') && attrib.endswith ('__')) || attrib == 'constructor' || attrib.startswith ('py_');
};
export function len (anObject) {
    if (anObject === undefined || anObject === null) {
        return 0;
    }
    if (anObject.__len__ instanceof Function) {
        return anObject.__len__ ();
    }
    if (anObject.length !== undefined) {
        return anObject.length;
    }
    var length = 0;
    for (var attr in anObject) {
        if (!__specialattrib__ (attr)) {
            length++;
        }
    }
    return length;
};
export function __i__ (any) {
    return py_typeof (any) == dict ? any.py_keys () : any;
}
export function __k__ (keyed, key) {
    var result = keyed [key];
    if (typeof result == 'undefined') {
        if (keyed instanceof Array)
            if (key == +key && key >= 0 && keyed.length > key)
                return result;
            else
                throw IndexError (key, new Error());
        else
            throw KeyError (key, new Error());
    }
    return result;
}
export function __t__ (target) {
    return (
        target === undefined || target === null ? false :
        ['boolean', 'number'] .indexOf (typeof target) >= 0 ? target :
        target.__bool__ instanceof Function ? (target.__bool__ () ? target : false) :
        target.__len__ instanceof Function ?  (target.__len__ () !== 0 ? target : false) :
        target instanceof Function ? target :
        len (target) !== 0 ? target :
        false
    );
}
export function float (any) {
    if (any == 'inf') {
        return Infinity;
    }
    else if (any == '-inf') {
        return -Infinity;
    }
    else if (any == 'nan') {
        return NaN;
    }
    else if (isNaN (parseFloat (any))) {
        if (any === false) {
            return 0;
        }
        else if (any === true) {
            return 1;
        }
        else {
            throw ValueError ("could not convert string to float: '" + str(any) + "'", new Error ());
        }
    }
    else {
        return +any;
    }
};
float.__name__ = 'float';
float.__bases__ = [object];
export function int (any) {
    return float (any) | 0
};
int.__name__ = 'int';
int.__bases__ = [object];
export function bool (any) {
    return !!__t__ (any);
};
bool.__name__ = 'bool';
bool.__bases__ = [int];
export function py_typeof (anObject) {
    var aType = typeof anObject;
    if (aType == 'object') {
        try {
            return '__class__' in anObject ? anObject.__class__ : object;
        }
        catch (exception) {
            return aType;
        }
    }
    else {
        return (
            aType == 'boolean' ? bool :
            aType == 'string' ? str :
            aType == 'number' ? (anObject % 1 == 0 ? int : float) :
            null
        );
    }
};
export function issubclass (aClass, classinfo) {
    if (classinfo instanceof Array) {
        for (var index = 0; index < classinfo.length; index++) {
            var aClass2 = classinfo [index];
            if (issubclass (aClass, aClass2)) {
                return true;
            }
        }
        return false;
    }
    try {
        var aClass2 = aClass;
        if (aClass2 == classinfo) {
            return true;
        }
        else {
            var bases = [].slice.call (aClass2.__bases__);
            while (bases.length) {
                aClass2 = bases.shift ();
                if (aClass2 == classinfo) {
                    return true;
                }
                if (aClass2.__bases__.length) {
                    bases = [].slice.call (aClass2.__bases__).concat (bases);
                }
            }
            return false;
        }
    }
    catch (exception) {
        return aClass == classinfo || classinfo == object;
    }
};
export function isinstance (anObject, classinfo) {
    try {
        return '__class__' in anObject ? issubclass (anObject.__class__, classinfo) : issubclass (py_typeof (anObject), classinfo);
    }
    catch (exception) {
        return issubclass (py_typeof (anObject), classinfo);
    }
};
export function  callable (anObject) {
    return anObject && typeof anObject == 'object' && '__call__' in anObject ? true : typeof anObject === 'function';
};
export function repr (anObject) {
    try {
        return anObject.__repr__ ();
    }
    catch (exception) {
        try {
            return anObject.__str__ ();
        }
        catch (exception) {
            try {
                if (anObject == null) {
                    return 'None';
                }
                else if (anObject.constructor == Object) {
                    var result = '{';
                    var comma = false;
                    for (var attrib in anObject) {
                        if (!__specialattrib__ (attrib)) {
                            if (attrib.isnumeric ()) {
                                var attribRepr = attrib;
                            }
                            else {
                                var attribRepr = '\'' + attrib + '\'';
                            }
                            if (comma) {
                                result += ', ';
                            }
                            else {
                                comma = true;
                            }
                            result += attribRepr + ': ' + repr (anObject [attrib]);
                        }
                    }
                    result += '}';
                    return result;
                }
                else {
                    return typeof anObject == 'boolean' ? anObject.toString () .capitalize () : anObject.toString ();
                }
            }
            catch (exception) {
                return '<object of type: ' + typeof anObject + '>';
            }
        }
    }
};
export function chr (charCode) {
    return String.fromCharCode (charCode);
};
export function ord (aChar) {
    return aChar.charCodeAt (0);
};
export function max (nrOrSeq) {
    return arguments.length == 1 ? Math.max.apply (null, nrOrSeq) : Math.max.apply (null, arguments);
};
export function min (nrOrSeq) {
    return arguments.length == 1 ? Math.min.apply (null, nrOrSeq) : Math.min.apply (null, arguments);
};
export var abs = Math.abs;
export function round (number, ndigits) {
    if (ndigits) {
        var scale = Math.pow (10, ndigits);
        number *= scale;
    }
    var rounded = Math.round (number);
    if (rounded - number == 0.5 && rounded % 2) {
        rounded -= 1;
    }
    if (ndigits) {
        rounded /= scale;
    }
    return rounded;
};
export function __jsUsePyNext__ () {
    try {
        var result = this.__next__ ();
        return {value: result, done: false};
    }
    catch (exception) {
        return {value: undefined, done: true};
    }
}
export function __pyUseJsNext__ () {
    var result = this.next ();
    if (result.done) {
        throw StopIteration (new Error ());
    }
    else {
        return result.value;
    }
}
export function py_iter (iterable) {
    if (typeof iterable == 'string' || '__iter__' in iterable) {
        var result = iterable.__iter__ ();
        result.next = __jsUsePyNext__;
    }
    else if ('selector' in iterable) {
        var result = list (iterable) .__iter__ ();
        result.next = __jsUsePyNext__;
    }
    else if ('next' in iterable) {
        var result = iterable
        if (! ('__next__' in result)) {
            result.__next__ = __pyUseJsNext__;
        }
    }
    else if (Symbol.iterator in iterable) {
        var result = iterable [Symbol.iterator] ();
        result.__next__ = __pyUseJsNext__;
    }
    else {
        throw IterableError (new Error ());
    }
    result [Symbol.iterator] = function () {return result;};
    return result;
}
export function py_next (iterator) {
    try {
        var result = iterator.__next__ ();
    }
    catch (exception) {
        var result = iterator.next ();
        if (result.done) {
            throw StopIteration (new Error ());
        }
        else {
            return result.value;
        }
    }
    if (result == undefined) {
        throw StopIteration (new Error ());
    }
    else {
        return result;
    }
}
export function __PyIterator__ (iterable) {
    this.iterable = iterable;
    this.index = 0;
}
__PyIterator__.prototype.__next__ = function () {
    if (this.index < this.iterable.length) {
        return this.iterable [this.index++];
    }
    else {
        throw StopIteration (new Error ());
    }
};
export function __JsIterator__ (iterable) {
    this.iterable = iterable;
    this.index = 0;
}
__JsIterator__.prototype.next = function () {
    if (this.index < this.iterable.py_keys.length) {
        return {value: this.index++, done: false};
    }
    else {
        return {value: undefined, done: true};
    }
};
export function py_reversed (iterable) {
    iterable = iterable.slice ();
    iterable.reverse ();
    return iterable;
};
export function zip () {
    var args = [] .slice.call (arguments);
    for (var i = 0; i < args.length; i++) {
        if (typeof args [i] == 'string') {
            args [i] = args [i] .split ('');
        }
        else if (!Array.isArray (args [i])) {
            args [i] = Array.from (args [i]);
        }
    }
    var shortest = args.length == 0 ? [] : args.reduce (
        function (array0, array1) {
            return array0.length < array1.length ? array0 : array1;
        }
    );
    return shortest.map (
        function (current, index) {
            return args.map (
                function (current) {
                    return current [index];
                }
            );
        }
    );
};
export function range (start, stop, step) {
    if (stop == undefined) {
        stop = start;
        start = 0;
    }
    if (step == undefined) {
        step = 1;
    }
    if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
        return [];
    }
    var result = [];
    for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
        result.push(i);
    }
    return result;
};
export function any (iterable) {
    for (var index = 0; index < iterable.length; index++) {
        if (bool (iterable [index])) {
            return true;
        }
    }
    return false;
}
export function all (iterable) {
    for (var index = 0; index < iterable.length; index++) {
        if (! bool (iterable [index])) {
            return false;
        }
    }
    return true;
}
export function sum (iterable) {
    var result = 0;
    for (var index = 0; index < iterable.length; index++) {
        result += iterable [index];
    }
    return result;
}
export function enumerate (iterable) {
    return zip (range (len (iterable)), iterable);
}
export function copy (anObject) {
    if (anObject == null || typeof anObject == "object") {
        return anObject;
    }
    else {
        var result = {};
        for (var attrib in obj) {
            if (anObject.hasOwnProperty (attrib)) {
                result [attrib] = anObject [attrib];
            }
        }
        return result;
    }
}
export function deepcopy (anObject) {
    if (anObject == null || typeof anObject == "object") {
        return anObject;
    }
    else {
        var result = {};
        for (var attrib in obj) {
            if (anObject.hasOwnProperty (attrib)) {
                result [attrib] = deepcopy (anObject [attrib]);
            }
        }
        return result;
    }
}
export function list (iterable) {
    var instance = iterable ? [] .slice.apply (iterable) : [];
    return instance;
}
Array.prototype.__class__ = list;
list.__name__ = 'list';
list.__bases__ = [object];
Array.prototype.__iter__ = function () {return new __PyIterator__ (this);};
Array.prototype.__getslice__ = function (start, stop, step) {
    if (start < 0) {
        start = this.length + start;
    }
    if (stop == null) {
        stop = this.length;
    }
    else if (stop < 0) {
        stop = this.length + stop;
    }
    else if (stop > this.length) {
        stop = this.length;
    }
    var result = list ([]);
    for (var index = start; index < stop; index += step) {
        result.push (this [index]);
    }
    return result;
};
Array.prototype.__setslice__ = function (start, stop, step, source) {
    if (start < 0) {
        start = this.length + start;
    }
    if (stop == null) {
        stop = this.length;
    }
    else if (stop < 0) {
        stop = this.length + stop;
    }
    if (step == null) {
        Array.prototype.splice.apply (this, [start, stop - start] .concat (source));
    }
    else {
        var sourceIndex = 0;
        for (var targetIndex = start; targetIndex < stop; targetIndex += step) {
            this [targetIndex] = source [sourceIndex++];
        }
    }
};
Array.prototype.__repr__ = function () {
    if (this.__class__ == set && !this.length) {
        return 'set()';
    }
    var result = !this.__class__ || this.__class__ == list ? '[' : this.__class__ == tuple ? '(' : '{';
    for (var index = 0; index < this.length; index++) {
        if (index) {
            result += ', ';
        }
        result += repr (this [index]);
    }
    if (this.__class__ == tuple && this.length == 1) {
        result += ',';
    }
    result += !this.__class__ || this.__class__ == list ? ']' : this.__class__ == tuple ? ')' : '}';;
    return result;
};
Array.prototype.__str__ = Array.prototype.__repr__;
Array.prototype.append = function (element) {
    this.push (element);
};
Array.prototype.py_clear = function () {
    this.length = 0;
};
Array.prototype.extend = function (aList) {
    this.push.apply (this, aList);
};
Array.prototype.insert = function (index, element) {
    this.splice (index, 0, element);
};
Array.prototype.remove = function (element) {
    var index = this.indexOf (element);
    if (index == -1) {
        throw ValueError ("list.remove(x): x not in list", new Error ());
    }
    this.splice (index, 1);
};
Array.prototype.index = function (element) {
    return this.indexOf (element);
};
Array.prototype.py_pop = function (index) {
    if (index == undefined) {
        return this.pop ();
    }
    else {
        return this.splice (index, 1) [0];
    }
};
Array.prototype.py_sort = function () {
    __sort__.apply  (null, [this].concat ([] .slice.apply (arguments)));
};
Array.prototype.__add__ = function (aList) {
    return list (this.concat (aList));
};
Array.prototype.__mul__ = function (scalar) {
    var result = this;
    for (var i = 1; i < scalar; i++) {
        result = result.concat (this);
    }
    return result;
};
Array.prototype.__rmul__ = Array.prototype.__mul__;
export function tuple (iterable) {
    var instance = iterable ? [] .slice.apply (iterable) : [];
    instance.__class__ = tuple;
    return instance;
}
tuple.__name__ = 'tuple';
tuple.__bases__ = [object];
export function set (iterable) {
    var instance = [];
    if (iterable) {
        for (var index = 0; index < iterable.length; index++) {
            instance.add (iterable [index]);
        }
    }
    instance.__class__ = set;
    return instance;
}
set.__name__ = 'set';
set.__bases__ = [object];
Array.prototype.__bindexOf__ = function (element) {
    element += '';
    var mindex = 0;
    var maxdex = this.length - 1;
    while (mindex <= maxdex) {
        var index = (mindex + maxdex) / 2 | 0;
        var middle = this [index] + '';
        if (middle < element) {
            mindex = index + 1;
        }
        else if (middle > element) {
            maxdex = index - 1;
        }
        else {
            return index;
        }
    }
    return -1;
};
Array.prototype.add = function (element) {
    if (this.indexOf (element) == -1) {
        this.push (element);
    }
};
Array.prototype.discard = function (element) {
    var index = this.indexOf (element);
    if (index != -1) {
        this.splice (index, 1);
    }
};
Array.prototype.isdisjoint = function (other) {
    this.sort ();
    for (var i = 0; i < other.length; i++) {
        if (this.__bindexOf__ (other [i]) != -1) {
            return false;
        }
    }
    return true;
};
Array.prototype.issuperset = function (other) {
    this.sort ();
    for (var i = 0; i < other.length; i++) {
        if (this.__bindexOf__ (other [i]) == -1) {
            return false;
        }
    }
    return true;
};
Array.prototype.issubset = function (other) {
    return set (other.slice ()) .issuperset (this);
};
Array.prototype.union = function (other) {
    var result = set (this.slice () .sort ());
    for (var i = 0; i < other.length; i++) {
        if (result.__bindexOf__ (other [i]) == -1) {
            result.push (other [i]);
        }
    }
    return result;
};
Array.prototype.intersection = function (other) {
    this.sort ();
    var result = set ();
    for (var i = 0; i < other.length; i++) {
        if (this.__bindexOf__ (other [i]) != -1) {
            result.push (other [i]);
        }
    }
    return result;
};
Array.prototype.difference = function (other) {
    var sother = set (other.slice () .sort ());
    var result = set ();
    for (var i = 0; i < this.length; i++) {
        if (sother.__bindexOf__ (this [i]) == -1) {
            result.push (this [i]);
        }
    }
    return result;
};
Array.prototype.symmetric_difference = function (other) {
    return this.union (other) .difference (this.intersection (other));
};
Array.prototype.py_update = function () {
    var updated = [] .concat.apply (this.slice (), arguments) .sort ();
    this.py_clear ();
    for (var i = 0; i < updated.length; i++) {
        if (updated [i] != updated [i - 1]) {
            this.push (updated [i]);
        }
    }
};
Array.prototype.__eq__ = function (other) {
    if (this.length != other.length) {
        return false;
    }
    if (this.__class__ == set) {
        this.sort ();
        other.sort ();
    }
    for (var i = 0; i < this.length; i++) {
        if (this [i] != other [i]) {
            return false;
        }
    }
    return true;
};
Array.prototype.__ne__ = function (other) {
    return !this.__eq__ (other);
};
Array.prototype.__le__ = function (other) {
    return this.issubset (other);
};
Array.prototype.__ge__ = function (other) {
    return this.issuperset (other);
};
Array.prototype.__lt__ = function (other) {
    return this.issubset (other) && !this.issuperset (other);
};
Array.prototype.__gt__ = function (other) {
    return this.issuperset (other) && !this.issubset (other);
};
export function bytearray (bytable, encoding) {
    if (bytable == undefined) {
        return new Uint8Array (0);
    }
    else {
        var aType = py_typeof (bytable);
        if (aType == int) {
            return new Uint8Array (bytable);
        }
        else if (aType == str) {
            var aBytes = new Uint8Array (len (bytable));
            for (var i = 0; i < len (bytable); i++) {
                aBytes [i] = bytable.charCodeAt (i);
            }
            return aBytes;
        }
        else if (aType == list || aType == tuple) {
            return new Uint8Array (bytable);
        }
        else {
            throw py_TypeError;
        }
    }
}
export var bytes = bytearray;
Uint8Array.prototype.__add__ = function (aBytes) {
    var result = new Uint8Array (this.length + aBytes.length);
    result.set (this);
    result.set (aBytes, this.length);
    return result;
};
Uint8Array.prototype.__mul__ = function (scalar) {
    var result = new Uint8Array (scalar * this.length);
    for (var i = 0; i < scalar; i++) {
        result.set (this, i * this.length);
    }
    return result;
};
Uint8Array.prototype.__rmul__ = Uint8Array.prototype.__mul__;
export function str (stringable) {
    if (typeof stringable === 'number')
        return stringable.toString();
    else {
        try {
            return stringable.__str__ ();
        }
        catch (exception) {
            try {
                return repr (stringable);
            }
            catch (exception) {
                return String (stringable);
            }
        }
    }
};
String.prototype.__class__ = str;
str.__name__ = 'str';
str.__bases__ = [object];
String.prototype.__iter__ = function () {new __PyIterator__ (this);};
String.prototype.__repr__ = function () {
    return (this.indexOf ('\'') == -1 ? '\'' + this + '\'' : '"' + this + '"') .py_replace ('\t', '\\t') .py_replace ('\n', '\\n');
};
String.prototype.__str__ = function () {
    return this;
};
String.prototype.capitalize = function () {
    return this.charAt (0).toUpperCase () + this.slice (1);
};
String.prototype.endswith = function (suffix) {
    if (suffix instanceof Array) {
        for (var i=0;i<suffix.length;i++) {
            if (this.slice (-suffix[i].length) == suffix[i])
                return true;
        }
    } else
        return suffix == '' || this.slice (-suffix.length) == suffix;
    return false;
};
String.prototype.find  = function (sub, start) {
    return this.indexOf (sub, start);
};
String.prototype.__getslice__ = function (start, stop, step) {
    if (start < 0) {
        start = this.length + start;
    }
    if (stop == null) {
        stop = this.length;
    }
    else if (stop < 0) {
        stop = this.length + stop;
    }
    var result = '';
    if (step == 1) {
        result = this.substring (start, stop);
    }
    else {
        for (var index = start; index < stop; index += step) {
            result = result.concat (this.charAt(index));
        }
    }
    return result;
};
__setProperty__ (String.prototype, 'format', {
    get: function () {return __get__ (this, function (self) {
        var args = tuple ([] .slice.apply (arguments).slice (1));
        var autoIndex = 0;
        return self.replace (/\{(\w*)\}/g, function (match, key) {
            if (key == '') {
                key = autoIndex++;
            }
            if (key == +key) {
                return args [key] == undefined ? match : str (args [key]);
            }
            else {
                for (var index = 0; index < args.length; index++) {
                    if (typeof args [index] == 'object' && args [index][key] != undefined) {
                        return str (args [index][key]);
                    }
                }
                return match;
            }
        });
    });},
    enumerable: true
});
String.prototype.isalnum = function () {
    return /^[0-9a-zA-Z]{1,}$/.test(this)
}
String.prototype.isalpha = function () {
    return /^[a-zA-Z]{1,}$/.test(this)
}
String.prototype.isdecimal = function () {
    return /^[0-9]{1,}$/.test(this)
}
String.prototype.isdigit = function () {
    return this.isdecimal()
}
String.prototype.islower = function () {
    return /^[a-z]{1,}$/.test(this)
}
String.prototype.isupper = function () {
    return /^[A-Z]{1,}$/.test(this)
}
String.prototype.isspace = function () {
    return /^[\s]{1,}$/.test(this)
}
String.prototype.isnumeric = function () {
    return !isNaN (parseFloat (this)) && isFinite (this);
};
String.prototype.join = function (strings) {
    return strings.join (this);
};
String.prototype.lower = function () {
    return this.toLowerCase ();
};
String.prototype.py_replace = function (old, aNew, maxreplace) {
    return this.split (old, maxreplace) .join (aNew);
};
String.prototype.lstrip = function () {
    return this.replace (/^\s*/g, '');
};
String.prototype.rfind = function (sub, start) {
    return this.lastIndexOf (sub, start);
};
String.prototype.rsplit = function (sep, maxsplit) {
    if (sep == undefined || sep == null) {
        sep = /\s+/;
        var stripped = this.strip ();
    }
    else {
        var stripped = this;
    }
    if (maxsplit == undefined || maxsplit == -1) {
        return stripped.split (sep);
    }
    else {
        var result = stripped.split (sep);
        if (maxsplit < result.length) {
            var maxrsplit = result.length - maxsplit;
            return [result.slice (0, maxrsplit) .join (sep)] .concat (result.slice (maxrsplit));
        }
        else {
            return result;
        }
    }
};
String.prototype.rstrip = function () {
    return this.replace (/\s*$/g, '');
};
String.prototype.py_split = function (sep, maxsplit) {
    if (sep == undefined || sep == null) {
        sep = /\s+/;
        var stripped = this.strip ();
    }
    else {
        var stripped = this;
    }
    if (maxsplit == undefined || maxsplit == -1) {
        return stripped.split (sep);
    }
    else {
        var result = stripped.split (sep);
        if (maxsplit < result.length) {
            return result.slice (0, maxsplit).concat ([result.slice (maxsplit).join (sep)]);
        }
        else {
            return result;
        }
    }
};
String.prototype.startswith = function (prefix) {
    if (prefix instanceof Array) {
        for (var i=0;i<prefix.length;i++) {
            if (this.indexOf (prefix [i]) == 0)
                return true;
        }
    } else
        return this.indexOf (prefix) == 0;
    return false;
};
String.prototype.strip = function () {
    return this.trim ();
};
String.prototype.upper = function () {
    return this.toUpperCase ();
};
String.prototype.__mul__ = function (scalar) {
    var result = '';
    for (var i = 0; i < scalar; i++) {
        result = result + this;
    }
    return result;
};
String.prototype.__rmul__ = String.prototype.__mul__;
export function __contains__ (element) {
    return this.hasOwnProperty (element);
}
export function __keys__ () {
    var keys = [];
    for (var attrib in this) {
        if (!__specialattrib__ (attrib)) {
            keys.push (attrib);
        }
    }
    return keys;
}
export function __items__ () {
    var items = [];
    for (var attrib in this) {
        if (!__specialattrib__ (attrib)) {
            items.push ([attrib, this [attrib]]);
        }
    }
    return items;
}
export function __del__ (key) {
    delete this [key];
}
export function __clear__ () {
    for (var attrib in this) {
        delete this [attrib];
    }
}
export function __getdefault__ (aKey, aDefault) {
    var result = this [aKey];
    if (result == undefined) {
        result = this ['py_' + aKey]
    }
    return result == undefined ? (aDefault == undefined ? null : aDefault) : result;
}
export function __setdefault__ (aKey, aDefault) {
    var result = this [aKey];
    if (result != undefined) {
        return result;
    }
    var val = aDefault == undefined ? null : aDefault;
    this [aKey] = val;
    return val;
}
export function __pop__ (aKey, aDefault) {
    var result = this [aKey];
    if (result != undefined) {
        delete this [aKey];
        return result;
    } else {
        if ( aDefault === undefined ) {
            throw KeyError (aKey, new Error());
        }
    }
    return aDefault;
}
export function __popitem__ () {
    var aKey = Object.keys (this) [0];
    if (aKey == null) {
        throw KeyError ("popitem(): dictionary is empty", new Error ());
    }
    var result = tuple ([aKey, this [aKey]]);
    delete this [aKey];
    return result;
}
export function __update__ (aDict) {
    for (var aKey in aDict) {
        this [aKey] = aDict [aKey];
    }
}
export function __values__ () {
    var values = [];
    for (var attrib in this) {
        if (!__specialattrib__ (attrib)) {
            values.push (this [attrib]);
        }
    }
    return values;
}
export function __dgetitem__ (aKey) {
    return this [aKey];
}
export function __dsetitem__ (aKey, aValue) {
    this [aKey] = aValue;
}
export function dict (objectOrPairs) {
    var instance = {};
    if (!objectOrPairs || objectOrPairs instanceof Array) {
        if (objectOrPairs) {
            for (var index = 0; index < objectOrPairs.length; index++) {
                var 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];
                if (!(objectOrPairs instanceof Array) && objectOrPairs instanceof Object) {
                     if (!isinstance (objectOrPairs, dict)) {
                         val = dict (val);
                     }
                }
                instance [key] = val;
            }
        }
    }
    else {
        if (isinstance (objectOrPairs, dict)) {
            var aKeys = objectOrPairs.py_keys ();
            for (var index = 0; index < aKeys.length; index++ ) {
                var key = aKeys [index];
                instance [key] = objectOrPairs [key];
            }
        } else if (objectOrPairs instanceof Object) {
            instance = objectOrPairs;
        } else {
            throw ValueError ("Invalid type of object for dict creation", new Error ());
        }
    }
    __setProperty__ (instance, '__class__', {value: dict, enumerable: false, writable: true});
    __setProperty__ (instance, '__contains__', {value: __contains__, enumerable: false});
    __setProperty__ (instance, 'py_keys', {value: __keys__, enumerable: false});
    __setProperty__ (instance, '__iter__', {value: function () {new __PyIterator__ (this.py_keys ());}, enumerable: false});
    __setProperty__ (instance, Symbol.iterator, {value: function () {new __JsIterator__ (this.py_keys ());}, enumerable: false});
    __setProperty__ (instance, 'py_items', {value: __items__, enumerable: false});
    __setProperty__ (instance, 'py_del', {value: __del__, enumerable: false});
    __setProperty__ (instance, 'py_clear', {value: __clear__, enumerable: false});
    __setProperty__ (instance, 'py_get', {value: __getdefault__, enumerable: false});
    __setProperty__ (instance, 'py_setdefault', {value: __setdefault__, enumerable: false});
    __setProperty__ (instance, 'py_pop', {value: __pop__, enumerable: false});
    __setProperty__ (instance, 'py_popitem', {value: __popitem__, enumerable: false});
    __setProperty__ (instance, 'py_update', {value: __update__, enumerable: false});
    __setProperty__ (instance, 'py_values', {value: __values__, enumerable: false});
    __setProperty__ (instance, '__getitem__', {value: __dgetitem__, enumerable: false});
    __setProperty__ (instance, '__setitem__', {value: __dsetitem__, enumerable: false});
    return instance;
}
dict.__name__ = 'dict';
dict.__bases__ = [object];
export function __setdoc__ (docString) {
    this.__doc__ = docString;
    return this;
}
__setProperty__ (Function.prototype, '__setdoc__', {value: __setdoc__, enumerable: false});
export function __jsmod__ (a, b) {
    if (typeof a == 'object' && '__mod__' in a) {
        return a.__mod__ (b);
    }
    else if (typeof b == 'object' && '__rmod__' in b) {
        return b.__rmod__ (a);
    }
    else {
        return a % b;
    }
};
export function __mod__ (a, b) {
    if (typeof a == 'object' && '__mod__' in a) {
        return a.__mod__ (b);
    }
    else if (typeof b == 'object' && '__rmod__' in b) {
        return b.__rmod__ (a);
    }
    else {
        return ((a % b) + b) % b;
    }
};
export function __pow__ (a, b) {
    if (typeof a == 'object' && '__pow__' in a) {
        return a.__pow__ (b);
    }
    else if (typeof b == 'object' && '__rpow__' in b) {
        return b.__rpow__ (a);
    }
    else {
        return Math.pow (a, b);
    }
};
export function __neg__ (a) {
    if (typeof a == 'object' && '__neg__' in a) {
        return a.__neg__ ();
    }
    else {
        return -a;
    }
};
export function __matmul__ (a, b) {
    return a.__matmul__ (b);
};
export function __mul__ (a, b) {
    if (typeof a == 'object' && '__mul__' in a) {
        return a.__mul__ (b);
    }
    else if (typeof b == 'object' && '__rmul__' in b) {
        return b.__rmul__ (a);
    }
    else if (typeof a == 'string') {
        return a.__mul__ (b);
    }
    else if (typeof b == 'string') {
        return b.__rmul__ (a);
    }
    else {
        return a * b;
    }
};
export function __truediv__ (a, b) {
    if (typeof a == 'object' && '__truediv__' in a) {
        return a.__truediv__ (b);
    }
    else if (typeof b == 'object' && '__rtruediv__' in b) {
        return b.__rtruediv__ (a);
    }
    else if (typeof a == 'object' && '__div__' in a) {
        return a.__div__ (b);
    }
    else if (typeof b == 'object' && '__rdiv__' in b) {
        return b.__rdiv__ (a);
    }
    else {
        return a / b;
    }
};
export function __floordiv__ (a, b) {
    if (typeof a == 'object' && '__floordiv__' in a) {
        return a.__floordiv__ (b);
    }
    else if (typeof b == 'object' && '__rfloordiv__' in b) {
        return b.__rfloordiv__ (a);
    }
    else if (typeof a == 'object' && '__div__' in a) {
        return a.__div__ (b);
    }
    else if (typeof b == 'object' && '__rdiv__' in b) {
        return b.__rdiv__ (a);
    }
    else {
        return Math.floor (a / b);
    }
};
export function __add__ (a, b) {
    if (typeof a == 'object' && '__add__' in a) {
        return a.__add__ (b);
    }
    else if (typeof b == 'object' && '__radd__' in b) {
        return b.__radd__ (a);
    }
    else {
        return a + b;
    }
};
export function __sub__ (a, b) {
    if (typeof a == 'object' && '__sub__' in a) {
        return a.__sub__ (b);
    }
    else if (typeof b == 'object' && '__rsub__' in b) {
        return b.__rsub__ (a);
    }
    else {
        return a - b;
    }
};
export function __lshift__ (a, b) {
    if (typeof a == 'object' && '__lshift__' in a) {
        return a.__lshift__ (b);
    }
    else if (typeof b == 'object' && '__rlshift__' in b) {
        return b.__rlshift__ (a);
    }
    else {
        return a << b;
    }
};
export function __rshift__ (a, b) {
    if (typeof a == 'object' && '__rshift__' in a) {
        return a.__rshift__ (b);
    }
    else if (typeof b == 'object' && '__rrshift__' in b) {
        return b.__rrshift__ (a);
    }
    else {
        return a >> b;
    }
};
export function __or__ (a, b) {
    if (typeof a == 'object' && '__or__' in a) {
        return a.__or__ (b);
    }
    else if (typeof b == 'object' && '__ror__' in b) {
        return b.__ror__ (a);
    }
    else {
        return a | b;
    }
};
export function __xor__ (a, b) {
    if (typeof a == 'object' && '__xor__' in a) {
        return a.__xor__ (b);
    }
    else if (typeof b == 'object' && '__rxor__' in b) {
        return b.__rxor__ (a);
    }
    else {
        return a ^ b;
    }
};
export function __and__ (a, b) {
    if (typeof a == 'object' && '__and__' in a) {
        return a.__and__ (b);
    }
    else if (typeof b == 'object' && '__rand__' in b) {
        return b.__rand__ (a);
    }
    else {
        return a & b;
    }
};
export function __eq__ (a, b) {
    if (typeof a == 'object' && '__eq__' in a) {
        return a.__eq__ (b);
    }
    else {
        return a == b;
    }
};
export function __ne__ (a, b) {
    if (typeof a == 'object' && '__ne__' in a) {
        return a.__ne__ (b);
    }
    else {
        return a != b
    }
};
export function __lt__ (a, b) {
    if (typeof a == 'object' && '__lt__' in a) {
        return a.__lt__ (b);
    }
    else {
        return a < b;
    }
};
export function __le__ (a, b) {
    if (typeof a == 'object' && '__le__' in a) {
        return a.__le__ (b);
    }
    else {
        return a <= b;
    }
};
export function __gt__ (a, b) {
    if (typeof a == 'object' && '__gt__' in a) {
        return a.__gt__ (b);
    }
    else {
        return a > b;
    }
};
export function __ge__ (a, b) {
    if (typeof a == 'object' && '__ge__' in a) {
        return a.__ge__ (b);
    }
    else {
        return a >= b;
    }
};
export function __imatmul__ (a, b) {
    if ('__imatmul__' in a) {
        return a.__imatmul__ (b);
    }
    else {
        return a.__matmul__ (b);
    }
};
export function __ipow__ (a, b) {
    if (typeof a == 'object' && '__pow__' in a) {
        return a.__ipow__ (b);
    }
    else if (typeof a == 'object' && '__ipow__' in a) {
        return a.__pow__ (b);
    }
    else if (typeof b == 'object' && '__rpow__' in b) {
        return b.__rpow__ (a);
    }
    else {
        return Math.pow (a, b);
    }
};
export function __ijsmod__ (a, b) {
    if (typeof a == 'object' && '__imod__' in a) {
        return a.__ismod__ (b);
    }
    else if (typeof a == 'object' && '__mod__' in a) {
        return a.__mod__ (b);
    }
    else if (typeof b == 'object' && '__rpow__' in b) {
        return b.__rmod__ (a);
    }
    else {
        return a % b;
    }
};
export function __imod__ (a, b) {
    if (typeof a == 'object' && '__imod__' in a) {
        return a.__imod__ (b);
    }
    else if (typeof a == 'object' && '__mod__' in a) {
        return a.__mod__ (b);
    }
    else if (typeof b == 'object' && '__rmod__' in b) {
        return b.__rmod__ (a);
    }
    else {
        return ((a % b) + b) % b;
    }
};
export function __imul__ (a, b) {
    if (typeof a == 'object' && '__imul__' in a) {
        return a.__imul__ (b);
    }
    else if (typeof a == 'object' && '__mul__' in a) {
        return a = a.__mul__ (b);
    }
    else if (typeof b == 'object' && '__rmul__' in b) {
        return a = b.__rmul__ (a);
    }
    else if (typeof a == 'string') {
        return a = a.__mul__ (b);
    }
    else if (typeof b == 'string') {
        return a = b.__rmul__ (a);
    }
    else {
        return a *= b;
    }
};
export function __idiv__ (a, b) {
    if (typeof a == 'object' && '__idiv__' in a) {
        return a.__idiv__ (b);
    }
    else if (typeof a == 'object' && '__div__' in a) {
        return a = a.__div__ (b);
    }
    else if (typeof b == 'object' && '__rdiv__' in b) {
        return a = b.__rdiv__ (a);
    }
    else {
        return a /= b;
    }
};
export function __iadd__ (a, b) {
    if (typeof a == 'object' && '__iadd__' in a) {
        return a.__iadd__ (b);
    }
    else if (typeof a == 'object' && '__add__' in a) {
        return a = a.__add__ (b);
    }
    else if (typeof b == 'object' && '__radd__' in b) {
        return a = b.__radd__ (a);
    }
    else {
        return a += b;
    }
};
export function __isub__ (a, b) {
    if (typeof a == 'object' && '__isub__' in a) {
        return a.__isub__ (b);
    }
    else if (typeof a == 'object' && '__sub__' in a) {
        return a = a.__sub__ (b);
    }
    else if (typeof b == 'object' && '__rsub__' in b) {
        return a = b.__rsub__ (a);
    }
    else {
        return a -= b;
    }
};
export function __ilshift__ (a, b) {
    if (typeof a == 'object' && '__ilshift__' in a) {
        return a.__ilshift__ (b);
    }
    else if (typeof a == 'object' && '__lshift__' in a) {
        return a = a.__lshift__ (b);
    }
    else if (typeof b == 'object' && '__rlshift__' in b) {
        return a = b.__rlshift__ (a);
    }
    else {
        return a <<= b;
    }
};
export function __irshift__ (a, b) {
    if (typeof a == 'object' && '__irshift__' in a) {
        return a.__irshift__ (b);
    }
    else if (typeof a == 'object' && '__rshift__' in a) {
        return a = a.__rshift__ (b);
    }
    else if (typeof b == 'object' && '__rrshift__' in b) {
        return a = b.__rrshift__ (a);
    }
    else {
        return a >>= b;
    }
};
export function __ior__ (a, b) {
    if (typeof a == 'object' && '__ior__' in a) {
        return a.__ior__ (b);
    }
    else if (typeof a == 'object' && '__or__' in a) {
        return a = a.__or__ (b);
    }
    else if (typeof b == 'object' && '__ror__' in b) {
        return a = b.__ror__ (a);
    }
    else {
        return a |= b;
    }
};
export function __ixor__ (a, b) {
    if (typeof a == 'object' && '__ixor__' in a) {
        return a.__ixor__ (b);
    }
    else if (typeof a == 'object' && '__xor__' in a) {
        return a = a.__xor__ (b);
    }
    else if (typeof b == 'object' && '__rxor__' in b) {
        return a = b.__rxor__ (a);
    }
    else {
        return a ^= b;
    }
};
export function __iand__ (a, b) {
    if (typeof a == 'object' && '__iand__' in a) {
        return a.__iand__ (b);
    }
    else if (typeof a == 'object' && '__and__' in a) {
        return a = a.__and__ (b);
    }
    else if (typeof b == 'object' && '__rand__' in b) {
        return a = b.__rand__ (a);
    }
    else {
        return a &= b;
    }
};
export function __getitem__ (container, key) {
    if (typeof container == 'object' && '__getitem__' in container) {
        return container.__getitem__ (key);
    }
    else if ((typeof container == 'string' || container instanceof Array) && key < 0) {
        return container [container.length + key];
    }
    else {
        return container [key];
    }
};
export function __setitem__ (container, key, value) {
    if (typeof container == 'object' && '__setitem__' in container) {
        container.__setitem__ (key, value);
    }
    else if ((typeof container == 'string' || container instanceof Array) && key < 0) {
        container [container.length + key] = value;
    }
    else {
        container [key] = value;
    }
};
export function __getslice__ (container, lower, upper, step) {
    if (typeof container == 'object' && '__getitem__' in container) {
        return container.__getitem__ ([lower, upper, step]);
    }
    else {
        return container.__getslice__ (lower, upper, step);
    }
};
export function __setslice__ (container, lower, upper, step, value) {
    if (typeof container == 'object' && '__setitem__' in container) {
        container.__setitem__ ([lower, upper, step], value);
    }
    else {
        container.__setslice__ (lower, upper, step, value);
    }
};
BLeAm commented 6 years ago

Very interesting approach. :D

metamarcdw commented 6 years ago

I was literally just trying to set Transcrypt up with React using create-react-app and decided that it was impossible without something like this, or a way to add es6 import/exports to the monolith itself, but outside of any IIFE.

This is very exciting!

doconix commented 6 years ago

This is fantastic. It seems to be the right approach. The universal module definition "standard" is essentially deprecated at this point.

For any projects that need to hit older browsers, it's a very common practice to transpile back to ES5. So I wouldn't worry about losing browser support because transpiling to earlier version and/or polyfills will fix that issue.

metamarcdw commented 6 years ago

If anyone is interested, I eventually did get React working well (although without CRA for now). I have a repo with a POC here: https://github.com/metamarcdw/react-transcrypt

JdeH commented 6 years ago

An update on progress and planning:

Transcrypt 3.7.0 will be the first version having its module mechanism fully based upon ES6 modules. The planning is to release it in the summer, shortly after the release of Python 3.7. If you want to know how it's moving forward, take a look at the modules branch. Note that this is unstable code. Not all commits result in working code, and significant changes may still take place. In general committing is messy in this branch, since currently I am the only one working on it and try to achieve as much development speed as possible.

One other improvement that comes with this, is that it won't require write privilege in the installation directory anymore. Everything generated, including the transpiled runtime, will be written in a subdir __target__ of the project dir.

Another improvement is that the main program can now also be a JavaScript-only module. JavaScript-only modules are taken into account into the minification process, including sourcemaps.

Each Transcrypt application will be compiled to a number of JS modules, at least the main module and the runtime module. Monoliths will not be supported anymore in 3.7, as this would greatly complicate code. It is however possible to package modules into a monolith using: https://rollupjs.org/guide/en .

The latter tool can also used (as a temporary solution) to make node.js applications with modules, as node.js currently doesn't fully support the ES6 modules spec. (it has no named imports and exports). If node.js will continue not supporting this, a more permanent solution will be to generate special purpose import and export code for node.js, but this is considered less desirable. After all, what do we have standards for.

Transcrypt 3.7 will require Python 3.7 or higher, and compile to ES6 or higher, although a postprocessor may be used to make the generated code run on ES5. Note that Transcrypt 3.6 will remain available for (further) development of existing applications.

Kind regards Jacques