Python bindings - reflection

Accessing reflection information from Python

This example illustrates how python can directly access reflection information about classes, interfaces etc.

With the following C++


namespace pizza
{
    $typedef+ float64 TCurrency;
    
    $typedef+ string8 TEmail;
    $typedef+ string8 TPhoneNumber;

    $model+ TAddress
    {
        string8 Line1;
        string8 Line2;
        string8 Line3;
        string8 Line4;
        string8 City;
        int32 ZipPostCode;
        string8 StateProvinceCounty;
        string8 Country;
    };
    
    $model+ TEmployee
    {
        int32 Id;
        TAddress Address;
        string8 Name;
        TPhoneNumber Phone;
    };

    $model+ TVehicleType
    {
        int32 Id;
        string8 Description;
    };

    $model+ TVehicle
    {
        int32 Id;
        int32 VehicleTypeId;
    };

    $enum+ class EPaymentMethod
    {
        Cash,
        EftPos,
        CreditCard
    };

    $model+ TCustomer
    {
        int32 Id;
        TAddress Address;
        string8 Name;
        TPhoneNumber Phone;
        TEmail Email;
        dt::TDateTime DateOfFirstOrder;
        EPaymentMethod PaymentMethod;
    };
    
    $enum+ class EDeliveryStatus
    {
        Cooking,
        Delivering,
        Completed,
        Returned
    };

    $enum+ class EBaseType
    {
        Thin,
        DeepPan
    };

    $model+ TCircle
    {
        float32 Radius;    
    };

    $model+ TRectangle
    {
        float32 Width;
        float32 Height;
    };

    $variant+ TShape
    {
        default TCircle(200);
        TCircle;
        TRectangle;
    };
    
    $model+ TToppings
    {
        int32 Id;
        TCurrency Price;
        string8 Description;   // e.g. "Ham", "Pineapple"
    };

    $model+ TOrderedPizza
    {
        TShape Shape;
        EBaseType BaseType;
        xvector ToppingIds;
    };

    $struct+ TOrder isa ceda::IPersistable :
        model
        {
            int32 Id;
            int32 CustomerId;
            int32 TakenByEmployeeId;
            int32 DeliveredByEmployeeId;
            EDeliveryStatus DeliveryStatus;
            int32 VehicleId;
            dt::TDateTime DateTimeOrderTaken;
            dt::TDateTime DateTimeOrderDelivered;
            TCurrency TotalOrderPrice;
            xvector Pizzas;
        }
    {
    };
    
    $interface+ IProcessOrder
    {
        void ProcessOrder(const TOrder& order);
        int32 GetNumPendingOrders() const;
    };

    $struct+ TPizzaDeliveryDatabase isa ceda::IPersistable :
        model
        {
            xvector< movable< cref > > Orders;
        }
    {
    };
} // namespace pizza

the following Python


# python code

def PrintEnumInfo(e,indent):
    print ' '*indent + '$enum ' + `e.GetName()`
    print ' '*indent + '{'
    for i in range(0,e.GetCount()):
        str = ' '*indent + '    '
        if not e.GetEnable(i):
            str += '-'
        str += `e.GetString(i)` + ' = ' + `e.GetValue(i)`
        print str 
    print ' '*indent + '}'

def GetFunctionPrototype(rbcRet,getArgByteCode,isMethod,fn):
    proto = ''
    if rbcRet.IsNull():
        proto = 'void'
    else:
        proto = `rbcRet`
    proto += ' ' + `fn.GetName()` + '('
    for j in range(0,fn.GetNumArgs().AsInt32()):
        a = fn.GetArg(j)
        rbc = getArgByteCode(a)
        proto += `rbc` + ' ' + `a.GetName()`
        if j != fn.GetNumArgs().AsInt32()-1:
            proto += ','
    proto += ')'
    if isMethod and fn.IsConst():
        proto += ' const'
    return proto

# Returns a string representation of the prototype of an interface method
def GetInterfaceMethodPrototype(ri,m):
    rbcRet = ceda.GetInterfaceMethodReturnTypeByteCode(ri,m)
    def getArgByteCode(a):
        return ceda.GetInterfaceMethodArgByteCode(ri,a)
    isMethod = 1
    return GetFunctionPrototype(rbcRet,getArgByteCode,isMethod,m)

