Changeset 100

Show
Ignore:
Timestamp:
02/17/07 02:32:39 (5 years ago)
Author:
KirkMcDonald
Message:

* Class wrapping API replaced.
* Inheritance "shim" classes now automatically generated.
* Requires DMD 1.005 or newer. Breaks GDC support for the moment.
* Docs not yet updated to reflect changes.
* Copyright notices updated to 2007.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/examples/inherit/inherit.d

    r91 r100  
    2121} 
    2222 
    23 class BaseWrap : Base { 
    24     mixin OverloadShim; 
    25     this(int i) { super(i); } 
    26     void foo() { 
    27         get_overload(&super.foo, "foo"); 
    28     } 
    29     void bar() { 
    30         get_overload(&super.bar, "bar"); 
    31     } 
    32 } 
    33  
    34 class DeriveWrap : Derived { 
    35     mixin OverloadShim; 
    36     this(int i) { super(i); } 
    37     void foo() { 
    38         get_overload(&super.foo, "foo"); 
    39     } 
    40 } 
    41  
    4223void call_poly(Base b) { 
    4324    writefln("call_poly:"); 
     
    5738} 
    5839 
    59 Base return_poly_wrap() { 
    60     if (b3 is null) b3 = new DeriveWrap(3); 
    61     return b3; 
    62 } 
    63  
    6440extern(C) void PydMain() { 
    6541    def!(call_poly); 
    6642    def!(return_poly_base); 
    6743    def!(return_poly_derived); 
    68     def!(return_poly_wrap); 
    6944 
    7045    module_init(); 
    7146 
    72     wrapped_class!(Base) b; 
    73     b.hide(); 
    74     b.def!(Base.foo); 
    75     b.def!(Base.bar); 
    76     finalize_class(b); 
     47    wrap_class!( 
     48        Base, 
     49        Init!(void function(int)), 
     50        Def!(Base.foo), 
     51        Def!(Base.bar) 
     52    ); 
    7753 
    78     wrapped_class!(Derived) d; 
    79     d.hide(); 
    80     d.def!(Derived.foo); 
    81     finalize_class(d); 
    82  
    83     wrapped_class!(BaseWrap, "Base") bw; 
    84     bw.init!(void function(int)); 
    85     bw.def!(BaseWrap.foo); 
    86     bw.def!(BaseWrap.bar); 
    87     finalize_class(bw); 
    88  
    89     wrapped_class!(DeriveWrap, "Derived") dw; 
    90     dw.init!(void function(int)); 
    91     dw.parent!(BaseWrap); 
    92     dw.def!(DeriveWrap.foo); 
    93     finalize_class(dw); 
     54    wrap_class!( 
     55        Derived, 
     56        Init!(void function(int)), 
     57        Def!(Derived.foo) 
     58    ); 
    9459} 
    9560 
  • trunk/examples/inherit/test.py

    r91 r100  
    5050print "inherit.return_poly_derived returned the same object twice" 
    5151assert b2 is b2a 
    52 b3 = inherit.return_poly_wrap() 
    53 print "inherit.return_poly_wrap returned instance of DeriveWrap" 
    54 assert type(b3) == inherit.Derived 
    5552 
    5653print 
  • trunk/examples/testdll/test.py

    r67 r100  
    3838print 
    3939 
     40print "Testing class wrapping" 
    4041a = testdll.Foo(10) 
     42print "Class instantiated!" 
     43print "Testing method wrapping:" 
    4144a.foo() 
     45print "Testing property wrapping:" 
     46print a.i 
     47a.i = 50 
     48print a.i 
    4249 
    4350print "Testing opApply wrapping:" 
  • trunk/examples/testdll/testdll.d

    r67 r100  
    118118    module_init(); 
    119119 
    120     wrapped_class!(Foo) f; 
    121     // Constructor wrapping 
    122     f.init!(void function(int), void function(int, int)); 
    123     // Member function wrapping 
    124     f.def!(Foo.foo); 
    125     // Property wrapping 
    126     f.prop!(Foo.i); 
    127     finalize_class(f); 
     120    wrap_class!( 
     121        Foo, 
     122        Init!(void delegate(int), void delegate(int, int)), 
     123        Property!(Foo.i), 
     124        Def!(Foo.foo) 
     125    ); 
    128126 
    129     wrapped_struct!(S) s; 
    130     s.def!(S.write_s); 
    131     const size_t i = S.i.offsetof; 
    132     const size_t t = S.s.offsetof; 
    133     s.member!(int, i, "i"); 
    134     s.member!(char[], t, "s"); 
    135     finalize_struct(s); 
     127    wrap_struct!( 
     128        S, 
     129        Def!(S.write_s), 
     130        Member!("i"), 
     131        Member!("s") 
     132    ); 
    136133} 
    137134 
  • trunk/infrastructure/pyd/LICENSE

    r24 r100  
    1 Copyright (c) 2006 Kirk McDonald 
     1Copyright 2006, 2007 Kirk McDonald 
    22 
    33Permission is hereby granted, free of charge, to any person obtaining a copy of 
  • trunk/infrastructure/pyd/class_wrap.d

    r91 r100  
    11/* 
    2 Copyright (c) 2006 Kirk McDonald 
     2Copyright 2006, 2007 Kirk McDonald 
    33 
    44Permission is hereby granted, free of charge, to any person obtaining a copy of 
     
    3232} 
    3333import pyd.make_object; 
     34import pyd.make_wrapper; 
    3435import pyd.op_wrap; 
     36import pyd.make_wrapper; 
    3537import pyd.lib_abstract : 
    3638    symbolnameof, 
     
    4042    ReturnType, 
    4143    minArgs, 
    42     objToStr 
     44    objToStr, 
     45    ToString 
    4346; 
    4447 
     
    4649 
    4750PyTypeObject*[ClassInfo] wrapped_classes; 
     51template shim_class(T) { 
     52    PyTypeObject* shim_class; 
     53} 
    4854 
    4955// This is split out in case I ever want to make a subtype of a wrapped class. 
     
    243249////////////////////////////// 
    244250 
     251/+ 
    245252/** 
    246253 * This struct wraps a D class. Its member functions are the primary way of 
     
    252259    static bool _private = false; 
    253260    alias T wrapped_type; 
    254     /** 
    255      * Wraps a member function of the class. 
    256      * 
    257      * Params: 
    258      * fn = The member function to wrap. 
    259      * name = The name of the function as it will appear in Python. 
    260      * fn_t = The type of the function. It is only useful to specify this 
    261      *        if more than one function has the same name as this one. 
    262      */ 
    263     static void def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn)) (char[] docstring="") { 
     261+/ 
     262 
     263//enum ParamType { Def, StaticDef, Property, Init, Parent, Hide, Iter, AltIter } 
     264struct DoNothing { 
     265    static void call(T) () {} 
     266
     267/** 
     268Wraps a member function of the class. 
     269 
     270Params: 
     271fn = The member function to wrap. 
     272name = The name of the function as it will appear in Python. 
     273fn_t = The type of the function. It is only useful to specify this 
     274       if more than one function has the same name as this one. 
     275*/ 
     276template Def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS=minArgs!(fn)) { 
     277    alias Def!(fn, symbolnameof!(fn), name, fn_t, MIN_ARGS) Def; 
     278
     279struct Def(alias fn, char[] _realname, char[] name, fn_t, uint MIN_ARGS) { 
     280    //static const type = ParamType.Def; 
     281    alias fn func; 
     282    alias fn_t func_t; 
     283    static const char[] realname = _realname; 
     284    static const char[] funcname = name; 
     285    static const uint min_args = MIN_ARGS; 
     286 
     287    static void call(T) () { 
    264288        pragma(msg, "class.def: " ~ name); 
    265289        static PyMethodDef empty = { null, null, 0, null }; 
     
    268292        list[length-1].ml_meth = &method_wrap!(T, fn, fn_t).func; 
    269293        list[length-1].ml_flags = METH_VARARGS; 
    270         list[length-1].ml_doc = (docstring ~ \0).ptr
     294        list[length-1].ml_doc = ""
    271295        list ~= empty; 
    272296        // It's possible that appending the empty item invalidated the 
     
    274298        wrapped_class_type!(T).tp_methods = list.ptr; 
    275299    } 
    276  
    277     /** 
    278      * Wraps a static member function of the class. Identical to pyd.def.def 
    279      */ 
    280     static void static_def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS=minArgs!(fn)) (char[] docstring="") { 
     300    template shim(uint i) { 
     301        const char[] shim = 
     302            "    alias Params["~ToString!(i)~"] __pyd_p"~ToString!(i)~";\n" 
     303            "    ReturnType!(__pyd_p"~ToString!(i)~".func_t) "~_realname~"(ParameterTypeTuple!(__pyd_p"~ToString!(i)~".func_t) t) {\n" 
     304            "        return __pyd_get_overload!(\""~_realname~"\", __pyd_p"~ToString!(i)~".func_t).func(\""~name~"\", t);\n" 
     305            "    }\n"; 
     306    } 
     307    template shim_call(char[] varname, uint i) { 
     308        const char[] shim_call = "Def!("~varname~"."~_realname~", p"~ToString!(i)~".realname, p"~ToString!(i)~".funcname, p"~ToString!(i)~".func_t, p"~ToString!(i)~".min_args)"; 
     309    } 
     310
     311 
     312/** 
     313Wraps a static member function of the class. Identical to pyd.def.def 
     314*/ 
     315struct StaticDef(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS=minArgs!(fn)) { 
     316    //static const type = ParamType.StaticDef; 
     317    alias fn func; 
     318    alias fn_t func_t; 
     319    static const char[] funcname = name; 
     320    static const uint min_args = MIN_ARGS; 
     321    static void call(T) () { 
    281322        pragma(msg, "class.static_def: " ~ name); 
    282323        static PyMethodDef empty = { null, null, 0, null }; 
     
    285326        list[length-1].ml_meth = &function_wrap!(fn, MIN_ARGS, fn_t).func; 
    286327        list[length-1].ml_flags = METH_VARARGS | METH_STATIC; 
    287         list[length-1].ml_doc = (docstring ~ \0).ptr
     328        list[length-1].ml_doc = ""
    288329        list ~= empty; 
    289330        wrapped_class_type!(T).tp_methods = list; 
    290331    } 
    291  
    292     /** 
    293      * Wraps a property of the class. 
    294      * 
    295      * Params: 
    296      * fn = The property to wrap. 
    297      * name = The name of the property as it will appear in Python. 
    298      * RO = Whether this is a read-only property. 
    299      */ 
    300     static void prop(alias fn, char[] name = symbolnameof!(fn), bool RO=false) (char[] docstring="") { 
     332    template shim(uint i) { 
     333        const char[] shim = ""; 
     334    } 
     335    template shim_call(char[] varname, uint i) { 
     336        const char[] shim_call = "DoNothing"; 
     337    } 
     338
     339 
     340/** 
     341Wraps a property of the class. 
     342 
     343Params: 
     344fn = The property to wrap. 
     345name = The name of the property as it will appear in Python. 
     346RO = Whether this is a read-only property. 
     347*/ 
     348template Property(alias fn, char[] name = symbolnameof!(fn), bool RO=false) { 
     349    alias Property!(fn, symbolnameof!(fn), name, RO) Property; 
     350
     351struct Property(alias fn, char[] _realname, char[] name, bool RO) { 
     352    alias property_parts!(fn).getter_type get_t; 
     353    alias property_parts!(fn).setter_type set_t; 
     354    static const char[] realname = _realname; 
     355    static const char[] funcname = name; 
     356    static const bool readonly = RO; 
     357    static void call(T) () { 
    301358        pragma(msg, "class.prop: " ~ name); 
    302359        static PyGetSetDef empty = { null, null, null, null, null }; 
     
    308365                &wrapped_set!(T, fn).func; 
    309366        } 
    310         wrapped_prop_list!(T)[length-1].doc = (docstring ~ \0).ptr
     367        wrapped_prop_list!(T)[length-1].doc = ""
    311368        wrapped_prop_list!(T)[length-1].closure = null; 
    312369        wrapped_prop_list!(T) ~= empty; 
     
    316373            wrapped_prop_list!(T).ptr; 
    317374    } 
    318  
    319     /** 
    320      * Wraps the constructors of the class. 
    321      * 
    322      * This template takes a series of specializations of the ctor template 
    323      * (see ctor_wrap.d), each of which describes a different constructor 
    324      * that the class supports. The default constructor need not be 
    325      * specified, and will always be available if the class supports it. 
    326      * 
    327      * Bugs: 
    328      * This currently does not support having multiple constructors with 
    329      * the same number of arguments. 
    330      */ 
    331     static void init(C ...) () { 
     375    template shim_setter(uint i) { 
     376        static if (RO) { 
     377            const char[] shim_setter = ""; 
     378        } else { 
     379            const char[] shim_setter = 
     380            "    ReturnType!(__pyd_p"~ToString!(i)~".set_t) "~_realname~"(ParameterTypeTuple!(__pyd_p"~ToString!(i)~".set_t) t) {\n" 
     381            "        return __pyd_get_overload!(\""~_realname~"\", __pyd_p"~ToString!(i)~".set_t).func(\""~name~"\", t);\n" 
     382            "    }\n"; 
     383        } 
     384    } 
     385    template shim(uint i) { 
     386        const char[] shim = 
     387            "    alias Params["~ToString!(i)~"] __pyd_p"~ToString!(i)~";\n" 
     388            "    ReturnType!(__pyd_p"~ToString!(i)~".get_t) "~_realname~"() {\n" 
     389            "        return __pyd_get_overload!(\""~_realname~"\", __pyd_p"~ToString!(i)~".get_t).func(\""~name~"\");\n" 
     390            "    }\n" ~ 
     391            shim_setter!(i); 
     392    } 
     393    template shim_call(char[] varname, uint i) { 
     394        const char[] shim_call = "Property!("~varname~"."~_realname~", p"~ToString!(i)~".realname, p"~ToString!(i)~".funcname, p"~ToString!(i)~".readonly)"; 
     395    } 
     396
     397 
     398/** 
     399Wraps the constructors of the class. 
     400 
     401This template takes a series of specializations of the ctor template 
     402(see ctor_wrap.d), each of which describes a different constructor 
     403that the class supports. The default constructor need not be 
     404specified, and will always be available if the class supports it. 
     405 
     406Bugs: 
     407This currently does not support having multiple constructors with 
     408the same number of arguments. 
     409*/ 
     410struct Init(C ...) { 
     411    alias C ctors; 
     412    static void call(T) () { 
    332413        wrapped_class_type!(T).tp_init = 
    333414            &wrapped_ctors!(T, C).init_func; 
    334415    } 
    335  
    336     static void parent(Parent) () { 
    337         wrapped_class_type!(T).tp_base = &wrapped_class_type!(Parent); 
    338     } 
    339  
    340     static void hide() { 
    341         _private = true; 
    342     } 
    343  
    344     // Iteration wrapping support requires StackThreads 
    345     version(Pyd_with_StackThreads) { 
    346  
    347     /** 
    348      * Allows selection of alternate opApply overloads. iter_t should be 
    349      * the type of the delegate in the opApply function that the user wants 
    350      * to be the default. 
    351      */ 
    352     static void iter(iter_t) () { 
     416    template shim_impl(uint i, uint c=0) { 
     417        static if (c < ctors.length) { 
     418            const char[] shim_impl =  
     419                "    this(ParameterTypeTuple!(__pyd_c"~ToString!(i)~"["~ToString!(c)~"]) t) {\n" 
     420                "        super(t);\n" 
     421                "    }\n" ~ shim_impl!(i, c+1); 
     422        } else { 
     423            const char[] shim_impl = ""; 
     424        } 
     425    } 
     426    template shim(uint i) { 
     427        const char[] shim = 
     428            "    alias Params["~ToString!(i)~"] __pyd_p"~ToString!(i)~";\n" 
     429            "    alias __pyd_p"~ToString!(i)~".ctors __pyd_c"~ToString!(i)~";\n"~ 
     430            shim_impl!(i); 
     431    } 
     432    template shim_call(char[] varname, uint i) { 
     433        const char[] shim_call = "Init!(p"~ToString!(i)~".ctors)"; 
     434    } 
     435
     436 
     437// Iteration wrapping support requires StackThreads 
     438version(Pyd_with_StackThreads) { 
     439 
     440/** 
     441Allows selection of alternate opApply overloads. iter_t should be 
     442the type of the delegate in the opApply function that the user wants 
     443to be the default. 
     444*/ 
     445struct Iter(iter_t) { 
     446    static void call(T) () { 
    353447        PydStackContext_Ready(); 
    354         wrapped_class_type!(T).tp_iter = &wrapped_iter!(T, T.opApply, int function(iter_t)).iter; 
    355     } 
    356  
    357     /** 
    358      * Exposes alternate iteration methods, originally intended for use with 
    359      * D's delegate-as-iterator features, as methods returning a Python 
    360      * iterator. 
    361      */ 
    362     static void alt_iter(alias fn, char[] name = symbolnameof!(fn), iter_t = funcDelegInfoT!(typeof(&fn)).Meta.ArgType!(0)) (char[] docstring="") { 
     448        // This strange bit of hackery is needed since we operate on pointer- 
     449        // to-struct types, rather than just struct types. 
     450        static if (is(T S : S*) && is(S == struct)) { 
     451            wrapped_class_type!(T).tp_iter = &wrapped_iter!(T, S.opApply, int function(iter_t)).iter; 
     452        } else { 
     453            wrapped_class_type!(T).tp_iter = &wrapped_iter!(T, T.opApply, int function(iter_t)).iter; 
     454        } 
     455    } 
     456
     457 
     458/** 
     459Exposes alternate iteration methods, originally intended for use with 
     460D's delegate-as-iterator features, as methods returning a Python 
     461iterator. 
     462*/ 
     463struct AltIter(alias fn, char[] name = symbolnameof!(fn), iter_t = funcDelegInfoT!(typeof(&fn)).Meta.ArgType!(0)) { 
     464    static void call(T) () { 
    363465        static PyMethodDef empty = { null, null, 0, null }; 
    364466        alias wrapped_method_list!(T) list; 
     
    373475        wrapped_class_type!(T).tp_methods = list; 
    374476    } 
    375  
    376     } /*Pyd_with_StackThreads*/ 
    377 
    378  
    379 /** 
    380  * Finalize the wrapping of the class. It is neccessary to call this after all 
    381  * calls to the wrapped_class member functions. 
    382  */ 
    383 void finalize_class(CLS) (CLS cls, char[] docstring="", char[] modulename="") { 
    384     alias CLS.wrapped_type T; 
     477
     478 
     479} /*Pyd_with_StackThreads*/ 
     480 
     481private 
     482template comma(uint i, uint length) { 
     483    static if (i < length-1) { 
     484        const char[] comma = ","; 
     485    } else { 
     486        const char[] comma = ""; 
     487    } 
     488
     489 
     490private 
     491template recursive_call(char[] name, int i, Params...) { 
     492    static if (i < Params.length) { 
     493        const char[] recursive_call = Params[i].shim_call!(name, i) ~ comma!(i, Params.length) ~ recursive_call!(name, i+1, Params); 
     494    } else { 
     495        const char[] recursive_call = ""; 
     496    } 
     497
     498 
     499private 
     500template aliases(uint i, Params...) { 
     501    static if (i < Params.length) { 
     502        const char[] aliases = "alias Params["~ToString!(i)~"] p"~ToString!(i)~";\n" ~ aliases!(i+1, Params); 
     503    } else { 
     504        const char[] aliases = ""; 
     505    } 
     506
     507 
     508void wrap_class(T, Params...) (char[] docstring="", char[] modulename="") { 
     509    wrap_class!(void, T, symbolnameof!(T), Params)(docstring, modulename); 
     510
     511void wrap_class(T, char[] name, Params...) (char[] docstring="", char[] modulename="") { 
     512    wrap_class!(void, T, name, Params)(docstring, modulename); 
     513
     514 
     515void wrap_class(wrapping, _T, char[] name, Params...) (char[] docstring="", char[] modulename="") { 
     516    //alias CLS.wrapped_type T; 
     517    //const char[] name = CLS._name; 
     518    static if (is(_T == class)) { 
     519        pragma(msg, "wrap_class: " ~ name); 
     520        alias _T T; 
     521    } else { 
     522        pragma(msg, "wrap_struct: " ~ name); 
     523        alias _T* T; 
     524    } 
    385525    alias wrapped_class_type!(T) type; 
    386     const char[] name = CLS._name; 
    387     static if (is(T == class)) { 
    388         pragma(msg, "finalize_class: " ~ name); 
    389     } else { 
    390         pragma(msg, "finalize_struct: " ~ name); 
    391     } 
    392     pragma(msg, "finalize_class, T is " ~ prettytypeof!(T)); 
    393      
     526    //pragma(msg, "wrap_class, T is " ~ prettytypeof!(T)); 
     527 
     528    //Params params; 
     529    foreach (param; Params) { 
     530        param.call!(T)(); 
     531    } 
     532 
    394533    assert(Pyd_Module_p(modulename) !is null, "Must initialize module before wrapping classes."); 
    395534    char[] module_name = toString(PyModule_GetName(Pyd_Module_p(modulename))); 
    396     // Fill in missing values 
     535 
     536    ////////////////// 
     537    // Basic values // 
     538    ////////////////// 
    397539    type.ob_type      = PyType_Type_p(); 
    398540    type.tp_basicsize = (wrapped_class_object!(T)).sizeof; 
     
    403545    type.tp_name      = (module_name ~ "." ~ name ~ \0).ptr; 
    404546 
    405     // Check for wrapped parent classes, if one was not explicitly supplied. 
    406     if (type.tp_base is null) { 
     547    ///////////////// 
     548    // Inheritance // 
     549    ///////////////// 
     550    static if (is(wrapping == void)) { 
     551        // Inherit directly-wrapped classes from their wrapped superclass. 
    407552        static if (is(T B == super)) { 
    408553            foreach (C; B) { 
     
    414559            } 
    415560        } 
    416     } 
    417  
     561    } else { 
     562        // Inherit shims from their grandparent's shim. 
     563        static if (is(wrapping B == super)) { 
     564            foreach (C; B) { 
     565                static if (is(C == class) && !is(C == Object)) { 
     566                    type.tp_base = shim_class!(C); 
     567                } 
     568            } 
     569        } 
     570    } 
     571 
     572    //////////////////////// 
     573    // Operator overloads // 
     574    //////////////////////// 
    418575    // Numerical operator overloads 
    419576    if (wrapped_class_as_number!(T) != PyNumberMethods.init) { 
     
    448605    } 
    449606 
    450     if (CLS._private) { 
     607    ////////////////////////// 
     608    // Constructor wrapping // 
     609    ////////////////////////// 
     610    static if (is(wrapping == void) && is(T == class)) { 
     611        // Non-shim classes cannot be instantiated from Python. 
    451612        type.tp_init = null; 
    452613    } else { 
    453614        // If a ctor wasn't supplied, try the default. 
     615        // If the default ctor isn't available, and no ctors were supplied, 
     616        // then this class cannot be instantiated from Python. 
     617        // (Structs always use the default ctor.) 
    454618        static if (is(typeof(new T))) { 
    455619            if (type.tp_init is null) { 
     
    462626        } 
    463627    } 
     628 
     629    ////////////////// 
     630    // Finalization // 
     631    ////////////////// 
    464632    if (PyType_Ready(&type) < 0) { 
    465633        throw new Exception("Couldn't ready wrapped type!"); 
    466634    } 
    467635    Py_INCREF(cast(PyObject*)&type); 
    468     if (!CLS._private) { 
     636    // Only directly expose a class to Python if it is a shim. 
     637    static if (!is(wrapping == void) || is(T U : U*) && is(U == struct)) { 
    469638        PyModule_AddObject(Pyd_Module_p(modulename), name.ptr, cast(PyObject*)&type); 
    470639    } 
     640 
    471641    is_wrapped!(T) = true; 
    472642    static if (is(T == class)) { 
    473643        wrapped_classes[T.classinfo] = &type; 
    474     } 
    475 
    476  
    477 template OverloadShim() { 
    478     std.traits.ReturnType!(dg_t) get_overload(dg_t, T ...) (dg_t dg, char[] name, T t) { 
    479         python.PyObject** _pyobj = cast(void*)this in wrapped_gc_objects; 
    480         python.PyTypeObject** _pytype = this.classinfo in wrapped_classes; 
    481         if (_pyobj is null || _pytype is null || (*_pyobj).ob_type != *_pytype) { 
    482             // If this object's type is not the wrapped class's type (that is, 
    483             // if this object is actually a Python subclass of the wrapped 
    484             // class), then call the Python object. 
    485             python.PyObject* method = python.PyObject_GetAttrString(*_pyobj, (name ~ \0).ptr); 
    486             if (method is null) handle_exception(); 
    487             dg_t pydg = PydCallable_AsDelegate!(dg_t)(method); 
    488             python.Py_DECREF(method); 
    489             return pydg(t); 
    490         } else { 
    491             return dg(t); 
     644        // If this is a class passed in by the user, create and wrap the shim. 
     645        // (By recursively calling this function.) 
     646        static if (is(wrapping == void)) { 
     647            alias make_wrapper!(T, Params).wrapper wrapper_class; 
     648            // Construct the recursive call. Since /this/ call to wrap_class 
     649            // was passed aliases to the members of the /base/ class, we need 
     650            // to pass the recursive call aliases to the members of the /shim/. 
     651            // The recursive_call template goes through each member of Params 
     652            // and constructs this. 
     653 
     654            // This is a workaround for some tuple shortcomings... 
     655            const char[] a = aliases!(0, Params); 
     656            pragma(msg, a); 
     657            mixin(a); 
     658 
     659            const char[] call = "wrap_class!(T, wrapper_class, name, "~recursive_call!("wrapper_class", 0, Params)~")();"; 
     660            pragma(msg, call); 
     661            mixin(call); 
     662            shim_class!(T) = &wrapped_class_type!(wrapper_class); 
    492663        } 
    493664    } 
     
    565736    alias wrapped_class_type!(T) type; 
    566737    wrapped_object* self = cast(wrapped_object*)_self; 
    567     if (!is_wrapped!(T) || self is null || !PyObject_TypeCheck(_self, &type)) { 
     738    if (!is_wrapped!(T) || self is null || (is(T : Object) && cast(T)cast(Object)self.d_obj is null)) { 
    568739        throw new Exception("Error extracting D object from Python object..."); 
    569740    } 
  • trunk/infrastructure/pyd/ctor_wrap.d

    r69 r100  
    11/* 
    2 Copyright (c) 2006 Kirk McDonald 
     2Copyright 2006, 2007 Kirk McDonald 
    33 
    44Permission is hereby granted, free of charge, to any person obtaining a copy of 
  • trunk/infrastructure/pyd/def.d

    r69 r100  
    11/* 
    2 Copyright (c) 2006 Kirk McDonald 
     2Copyright 2006, 2007 Kirk McDonald 
    33 
    44Permission is hereby granted, free of charge, to any person obtaining a copy of 
  • trunk/infrastructure/pyd/dg_convert.d

    r69 r100  
    11/* 
    2 Copyright (c) 2006 Kirk McDonald 
     2Copyright 2006, 2007 Kirk McDonald 
    33 
    44Permission is hereby granted, free of charge, to any person obtaining a copy of 
  • trunk/infrastructure/pyd/exception.d

    r69 r100  
    11/* 
    2 Copyright (c) 2006 Kirk McDonald 
     2Copyright 2006, 2007 Kirk McDonald 
    33 
    44Permission is hereby granted, free of charge, to any person obtaining a copy of 
  • trunk/infrastructure/pyd/func_wrap.d

    r69 r100  
    11/* 
    2 Copyright (c) 2006 Kirk McDonald 
     2Copyright 2006, 2007 Kirk McDonald 
    33 
    44Permission is hereby granted, free of charge, to any person obtaining a copy of 
  • trunk/infrastructure/pyd/iteration.d

    r68 r100  
    11/* 
    2 Copyright (c) 2006 Kirk McDonald 
     2Copyright 2006, 2007 Kirk McDonald 
    33 
    44Permission is hereby granted, free of charge, to any person obtaining a copy of 
  • trunk/infrastructure/pyd/lib_abstract.d

    r69 r100  
    2525module pyd.lib_abstract; 
    2626 
    27 version (Pyd_with_Tango) { 
     27version (Tango) { 
    2828    import tango.stdc.string : strlen; 
    2929    import tango.text.convert.Integer : qadut; 
     
    5050    public import std.traits : ParameterTypeTuple, ReturnType; 
    5151    public import std.bind : minArgs = minNumArgs; 
     52    public import std.metastrings : ToString; 
    5253} 
  • trunk/infrastructure/pyd/make_object.d

    r69 r100  
    11/* 
    2 Copyright (c) 2006 Kirk McDonald 
     2Copyright 2006, 2007 Kirk McDonald 
    33 
    44Permission is hereby granted, free of charge, to any person obtaining a copy of 
     
    248248        // We can only convert to a class if it has been wrapped, and of course 
    249249        // we can only convert the object if it is the wrapped type. 
    250         if (is_wrapped!(T) && PyObject_TypeCheck(o, &wrapped_class_type!(T))) { 
     250        if (is_wrapped!(T) && cast(T)((cast(wrapped_class_object!(Object)*)o).d_obj) !is null) { 
    251251            return WrapPyObject_AsObject!(T)(o); 
    252252        } 
  • trunk/infrastructure/pyd/op_wrap.d

    r69 r100  
    11/* 
    2 Copyright (c) 2006 Kirk McDonald 
     2Copyright 2006, 2007 Kirk McDonald 
    33 
    44Permission is hereby granted, free of charge, to any person obtaining a copy of 
  • trunk/infrastructure/pyd/pyd.d

    r60 r100  
    11/* 
    2 Copyright (c) 2006 Kirk McDonald 
     2Copyright 2006, 2007 Kirk McDonald 
    33 
    44Permission is hereby granted, free of charge, to any person obtaining a copy of 
  • trunk/infrastructure/pyd/pydobject.d

    r69 r100  
    170170        return new PydObject(PyObject_Str(m_ptr)); 
    171171    } 
    172     /// Allows use of PydObject in writef via %s 
    173     version (Pyd_with_Tango) { 
     172    version (Tango) { 
     173        /// Allows PydObject to be formatted. 
    174174        char[] toUtf8() { 
    175175            return d_type!(char[])(m_ptr); 
    176176        } 
    177177    } else { 
     178        /// Allows use of PydObject in writef via %s 
    178179        char[] toString() { 
    179180            return d_type!(char[])(m_ptr); 
  • trunk/infrastructure/pyd/struct_wrap.d

    r92 r100  
    11/* 
    2 Copyright (c) 2006 Kirk McDonald 
     2Copyright 2006, 2007 Kirk McDonald 
    33 
    44Permission is hereby granted, free of charge, to any person obtaining a copy of 
     
    3434; 
    3535 
    36 //import std.stdio; 
    37 //import std.string; 
    38 //import meta.Nameof; 
     36// It is intended that all of these templates accept a pointer-to-struct type 
     37// as a template parameter, rather than the struct type itself. 
    3938 
    40 // With the exception of the T passed to wrapped_struct, it is intended that 
    41 // all of these templates accept a pointer-to-struct type as a template 
    42 // parameter, rather than the struct type itself. 
    43  
    44 template wrapped_member(T, M, size_t offset) { 
     39template wrapped_member(T, char[] name, _M=void) { 
    4540    alias wrapped_class_type!(T) type; 
    4641    alias wrapped_class_object!(T) obj; 
    47     //alias typeof(member) M; 
     42    static if (is(_M == void)) { 
     43        mixin("alias typeof(T."~name~") M;"); 
     44    } else { 
     45        alias _M M; 
     46    } 
    4847    extern(C) 
    4948    PyObject* get(PyObject* self, void* closure) { 
    5049        return exception_catcher(delegate PyObject*() { 
    5150            T t = (cast(obj*)self).d_obj; 
    52             M* m = cast(M*)(cast(void*)t + offset); 
    53             return _py(*m); 
     51            mixin("return _py(t."~name~");"); 
    5452        }); 
    5553    } 
     
    5957        return exception_catcher(delegate int() { 
    6058            T t = (cast(obj*)self).d_obj; 
    61             M* m = cast(M*)(cast(void*)(t) + offset); 
    62             *m = d_type!(M)(value); 
     59            mixin("t."~name~" = d_type!(M)(value);"); 
    6360            return 0; 
    6461        }); 
     
    6663} 
    6764 
    68 struct wrapped_struct(T, char[] structname = symbolnameof!(T)) { 
    69     pragma(msg, "wrapped_struct: " ~ structname); 
    70     static const char[] _name = structname; 
    71     static bool _private = false; 
    72     alias T* wrapped_type; 
    73  
    74     static void member(M, size_t offset, char[] name) (char[] docstring="") { 
     65struct Member(char[] realname, char[] name=realname) { 
     66    static void call(T) () { 
    7567        pragma(msg, "struct.member: " ~ name); 
    7668        static PyGetSetDef empty = {null, null, null, null, null}; 
    77         alias wrapped_prop_list!(T*) list; 
     69        alias wrapped_prop_list!(T) list; 
    7870        list[length-1].name = (name ~ \0).ptr; 
    79         list[length-1].get = &wrapped_member!(T*, M, offset).get; 
    80         list[length-1].set = &wrapped_member!(T*, M, offset).set; 
    81         list[length-1].doc = (docstring ~ \0).ptr
     71        list[length-1].get = &wrapped_member!(T, realname).get; 
     72        list[length-1].set = &wrapped_member!(T, realname).set; 
     73        list[length-1].doc = ""
    8274        list[length-1].closure = null; 
    8375        list ~= empty; 
    84         wrapped_class_type!(T*).tp_getset = list.ptr; 
     76        wrapped_class_type!(T).tp_getset = list.ptr; 
    8577    } 
    86  
    87     alias wrapped_class!(T*, structname).def def; 
    88     alias wrapped_class!(T*, structname).static_def static_def; 
    89     alias wrapped_class!(T*, structname).prop prop; 
    90  
    91     version(Pyd_with_StackThreads) { 
    92  
    93     static void iter(iter_t) () { 
    94         PydStackContext_Ready(); 
    95         wrapped_class_type!(T*).tp_iter = &wrapped_iter!(T*, T.opApply, int function(iter_t)).iter; 
    96     } 
    97  
    98     alias wrapped_class!(T*, structname).alt_iter alt_iter; 
    99  
    100     } /*Pyd_with_StackThreads*/ 
    10178} 
    10279 
    103 alias pyd.class_wrap.finalize_class finalize_struct; 
     80alias wrap_class wrap_struct; 
    10481 
    105 /+ 
    106 void finalize_struct(SCT) (SCT sct, char[] modulename="") { 
    107     alias SCT.wrapped_type T; 
    108     alias wrapped_class_type!(T) type; 
    109     const char[] name = SCT._name; 
    110     pragma(msg, "finalize_struct: " ~ name); 
    111  
    112     assert(Pyd_Module_p(modulename) !is null, "Must initialize module before wrapping structs."); 
    113     char[] module_name = toString(PyModule_GetName(Pyd_Module_p(modulename))); 
    114     // Fill in missing values 
    115     type.ob_type      = PyType_Type_p(); 
    116     type.tp_basicsize = (wrapped_class_object!(T)).sizeof; 
    117     type.tp_doc       = name ~ " objects" ~ \0; 
    118     type.tp_flags     = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; 
    119     //type.tp_repr      = &wrapped_repr!(T).repr; 
    120     type.tp_methods   = wrapped_method_list!(T); 
    121     type.tp_name      = module_name ~ "." ~ name ~ \0; 
    122  
    123 } 
    124 +/