1. Lucian Brănescu-Mihăilă
  2. puffin

Source

puffin / objects / src / type.winxed

namespace Python {

function type() {
    var t = new Python.instance;

    t.__class__ = t;

    t.__name__ = 'type';
    t.__module__ = 'builtins';

    t.__new__ = function(cls, name, bases) {
        var o = new Python.instance;

        o.__class__ = cls;
        o.__name__ = name;
        o.__bases__ = bases;

        return o;
    };

    t.__call__ = function(obj) {
        return obj.__class__;
    };

    t.__init__ = function(obj) {};

    t.__hash__ = function(obj) {
        return id(obj);
    };

    t.__repr__ = function(obj) {
        var sb = new 'StringBuilder';
        if(id(obj.__class__) == id(t)) // if object is a 'type'
            if(obj.__module__ == 'builtins')
                sb.append_format("<class '%0'>", obj.__name__);
            else
                sb.append_format("<class '%0.%1'>", obj.__module__, obj.__name__);
        else
            return null; //TypeError
        
        return string(sb);
    };
 
    t.__str__ = t.__repr__;

    t.__getattribute__ = function(obj, key) {
        cry(string(key));

        var cls = obj.__dict__['__class__'];
        var chain = get_mro(cls);
        
        // first try descriptor among class attrs
        for(var i in chain) {
            if(exists i.__dict__[key]) {
                var attr = i.__dict__[key];
   
                // only for python objects
                if(typeof(attr) == 'Python;instance')
                    // if data-descriptor
                    if(exists attr.__dict__['__get__'] && exists attr.__dict__['__set__']) {
                        cry('using data descriptor');
                        return attr.__dict__['__get__'](attr, obj);
                    }
            }
        }

        // then attr on actual obj
        if(id(cls) == id(t)) { // if obj is a class
            cry('obj is class');
            for(var i in get_mro(obj)) {
                if(exists i.__dict__[key]) {
                    cry('getting from obj or parents');
                    var attr = i.__dict__[key];

                    // only for python objects
                    if(typeof(attr) == 'Python;instance')
                        if(exists attr.__dict__['__get__']) {
                            cry('using data descriptor');
                            return attr.__dict__['__get__'](attr, obj);
                        }

                    return attr;
                }
            }
        } else {
            cry('obj is not class');
            if(exists obj.__dict__[key]) {
                return obj.__dict__[key];
            }
        }

        // then on the obj's class
        for(var i in chain) {
            if(exists i.__dict__[key]) {
                var attr = i.__dict__[key];
                
                cry('getting from class');
            
                // only for python objects
                if(typeof(attr) == 'Python;instance')
                    if(exists attr.__dict__['__get__']) // if non-data descriptor
                        return attr.__dict__['__get__'](attr, obj);

                return attr;
            }
        }

        throw 'AttributeError';
    };

    t.__setattr__ = function(obj, key, val) {
        var cls = obj.__dict__['__class__'];
        
        if(exists cls.__dict__[key]) {
            var attr = cls.__dict__[key];

            // only for python objects
            if(typeof(attr) == 'Python;instance')
                if(exists attr.__dict__['__set__']) {
                    say('using data descriptor');
                    attr.__dict__['__set__'](attr, obj, val);
                    return;
                }
        }

        obj.__dict__[key] = val;
    };

    return t;
}

}