# Returns a string representation of the prototype of a class method
def GetClassMethodPrototype(rc,m):
    rbcRet = ceda.GetClassMethodReturnTypeByteCode(rc,m)
    def getArgByteCode(a):
        return ceda.GetClassMethodArgByteCode(rc,a)
    isMethod = 1
    return GetFunctionPrototype(rbcRet,getArgByteCode,isMethod,m)

def GetGlobalFunctionPrototype(gf):
    rbcRet = ceda.GetGlobalFunctionReturnTypeByteCode(gf)
    def getArgByteCode(a):
        return ceda.GetGlobalFunctionArgByteCode(gf,a)
    isMethod = 0
    return GetFunctionPrototype(rbcRet,getArgByteCode,isMethod,gf)
                    
def GetFunctorPrototype(f):
    rbcRet = ceda.GetFunctorReturnTypeByteCode(f)
    def getArgByteCode(a):
        return ceda.GetFunctorArgByteCode(f,a)
    isMethod = 0
    return GetFunctionPrototype(rbcRet,getArgByteCode,isMethod,f)
                    
def PrintGlobalFunctionInfo(gf,indent):
    print ' '*indent + '$function ' + GetGlobalFunctionPrototype(gf)

def PrintFunctorInfo(f,indent):
    print ' '*indent + '$functor ' + GetFunctorPrototype(f)
                
def PrintGlobalVariableInfo(gv,indent):
    rbc = ceda.GetGlobalVariableByteCode(gv)
    print ' '*indent + '$var ' + `rbc` + ' ' + `gv.GetName()`

def PrintTypedefInfo(t,indent):
    rbc = ceda.GetTypeDefByteCode(t)
    print ' '*indent + '$typedef ' + `rbc` + ' ' + `t.GetName()`

def PrintInterfaceInfo(ri,indent):
    print ' '*indent + '$interface ' + `ri.GetName()`
    print ' '*indent + '{'
    for i in range(0,ri.GetNumMethods().AsInt32()):
        m = ri.GetMethod(i)
        print ' '*indent + '    ' + GetInterfaceMethodPrototype(ri,m)
    print ' '*indent + '}'

def PrintVariantInfo(rv,indent):
    print ' '*indent + '$variant ' + `rv.GetName()`
    print ' '*indent + '{'
    for i in range(0,rv.GetNumFields().AsInt32()):
        f = rv.GetField(i)
        rbc = ceda.GetVariantFieldByteCode(rv,f)
        str = '[' + `f.GetOffset()` + ']'
        str += '    '
        str += `rbc` + ' ' + `f.GetName()`
        print ' '*indent + '    ' + str
    print ' '*indent + '}'

                    
                    
def GetClassSpecifier(c):
    #if c.IsStruct():
        #return 'datasource'
    if c.IsModel():
        return 'model'
    elif c.IsAdt():
        return 'adt'
    elif c.IsStruct():
        return 'struct'
    else:
        return 'class'
                
def PrintClassInfo(c,indent):
    print ' '*indent + '$' + GetClassSpecifier(c) + ' ' + `c.GetName()`
    print ' '*indent + '{'
    indent += 4
    #print ' '*indent + 'Flags = ' + `c.GetFlags()`
    print ' '*indent + 'Size = ' + `c.GetSize()` + ' bytes'
    print ' '*indent + 'CanCreate = ' + `c.CanCreate()`

    if c.GetNumModelFields().AsInt32() > 0:
        print ' '*indent + 'model'
        print ' '*indent + '{'
        for i in range(0,c.GetNumModelFields().AsInt32()):
            f = c.GetModelField(i)
            rbc = ceda.GetModelFieldByteCode(c,f)
            str = '[' + `f.GetOffset()` + ']'
            str += '    '
            str += `rbc` + ' ' + `f.GetName()` + '    '
            str += '[' + `f.GetRsn1()` + ',' + `f.GetRsn2()` + ')'
            if not f.Present():
                str += '*'
            print ' '*indent + '    ' + str
        print ' '*indent + '}'

    if c.GetNumFields().AsInt32() > 0:
        print ' '*indent + 'fields'
        print ' '*indent + '{'
        for i in range(0,c.GetNumFields().AsInt32()):
            f = c.GetField(i)
            rbc = ceda.GetFieldByteCode(c,f)
            str = '[' + `f.GetOffset()` + ']'
            str += '    '
            str += `rbc` + ' ' + `f.GetName()`
            print ' '*indent + '    ' + str
        print ' '*indent + '}'  

    if c.GetNumMethods().AsInt32() > 0:
        print ' '*indent + 'methods'
        print ' '*indent + '{'
        for i in range(0,c.GetNumMethods().AsInt32()):
            m = c.GetMethod(i)
            print ' '*indent + '    ' + GetClassMethodPrototype(c,m)
        print ' '*indent + '}'  

    if c.GetNumIndirectInterfaces().AsInt32() > 0:
        print ' '*indent + 'indirect interfaces'
        print ' '*indent + '{'
        for i in range(0,c.GetNumIndirectInterfaces().AsInt32()):
            nm = c.GetInterfaceName(i)
            print ' '*indent + '    ' + `nm`
        print ' '*indent + '}'  

    if c.GetNumDirectInterfaces().AsInt32() > 0:
        print ' '*indent + 'direct interfaces'
        print ' '*indent + '{'
        for i in range(c.GetNumIndirectInterfaces().AsInt32(),c.GetNumInterfaces().AsInt32()):
            nm = c.GetInterfaceName(i)
            print ' '*indent + '    ' + `nm`
        print ' '*indent + '}'  
                    
    indent -= 4
    print ' '*indent + '}'

def PrintNameSpaceElement(nse,indent):
    tp = nse.GetType()
    if tp == ceda.ENSType.NST_Interface:
        PrintInterfaceInfo(nse.AsInterface(),indent)
    elif tp == ceda.ENSType.NST_Class:
        PrintClassInfo(nse.AsClass(),indent)
    elif tp == ceda.ENSType.NST_GlobalFunction:
        PrintGlobalFunctionInfo(nse.AsGlobalFunction(),indent)
    elif tp == ceda.ENSType.NST_GlobalVariable:
        PrintGlobalVariableInfo(nse.AsGlobalVariable(),indent)
    elif tp == ceda.ENSType.NST_Typedef:
        PrintTypedefInfo(nse.AsTypedef(),indent)
    elif tp == ceda.ENSType.NST_Enum:
        PrintEnumInfo(nse.AsEnum(),indent)
    elif tp == ceda.ENSType.NST_Functor:
        PrintFunctorInfo(nse.AsFunctor(),indent)
    elif tp == ceda.ENSType.NST_Variant:
        PrintVariantInfo(nse.AsVariant(),indent)
    else:
        print 'unrecognised namespace element type ' + `tp`
        Assert(False)

def DumpNameSpace(ns,indent):
    # Show all elements in namespace ns
    i = ns.GetElementIterator()
    while not i.AtEnd():
        nse = i.GetElement()
        tp = nse.GetType()
        PrintNameSpaceElement(nse,indent)
        i.Next()
    i.Close()

    # Recurse into child namespaces
    i = ns.GetChildNameSpaceIterator()
    while not i.AtEnd():
        print ' '*indent + 'namespace ' + `i.GetName()`
        DumpNameSpace(i.GetNameSpace(),indent+4)
        i.Next()
    i.Close()
                
DumpNameSpace(cns.pizza, 0)

produces the following output


$enum pizza::EBaseType
{
    Thin = 0
    DeepPan = 1
}
$enum pizza::EDeliveryStatus
{
    Cooking = 0
    Delivering = 1
    Completed = 2
    Returned = 3
}
$enum pizza::EPaymentMethod
{
    Cash = 0
    EftPos = 1
    CreditCard = 2
}
$interface pizza::IProcessOrder
{
    void ProcessOrder(pizza::TOrder const& order)
    int32 GetNumPendingOrders()
}
$model pizza::TAddress
{
    Size = 176 bytes
    CanCreate = 0
    model
    {
        [0]    string8 Line1    [0,-1)
        [24]    string8 Line2    [0,-1)
        [48]    string8 Line3    [0,-1)
        [72]    string8 Line4    [0,-1)
        [96]    string8 City    [0,-1)
        [120]    int32 ZipPostCode    [0,-1)
        [128]    string8 StateProvinceCounty    [0,-1)
        [152]    string8 Country    [0,-1)
    }
}
$model pizza::TCircle
{
    Size = 4 bytes
    CanCreate = 0
    model
    {
        [0]    float32 Radius    [0,-1)
    }
}
$typedef float64 pizza::TCurrency
$model pizza::TCustomer
{
    Size = 288 bytes
    CanCreate = 0
    model
    {
        [0]    int32 Id    [0,-1)
        [8]    pizza::TAddress Address    [0,-1)
        [184]    string8 Name    [0,-1)
        [208]    pizza::TPhoneNumber Phone    [0,-1)
        [232]    pizza::TEmail Email    [0,-1)
        [256]    dt::TDateTime DateOfFirstOrder    [0,-1)
        [280]    pizza::EPaymentMethod PaymentMethod    [0,-1)
    }
}
$typedef string8 pizza::TEmail
$model pizza::TEmployee
{
    Size = 232 bytes
    CanCreate = 0
    model
    {
        [0]    int32 Id    [0,-1)
        [8]    pizza::TAddress Address    [0,-1)
        [184]    string8 Name    [0,-1)
        [208]    pizza::TPhoneNumber Phone    [0,-1)
    }
}
$model pizza::TOrder
{
    Size = 160 bytes
    CanCreate = 1
    model
    {
        [56]    int32 Id    [0,-1)
        [60]    int32 CustomerId    [0,-1)
        [64]    int32 TakenByEmployeeId    [0,-1)
        [68]    int32 DeliveredByEmployeeId    [0,-1)
        [72]    pizza::EDeliveryStatus DeliveryStatus    [0,-1)
        [76]    int32 VehicleId    [0,-1)
        [80]    dt::TDateTime DateTimeOrderTaken    [0,-1)
        [104]    dt::TDateTime DateTimeOrderDelivered    [0,-1)
        [128]    pizza::TCurrency TotalOrderPrice    [0,-1)
        [136]    xvector Pizzas    [0,-1)
    }
    indirect interfaces
    {
        ceda::IObject
    }
    direct interfaces
    {
        ceda::IPersistable
    }
}
$model pizza::TOrderedPizza
{
    Size = 40 bytes
    CanCreate = 0
    model
    {
        [0]    pizza::TShape Shape    [0,-1)
        [12]    pizza::EBaseType BaseType    [0,-1)
        [16]    xvector ToppingIds    [0,-1)
    }
}
$typedef string8 pizza::TPhoneNumber
$model pizza::TPizzaDeliveryDatabase
{
    Size = 80 bytes
    CanCreate = 1
    model
    {
        [56]    xvector> Orders    [0,-1)
    }
    indirect interfaces
    {
        ceda::IObject
    }
    direct interfaces
    {
        ceda::IPersistable
    }
}
$model pizza::TRectangle
{
    Size = 8 bytes
    CanCreate = 0
    model
    {
        [0]    float32 Width    [0,-1)
        [4]    float32 Height    [0,-1)
    }
}
$variant pizza::TShape
{
    [4]    pizza::TCircle pizza::TCircle
    [4]    pizza::TRectangle pizza::TRectangle
}
$model pizza::TToppings
{
    Size = 40 bytes
    CanCreate = 0
    model
    {
        [0]    int32 Id    [0,-1)
        [8]    pizza::TCurrency Price    [0,-1)
        [16]    string8 Description    [0,-1)
    }
}
$model pizza::TVehicle
{
    Size = 8 bytes
    CanCreate = 0
    model
    {
        [0]    int32 Id    [0,-1)
        [4]    int32 VehicleTypeId    [0,-1)
    }
}
$model pizza::TVehicleType
{
    Size = 32 bytes
    CanCreate = 0
    model
    {
        [0]    int32 Id    [0,-1)
        [8]    string8 Description    [0,-1)
    }
}