ariovistus avatar ariovistus committed 1d0a092

allow python to skip d default arguments
add error message when an invalid keyword argument is given.

Comments (0)

Files changed (10)

examples/pyd_unittests/class_wrap.d

 import pyd.pyd, pyd.embedded;
 import deimos.python.pyport: Py_ssize_t;
+import std.exception;
 import std.stdio;
 
 shared static this() {
             StaticDef!(Bizzy2.a),
             StaticDef!(Bizzy2.b),
             StaticDef!(Bizzy2.c),
+            StaticDef!(Bizzy2.d),
+            Def!(Bizzy2.jj),
     )();
     wrap_class!(Bizzy3,
             ModuleName!"testing",
             Def!(Bizzy3.a),
             Def!(Bizzy3.b),
             Def!(Bizzy3.c),
+            Def!(Bizzy3.d),
     )();
     wrap_class!(Bizzy4,
             ModuleName!"testing",
             Repr!(Bizzy4.repr),
             Len!(),
     )();
+    wrap_class!(Bizzy5,
+            ModuleName!"testing",
+            Init!(int,double,string),
+            Def!(Bizzy5.a),
+    )();
     }, PyInitOrdering.After);
 
 }
     int m() { return _m; }
 
     this(int i, double d = 1.0, string s = "hi") {
-        writefln("shawarma i=%s, d=%s, s='%s'",i,d,s);
     }
 
     int a(int i){
 }
 
 class Bizzy2 {
+    int[] js;
     this(int[] i...) {
-        writeln("abooba",i);
+        js = i.dup;
+    }
+
+    int[] jj() {
+        return js;
     }
 
     static int a(int i, double d) {
         }
         return ret;
     }
+
+    static string d(int i, int j = 101, string k = "bizbar") {
+        import std.string;
+        return format("<%s, %s, '%s'>", i,j,k);
+    }
 }
 
 class Bizzy3{
     this(int i, int j) {
-        writefln("broomba(%s,%s)",i,j);
     }
 
     int a(int i, double d) {
         }
         return ret;
     }
+
+    string d(int i, int j = 102, string k = "bizbar") {
+        import std.string;
+        return format("<%s, %s, '%s'>", i,j,k);
+    }
+
 }
 
 class Bizzy4 {
     @property string repr() { return "cowabunga"; }
 }
 
+class Bizzy5 {
+    int i;
+    double d;
+    string s;
+    this(int i, double d = 1.0, string s = "hi") {
+        this.i = i;
+        this.d = d;
+        this.s = s;
+    }
+    string a() {
+        import std.string;
+        return format("<%s, %s, '%s'>", i,d,s);
+    }
+}
+
 unittest {
-    py_stmts(q"{
-#bizzy=Bizzy(1,2,3,4,5)
-#bizzy=Bizzy(d=7.1,i=4)
-bizzy=Bizzy(i=4)
-assert bizzy.a(1.0) == 13
-assert Bizzy.b(1.0) == 15
-assert repr(bizzy) == "bye"
-assert bizzy+1 == 2
-assert bizzy*1 == 3
-assert bizzy**1 == 4
-assert 1+bizzy == 5
-assert 19 in bizzy
-assert 0 not in bizzy 
-assert +bizzy == 55
-assert ~bizzy == 44
-assert bizzy > 1
-assert len(bizzy) == 401
-assert bizzy[1:2] == [1,2,3]
-bizzy += 2
-assert bizzy.m == 24
-bizzy %= 3
-assert bizzy.m == 36
-bizzy **= 4
-assert bizzy.m == 48
-bizzy[2] = 3.5
-assert bizzy.m == 3502
-bizzy[2:3] = 4.5
-assert bizzy.m == 4523
-assert bizzy(40.5) == 45023
-}", "testing");
+    InterpContext c = new InterpContext();
+    c.py_stmts("from testing import *");
+    c.py_stmts("bizzy = Bizzy(i=4)");
+    c.py_stmts("assert bizzy.a(1.0) == 13");
+    c.py_stmts("assert Bizzy.b(1.0) == 15");
+    c.py_stmts("assert repr(bizzy) == 'bye'");
+    c.py_stmts("assert bizzy+1 == 2");
+    c.py_stmts("assert bizzy*1 == 3");
+    c.py_stmts("assert bizzy**1 == 4");
+    c.py_stmts("assert 1+bizzy == 5");
+    c.py_stmts("assert 19 in bizzy");
+    c.py_stmts("assert 0 not in bizzy ");
+    c.py_stmts("assert +bizzy == 55");
+    c.py_stmts("assert ~bizzy == 44");
+    c.py_stmts("assert bizzy > 1");
+    c.py_stmts("assert len(bizzy) == 401");
+    c.py_stmts("assert bizzy[1:2] == [1,2,3]");
+    c.py_stmts("bizzy += 2");
+    c.py_stmts("assert bizzy.m == 24");
+    c.py_stmts("bizzy %= 3");
+    c.py_stmts("assert bizzy.m == 36");
+    c.py_stmts("bizzy **= 4");
+    c.py_stmts("assert bizzy.m == 48");
+    c.py_stmts("bizzy[2] = 3.5");
+    c.py_stmts("assert bizzy.m == 3502");
+    c.py_stmts("bizzy[2:3] = 4.5");
+    c.py_stmts("assert bizzy.m == 4523");
+    c.py_stmts("assert bizzy(40.5) == 45023");
 
-py_stmts(q"{
-bizzy = Bizzy2(4);
-bizzy = Bizzy2([4,5]);
-bizzy = Bizzy2(i=4);
-bizzy = Bizzy2(i=[4,5]);
-}", "testing");
+    c.py_stmts("bizzy = Bizzy2(4);");
+    c.py_stmts("assert bizzy.jj() == [4]");
+    c.py_stmts("bizzy = Bizzy2(4,5);");
+    c.py_stmts("assert bizzy.jj() == [4,5]");
+    c.py_stmts("bizzy = Bizzy2(i=4);");
+    c.py_stmts("assert bizzy.jj() == [4]");
+    c.py_stmts("bizzy = Bizzy2(i=[4,5]);");
+    c.py_stmts("assert bizzy.jj() == [4,5]");
 
-assert(py_eval!int("Bizzy2.a(7, 32.1)","testing") == 6427);
-assert(py_eval!int("Bizzy2.a(i=7, d=32.1)","testing") == 6427);
-assert(py_eval!int("Bizzy2.a(d=32.1,i=7)","testing") == 6427);
-assert(py_eval!int("Bizzy2.b(7, 32.1)","testing") == 32173);
-assert(py_eval!int("Bizzy2.b(d=32.1,i=7)","testing") == 32173);
-assert(py_eval!int("Bizzy2.b(i=7, d=32.1)","testing") == 32173);
-assert(py_eval!int("Bizzy2.b(7)","testing") == 3273);
-assert(py_eval!int("Bizzy2.b(i=7)","testing") == 3273);
-assert(py_eval!int("Bizzy2.c(7)","testing") == 7);
-assert(py_eval!int("Bizzy2.c(i=7)","testing") == 7);
-assert(py_eval!int("Bizzy2.c(i=[7])","testing") == 7);
-assert(py_eval!int("Bizzy2.c(7,5,6)","testing") == 657);
-assert(py_eval!int("Bizzy2.c(i=[7,5,6])","testing") == 657);
+    assert(c.py_eval!int("Bizzy2.a(7, 32.1)") == 6427);
+    assert(c.py_eval!int("Bizzy2.a(i=7, d=32.1)") == 6427);
+    assert(c.py_eval!int("Bizzy2.a(d=32.1,i=7)") == 6427);
+    assert(c.py_eval!int("Bizzy2.b(7, 32.1)") == 32173);
+    assert(c.py_eval!int("Bizzy2.b(d=32.1,i=7)") == 32173);
+    assert(c.py_eval!int("Bizzy2.b(i=7, d=32.1)") == 32173);
+    assert(c.py_eval!int("Bizzy2.b(7)") == 3273);
+    assert(c.py_eval!int("Bizzy2.b(i=7)") == 3273);
+    assert(c.py_eval!int("Bizzy2.c(7)") == 7);
+    assert(c.py_eval!int("Bizzy2.c(i=7)") == 7);
+    assert(c.py_eval!int("Bizzy2.c(i=[7])") == 7);
+    assert(c.py_eval!int("Bizzy2.c(7,5,6)") == 657);
+    assert(c.py_eval!int("Bizzy2.c(i=[7,5,6])") == 657);
+    assert(c.py_eval!string("Bizzy2.d(i=7, k='foobiz')") == "<7, 101, 'foobiz'>");
+    // unexpected arguments (s in this case) are invalid.
+    assert(collectException!PythonException(
+                c.py_eval!string("Bizzy2.d(i=7, s='foobiz')")));
 
-py_stmts(q"{
-bizzy = Bizzy3(1,2)
-}", "testing");
-assert(py_eval!int("bizzy.a(7, 32.1)","testing") == 3224);
-assert(py_eval!int("bizzy.a(i=7, d=32.1)","testing") == 3224);
-assert(py_eval!int("bizzy.a(d=32.1,i=7)","testing") == 3224);
-assert(py_eval!int("bizzy.b(7, 32.1)","testing") == 32244);
-assert(py_eval!int("bizzy.b(d=32.1,i=7)","testing") == 32244);
-assert(py_eval!int("bizzy.b(i=7, d=32.1)","testing") == 32244);
-assert(py_eval!int("bizzy.b(7)","testing") == 3344);
-assert(py_eval!int("bizzy.b(i=7)","testing") == 3344);
-assert(py_eval!int("bizzy.c(7)","testing") == 7);
-assert(py_eval!int("bizzy.c(i=7)","testing") == 7);
-assert(py_eval!int("bizzy.c(i=[7])","testing") == 7);
-assert(py_eval!int("bizzy.c(7,5,6)","testing") == 756);
-assert(py_eval!int("bizzy.c(i=[7,5,6])","testing") == 756);
+    c.py_stmts("bizzy = Bizzy3(1,2)");
+    assert(c.py_eval!int("bizzy.a(7, 32.1)") == 3224);
+    assert(c.py_eval!int("bizzy.a(i=7, d=32.1)") == 3224);
+    assert(c.py_eval!int("bizzy.a(d=32.1,i=7)") == 3224);
+    assert(c.py_eval!int("bizzy.b(7, 32.1)") == 32244);
+    assert(c.py_eval!int("bizzy.b(d=32.1,i=7)") == 32244);
+    assert(c.py_eval!int("bizzy.b(i=7, d=32.1)") == 32244);
+    assert(c.py_eval!int("bizzy.b(7)") == 3344);
+    assert(c.py_eval!int("bizzy.b(i=7)") == 3344);
+    assert(c.py_eval!int("bizzy.c(7)") == 7);
+    assert(c.py_eval!int("bizzy.c(i=7)") == 7);
+    assert(c.py_eval!int("bizzy.c(i=[7])") == 7);
+    assert(c.py_eval!int("bizzy.c(7,5,6)") == 756);
+    assert(c.py_eval!int("bizzy.c(i=[7,5,6])") == 756);
+    assert(c.py_eval!string("bizzy.d(i=7, k='foobiz')") == "<7, 102, 'foobiz'>");
 
-py_stmts(q"{
-bizzy = Bizzy4()
-}", "testing");
-assert(py_eval!int("bizzy.i","testing") == 4);
-py_stmts(q"{
-bizzy.i = 10
-}", "testing");
-assert(py_eval!int("bizzy.i","testing") == 10);
-assert(py_eval!int("len(bizzy)","testing") == 5);
-assert(py_eval!string("repr(bizzy)","testing") == "cowabunga");
+    c.py_stmts("bizzy = Bizzy4()");
+    assert(c.py_eval!int("bizzy.i") == 4);
+    c.py_stmts("bizzy.i = 10");
+    assert(c.py_eval!int("bizzy.i") == 10);
+    assert(c.py_eval!int("len(bizzy)") == 5);
+    assert(c.py_eval!string("repr(bizzy)") == "cowabunga");
+
+    c.py_stmts("boozy = Bizzy5(1)");
+    assert(c.py_eval!string("boozy.a()") == "<1, 1, 'hi'>");
+    c.py_stmts("boozy = Bizzy5(1, d=2.0)");
+    assert(c.py_eval!string("boozy.a()") == "<1, 2, 'hi'>");
+    c.py_stmts("boozy = Bizzy5(1, s='ten')");
+    assert(c.py_eval!string("boozy.a()") == "<1, 1, 'ten'>");
 
 }
 

examples/pyd_unittests/class_wrap3.d

 import pyd.pyd, pyd.embedded;
 import deimos.python.pyport: Py_ssize_t;
+import std.exception;
 import std.stdio;
 
 shared static this() {
             StaticDef!(Bizzy2.a),
             StaticDef!(Bizzy2.b),
             StaticDef!(Bizzy2.c),
+            StaticDef!(Bizzy2.d),
+            Def!(Bizzy2.jj),
     )();
     wrap_class!(Bizzy3,
             ModuleName!"testing",
             Def!(Bizzy3.a),
             Def!(Bizzy3.b),
             Def!(Bizzy3.c),
+            Def!(Bizzy3.d),
     )();
     wrap_class!(Bizzy4,
             ModuleName!"testing",
             Repr!(Bizzy4.repr),
             Len!(),
     )();
+    wrap_class!(Bizzy5,
+            ModuleName!"testing",
+            Init!(int,double,string),
+            Def!(Bizzy5.a),
+    )();
     }, PyInitOrdering.After);
 
 }
     int m() { return _m; }
 
     this(int i, double d = 1.0, string s = "hi") {
-        writefln("shawarma i=%s, d=%s, s='%s'",i,d,s);
     }
 
     int a(int i){
 }
 
 class Bizzy2 {
+    int[] js;
     this(int[] i...) {
-        writeln("abooba",i);
+        js = i.dup;
+    }
+
+    int[] jj() {
+        return js;
     }
 
     static int a(int i, double d) {
         }
         return ret;
     }
+
+    static string d(int i, int j = 101, string k = "bizbar") {
+        import std.string;
+        return format("<%s, %s, '%s'>", i,j,k);
+    }
 }
 
 class Bizzy3{
     this(int i, int j) {
-        writefln("broomba(%s,%s)",i,j);
     }
 
     int a(int i, double d) {
         }
         return ret;
     }
+
+    string d(int i, int j = 102, string k = "bizbar") {
+        import std.string;
+        return format("<%s, %s, '%s'>", i,j,k);
+    }
+
 }
 
 class Bizzy4 {
     @property string repr() { return "cowabunga"; }
 }
 
-unittest {
+class Bizzy5 {
+    int i;
+    double d;
+    string s;
+    this(int i, double d = 1.0, string s = "hi") {
+        this.i = i;
+        this.d = d;
+        this.s = s;
+    }
+    string a() {
+        import std.string;
+        return format("<%s, %s, '%s'>", i,d,s);
+    }
+}
+
+/+unittest {
     py_stmts(q"{
 #bizzy=Bizzy(1,2,3,4,5)
 #bizzy=Bizzy(d=7.1,i=4)
 assert(py_eval!int("len(bizzy)","testing") == 5);
 assert(py_eval!string("repr(bizzy)","testing") == "cowabunga");
 
+}+/
+unittest{
+    InterpContext c = new InterpContext();
+    c.py_stmts("from testing import *");
+    c.py_stmts("bizzy = Bizzy(i=4)");
+    c.py_stmts("assert bizzy.a(1.0) == 13");
+    c.py_stmts("assert Bizzy.b(1.0) == 15");
+    c.py_stmts("assert repr(bizzy) == 'bye'");
+    c.py_stmts("assert bizzy+1 == 2");
+    c.py_stmts("assert bizzy*1 == 3");
+    c.py_stmts("assert bizzy**1 == 4");
+    c.py_stmts("assert 1+bizzy == 5");
+    c.py_stmts("assert 19 in bizzy");
+    c.py_stmts("assert 0 not in bizzy ");
+    c.py_stmts("assert +bizzy == 55");
+    c.py_stmts("assert ~bizzy == 44");
+    c.py_stmts("assert bizzy > 1");
+    c.py_stmts("assert len(bizzy) == 401");
+    c.py_stmts("assert bizzy[1:2] == [1,2,3]");
+    c.py_stmts("bizzy += 2");
+    c.py_stmts("assert bizzy.m == 24");
+    c.py_stmts("bizzy %= 3");
+    c.py_stmts("assert bizzy.m == 36");
+    c.py_stmts("bizzy **= 4");
+    c.py_stmts("assert bizzy.m == 48");
+    c.py_stmts("bizzy[2] = 3.5");
+    c.py_stmts("assert bizzy.m == 3502");
+    c.py_stmts("bizzy[2:3] = 4.5");
+    c.py_stmts("assert bizzy.m == 4523");
+    c.py_stmts("assert bizzy(40.5) == 45023");
+
+    c.py_stmts("bizzy = Bizzy2(4);");
+    c.py_stmts("assert bizzy.jj() == [4]");
+    c.py_stmts("bizzy = Bizzy2(4,5);");
+    c.py_stmts("assert bizzy.jj() == [4,5]");
+    c.py_stmts("bizzy = Bizzy2(i=4);");
+    c.py_stmts("assert bizzy.jj() == [4]");
+    c.py_stmts("bizzy = Bizzy2(i=[4,5]);");
+    c.py_stmts("assert bizzy.jj() == [4,5]");
+
+    assert(c.py_eval!int("Bizzy2.a(7, 32.1)") == 6427);
+    assert(c.py_eval!int("Bizzy2.a(i=7, d=32.1)") == 6427);
+    assert(c.py_eval!int("Bizzy2.a(d=32.1,i=7)") == 6427);
+    assert(c.py_eval!int("Bizzy2.b(7, 32.1)") == 32173);
+    assert(c.py_eval!int("Bizzy2.b(d=32.1,i=7)") == 32173);
+    assert(c.py_eval!int("Bizzy2.b(i=7, d=32.1)") == 32173);
+    assert(c.py_eval!int("Bizzy2.b(7)") == 3273);
+    assert(c.py_eval!int("Bizzy2.b(i=7)") == 3273);
+    assert(c.py_eval!int("Bizzy2.c(7)") == 7);
+    assert(c.py_eval!int("Bizzy2.c(i=7)") == 7);
+    assert(c.py_eval!int("Bizzy2.c(i=[7])") == 7);
+    assert(c.py_eval!int("Bizzy2.c(7,5,6)") == 657);
+    assert(c.py_eval!int("Bizzy2.c(i=[7,5,6])") == 657);
+    assert(c.py_eval!string("Bizzy2.d(i=7, k='foobiz')") == "<7, 101, 'foobiz'>");
+    // unexpected arguments (s in this case) are invalid.
+    assert(collectException!PythonException(
+                c.py_eval!string("Bizzy2.d(i=7, s='foobiz')")));
+
+    c.py_stmts("bizzy = Bizzy3(1,2)");
+    assert(c.py_eval!int("bizzy.a(7, 32.1)") == 3224);
+    assert(c.py_eval!int("bizzy.a(i=7, d=32.1)") == 3224);
+    assert(c.py_eval!int("bizzy.a(d=32.1,i=7)") == 3224);
+    assert(c.py_eval!int("bizzy.b(7, 32.1)") == 32244);
+    assert(c.py_eval!int("bizzy.b(d=32.1,i=7)") == 32244);
+    assert(c.py_eval!int("bizzy.b(i=7, d=32.1)") == 32244);
+    assert(c.py_eval!int("bizzy.b(7)") == 3344);
+    assert(c.py_eval!int("bizzy.b(i=7)") == 3344);
+    assert(c.py_eval!int("bizzy.c(7)") == 7);
+    assert(c.py_eval!int("bizzy.c(i=7)") == 7);
+    assert(c.py_eval!int("bizzy.c(i=[7])") == 7);
+    assert(c.py_eval!int("bizzy.c(7,5,6)") == 756);
+    assert(c.py_eval!int("bizzy.c(i=[7,5,6])") == 756);
+    assert(c.py_eval!string("bizzy.d(i=7, k='foobiz')") == "<7, 102, 'foobiz'>");
+
+    c.py_stmts("bizzy = Bizzy4()");
+    assert(c.py_eval!int("bizzy.i") == 4);
+    c.py_stmts("bizzy.i = 10");
+    assert(c.py_eval!int("bizzy.i") == 10);
+    assert(c.py_eval!int("len(bizzy)") == 5);
+    assert(c.py_eval!string("repr(bizzy)") == "cowabunga");
+
+    c.py_stmts("boozy = Bizzy5(1)");
+    assert(c.py_eval!string("boozy.a()") == "<1, 1, 'hi'>");
+    c.py_stmts("boozy = Bizzy5(1, d=2.0)");
+    assert(c.py_eval!string("boozy.a()") == "<1, 2, 'hi'>");
+    c.py_stmts("boozy = Bizzy5(1, s='ten')");
+    assert(c.py_eval!string("boozy.a()") == "<1, 1, 'ten'>");
+
 }
 
 void main() {}

examples/pyd_unittests/def.d

 import pyd.pyd, pyd.embedded;
+import std.string;
 
 int a(int i) {
     return 10;
     return ret;
 }
 
+string a4(string s1, int i1, string s2 = "friedman", int i2 = 4, string s3 = "jefferson") {
+    return std.string.format("<'%s', %s, '%s', %s, '%s'>", s1,i1,s2,i2,s3);
+}
+
 static this() {
     def!(a,int function(double), ModuleName!"testing")(); 
     def!(a2, int function(int,double,), ModuleName!"testing")(); 
     def!(a3, int function(int[]), ModuleName!"testing")(); 
+    def!(a4, ModuleName!"testing")(); 
     on_py_init({
             add_module!(ModuleName!"testing")();
     });
 }
 
 unittest{
-    assert(py_eval!int("a(1.0)","testing") == 20);
-    assert(py_eval!int("a2(4,2.1)","testing") == 214);
-    assert(py_eval!int("a2(4)","testing") == 454);
-    assert(py_eval!int("a2(i=4)","testing") == 454);
-    assert(py_eval!int("a3(4)","testing") == 46);
-    assert(py_eval!int("a3(i=4)","testing") == 46);
-    assert(py_eval!int("a3(4,3)","testing") == 49);
-    assert(py_eval!int("a3(i=[4,3])","testing") == 49);
+    InterpContext c = new InterpContext();
+    c.py_stmts("from testing import *");
+
+    assert(c.py_eval!int("a(1.0)") == 20);
+    assert(c.py_eval!int("a2(4,2.1)") == 214);
+    assert(c.py_eval!int("a2(4)") == 454);
+    assert(c.py_eval!int("a2(i=4)") == 454);
+    assert(c.py_eval!int("a3(4)") == 46);
+    assert(c.py_eval!int("a3(i=4)") == 46);
+    assert(c.py_eval!int("a3(4,3)") == 49);
+    assert(c.py_eval!int("a3(i=[4,3])") == 49);
+    assert(c.py_eval!string("a4('hi',2,s3='zi')") == 
+            "<'hi', 2, 'friedman', 4, 'zi'>");
+
+
 }
 
 void main() {}

examples/pyd_unittests/def3.d

     foreach(_i; i) ret += _i;
     return ret;
 }
+string a4(string s1, int i1, string s2 = "friedman", int i2 = 4, string s3 = "jefferson") {
+    return std.string.format("<'%s', %s, '%s', %s, '%s'>", s1,i1,s2,i2,s3);
+}
 
 static this() {
     def!(a,int function(double), ModuleName!"testing")(); 
     def!(a2, int function(int,double,), ModuleName!"testing")(); 
     def!(a3, int function(int[]), ModuleName!"testing")(); 
+    def!(a4, ModuleName!"testing")(); 
     on_py_init({
             add_module!(ModuleName!"testing")();
     });
 }
 
 unittest{
-    assert(py_eval!int("a(1.0)","testing") == 20);
-    assert(py_eval!int("a2(4,2.1)","testing") == 214);
-    assert(py_eval!int("a2(4)","testing") == 454);
-    assert(py_eval!int("a2(i=4)","testing") == 454);
-    assert(py_eval!int("a3(4)","testing") == 46);
-    assert(py_eval!int("a3(i=4)","testing") == 46);
-    assert(py_eval!int("a3(4,3)","testing") == 49);
-    assert(py_eval!int("a3(i=[4,3])","testing") == 49);
+    InterpContext c = new InterpContext();
+    c.py_stmts("from testing import *");
+    c.py_stmts("print (a4('hi',2,s3='zi'))");
+
+    assert(c.py_eval!int("a(1.0)") == 20);
+    assert(c.py_eval!int("a2(4,2.1)") == 214);
+    assert(c.py_eval!int("a2(4)") == 454);
+    assert(c.py_eval!int("a2(i=4)") == 454);
+    assert(c.py_eval!int("a3(4)") == 46);
+    assert(c.py_eval!int("a3(i=4)") == 46);
+    assert(c.py_eval!int("a3(4,3)") == 49);
+    assert(c.py_eval!int("a3(i=[4,3])") == 49);
+    assert(c.py_eval!string("a4('hi',2,s3='zi')") == 
+            "<'hi', 2, 'friedman', 4, 'zi'>");
 }
 
 void main() {}

examples/pyd_unittests/func_wrap.d

     }
 }
 
+class Foo5{
+    this(int i, double j = 1.0, double k = 4.5, double L = 6.325){
+    }
+}
+
 unittest {
     static assert(getparams!foo1 == "int i, int j");
     static assert(getparams!foo2 == "int i, double j = 2");
     //pragma(msg, typeof(fn));
     //fn(1);
     static assert(minArgs!(call_ctor!(Foo2, Init!(int, double)).func) == 1);
+    auto fn2 = &call_ctor!(Foo5, Init!(int, double, double, double)).func;
+    static assert(minArgs!(call_ctor!(Foo5, Init!(int, double, double, double)).func) == 1);
 
     static assert(minArgs!foo1 == 2);
     static assert(minArgs!foo2 == 1);
     assert(supportsNArgs!foo5(2));
     assert(!supportsNArgs!foo5(3));
 
+    assert(!supportsNArgs!(Foo5.__ctor)(0));
+    assert(supportsNArgs!(Foo5.__ctor)(1));
+    assert(supportsNArgs!(Foo5.__ctor)(2));
+    assert(supportsNArgs!(Foo5.__ctor)(3));
+    assert(supportsNArgs!(Foo5.__ctor)(4));
+    assert(!supportsNArgs!(Foo5.__ctor)(5));
 }
 
 

infrastructure/pyd/class_wrap.d

 }
 
 //
-template wrapped_get(T, Parts) {
+template wrapped_get(string fname, T, Parts) {
     // A generic wrapper around a "getter" property.
     extern(C)
     PyObject* func(PyObject* self, void* closure) {
         // method_wrap already catches exceptions
-        return method_wrap!(T, Parts.GetterFn).func(self, null, null);
+        return method_wrap!(T, Parts.GetterFn, fname).func(self, null, null);
     }
 }
 
 //
-template wrapped_set(T, Parts) {
+template wrapped_set(string fname, T, Parts) {
     // A generic wrapper around a "setter" property.
     extern(C)
     int func(PyObject* self, PyObject* value, void* closure) {
         scope(exit) Py_DECREF(temp_tuple);
         Py_INCREF(value);
         PyTuple_SetItem(temp_tuple, 0, value);
-        PyObject* res = method_wrap!(T, Parts.SetterFn).func(self, temp_tuple, null);
+        PyObject* res = method_wrap!(T, Parts.SetterFn, fname).func(self, temp_tuple, null);
         // If we get something back, we need to DECREF it.
         if (res) Py_DECREF(res);
         // If we don't, propagate the exception
 
 //enum ParamType { Def, StaticDef, Property, Init, Parent, Hide, Iter, AltIter }
 struct DoNothing {
-    static void call(T) () {}
+    static void call(string classname, T) () {}
 }
 
 /**
     enum min_args = minArgs!(func);
     enum bool needs_shim = false;
 
-    static void call(T) () {
+    static void call(string classname, T) () {
         pragma(msg, "class.def: " ~ name);
         static PyMethodDef empty = { null, null, 0, null };
         alias wrapped_method_list!(T) list;
         list[$-1].ml_name = (name ~ "\0").ptr;
-        list[$-1].ml_meth = cast(PyCFunction) &method_wrap!(T, func).func;
+        list[$-1].ml_meth = cast(PyCFunction) &method_wrap!(T, func, classname ~ "." ~ name).func;
         list[$-1].ml_flags = METH_VARARGS | METH_KEYWORDS;
         list[$-1].ml_doc = (docstring~"\0").ptr;
         list ~= empty;
     alias fn_t func_t;
     enum funcname = name;
     enum bool needs_shim = false;
-    static void call(T) () {
+    static void call(string classname, T) () {
         pragma(msg, "class.static_def: " ~ name);
         static PyMethodDef empty = { null, null, 0, null };
         alias wrapped_method_list!(T) list;
         list[$-1].ml_name = (name ~ "\0").ptr;
-        list[$-1].ml_meth = cast(PyCFunction) &function_wrap!func.func;
+        list[$-1].ml_meth = cast(PyCFunction) &function_wrap!(func, classname ~ "." ~ name).func;
         list[$-1].ml_flags = METH_VARARGS | METH_STATIC | METH_KEYWORDS;
         list[$-1].ml_doc = (docstring~"\0").ptr;
         list ~= empty;
         enum realname = __traits(identifier, fn);
         enum funcname = pyname;
         enum bool needs_shim = false;
-        static void call(T) () {
+        static void call(string classname, T) () {
             pragma(msg, "class.prop: " ~ pyname);
             static PyGetSetDef empty = { null, null, null, null, null };
             wrapped_prop_list!(T)[$-1].name = (pyname ~ "\0").dup.ptr;
             static if (countUntil(parts.mode, "r") != -1) {
                 wrapped_prop_list!(T)[$-1].get =
-                    &wrapped_get!(T, parts).func;
+                    &wrapped_get!(classname ~ "." ~ pyname, T, parts).func;
             }
             static if (countUntil(parts.mode, "w") != -1) {
                 wrapped_prop_list!(T)[$-1].set =
-                    &wrapped_set!(T, parts).func;
+                    &wrapped_set!(classname ~ "." ~ pyname,T, parts).func;
             }
             wrapped_prop_list!(T)[$-1].doc = (docstring~"\0").dup.ptr;
             wrapped_prop_list!(T)[$-1].closure = null;
 struct Repr(alias _fn) {
     alias def_selector!(_fn, string function()).FN fn;
     enum bool needs_shim = false;
-    static void call(T)() {
+    static void call(string classname, T)() {
         alias wrapped_class_type!(T) type;
         type.tp_repr = &wrapped_repr!(T, fn).repr;
     }
                     T.stringof, CtorParams.stringof));
         alias VOverloads[0] FN;
     }
-    static void call(T)() {
+    static void call(string classname, T)() {
     }
     template shim(size_t i, T) {
         enum params = getparams!(Inner!T.FN);
         } else static assert(false, "Cannot get operator overload");
     }
 
-    static void call(T)() {
+    static void call(string classname, T)() {
         // can't handle __op__ __rop__ pairs here
     }
 
             alias C.opUnary!(op) FN;
         } else static assert(false, "Cannot get operator overload");
     }
-    static void call(T)() {
+    static void call(string classname, T)() {
         alias wrapped_class_type!T type;
         enum slot = unaryslots[op];
         mixin(autoInitializeMethods());
             alias C.opOpAssign!(_op,rhs_t) FN;
         } else static assert(false, "Cannot get operator assignment overload");
     }
-    static void call(T)() {
+    static void call(string classname, T)() {
         alias wrapped_class_type!T type;
         enum slot = binaryslots[op];
         mixin(autoInitializeMethods());
             alias Overloads1[0] FN;
         }
     }
-    static void call(T)() {
+    static void call(string classname, T)() {
         alias wrapped_class_type!T type;
         type.tp_richcompare = &rich_opcmp_wrap!(T, Inner!T.FN).func;
     }
                     Format!("cannot get a handle on %s.opIndex", C.stringof));
         }
     }
-    static void call(T)() {
+    static void call(string classname, T)() {
         /*
         alias wrapped_class_type!T type;
         enum slot = "type.tp_as_mapping.mp_subscript";
                     Format!("cannot get a handle on %s.opIndexAssign", C.stringof));
         }
     }
-    static void call(T)() {
+    static void call(string classname, T)() {
         /*
         alias wrapped_class_type!T type;
         enum slot = "type.tp_as_mapping.mp_ass_subscript";
                         C.stringof));
         }
     }
-    static void call(T)() {
+    static void call(string classname, T)() {
         /*
         alias wrapped_class_type!T type;
         enum slot = "type.tp_as_sequence.sq_slice";
                         C.stringof));
         }
     }
-    static void call(T)() {
+    static void call(string classname, T)() {
         /*
         alias wrapped_class_type!T type;
         enum slot = "type.tp_as_sequence.sq_ass_slice";
                 Format!("%s.%s: cannot choose between %s", T.stringof, nom,
                     VOverloads.stringof));
     }
-    static void call(T)() {
+    static void call(string classname, T)() {
         alias wrapped_class_type!T type;
         alias Inner!T.FN fn;
         type.tp_call = &opcall_wrap!(T, Inner!T.FN).func;
                 Format!("%s.%s: cannot choose between %s", T.stringof, nom,
                     VOverloads.stringof));
     }
-    static void call(T)() {
+    static void call(string classname, T)() {
         alias wrapped_class_type!T type;
         enum slot = "type.tp_as_sequence.sq_length";
         mixin(autoInitializeMethods());
     }
 }
 
-struct Constructors(Ctors...) {
+struct Constructors(string classname, Ctors...) {
     enum bool needs_shim = true;
 
     static void call(T, Shim)() {
         alias wrapped_class_type!T type;
         static if(Ctors.length) {
-            type.tp_init = &wrapped_ctors!(T, Shim, Ctors).func;
+            type.tp_init = &wrapped_ctors!(classname, T, Shim, Ctors).func;
         }else {
             // If a ctor wasn't supplied, try the default.
             // If the default ctor isn't available, and no ctors were supplied,
 /*
 Params: each param is a Type which supports the interface
 
-Param.needs_shim == false => Param.call!(T)
+Param.needs_shim == false => Param.call!(pyclassname, T)
 or 
-Param.needs_shim == true => Param.call!(T, Shim)
+Param.needs_shim == true => Param.call!(pyclassname,T, Shim)
 
     performs appropriate mutations to the PyTypeObject
 
 
         foreach (param; Params) {
             static if (param.needs_shim) {
-                param.call!(T, shim_class)();
+                param.call!(name, T, shim_class)();
             } else {
-                param.call!(T)();
+                param.call!(name,T)();
             }
         }
 
         //////////////////////////
         // Constructor wrapping //
         //////////////////////////
-        Constructors!(Filter!(IsInit, Params)).call!(T, shim_class)();
+        Constructors!(name, Filter!(IsInit, Params)).call!(T, shim_class)();
 
         //////////////////////////
         // Iterator wrapping    //

infrastructure/pyd/ctor_wrap.d

 //import std.stdio;
 // This template accepts a tuple of function pointer types, which each describe
 // a ctor of T, and  uses them to wrap a Python tp_init function.
-template wrapped_ctors(T,Shim, C ...) {
+template wrapped_ctors(string classname, T,Shim, C ...) {
     //alias shim_class T;
     alias wrapped_class_object!(T) wrap_object;
 
             }
             // find another Ctor
             foreach(i, init; C) {
-                if (supportsNArgs!(init.Inner!T.FN)(len) && 
-                    (kwlen <= 0 || hasAllNamedArgs!(init.Inner!T.FN)(arglen,kwargs))) {
+                if (supportsNArgs!(init.Inner!T.FN)(len)) {
                     alias call_ctor!(T, init).func fn;
-                    T t = applyPyTupleToAlias!(fn)(args, kwargs);
+                    T t = applyPyTupleToAlias!(fn, classname)(args, kwargs);
                     if (t is null) {
                         PyErr_SetString(PyExc_RuntimeError, "Class ctor redirect didn't return a class instance!");
                         return -1;

infrastructure/pyd/def.d

     PyMethodDef[]* list = &module_methods[args.modulename];
 
     (*list)[$-1].ml_name = (args.pyname ~ "\0").dup.ptr;
-    (*list)[$-1].ml_meth = cast(PyCFunction) &function_wrap!fn.func;
+    (*list)[$-1].ml_meth = cast(PyCFunction) &function_wrap!(fn,args.pyname).func;
     (*list)[$-1].ml_flags = METH_VARARGS | METH_KEYWORDS;
     (*list)[$-1].ml_doc = (args.docstring ~ "\0").dup.ptr;
     (*list) ~= empty;

infrastructure/pyd/func_wrap.d

 module pyd.func_wrap;
 
 import deimos.python.Python;
+import std.algorithm: max;
 import std.metastrings;
 import std.exception: enforce;
 import std.range;
 
 // Calls callable alias fn with PyTuple args.
 // kwargs may be null, args may not
-ReturnType!fn applyPyTupleToAlias(alias fn)(PyObject* args, PyObject* kwargs) {
+ReturnType!fn applyPyTupleToAlias(alias fn, string fname)(PyObject* args, PyObject* kwargs) {
     alias ParameterTypeTuple!fn T;
     enum size_t MIN_ARGS = minArgs!fn;
     alias maxArgs!fn MaxArgs;
     Py_ssize_t argCount = 0;
     // This can make it more convenient to call this with 0 args.
     if(kwargs !is null && PyObject_Length(kwargs) > 0) {
-        args = arrangeNamedArgs!(fn)(args, kwargs);
+        args = arrangeNamedArgs!(fn,fname)(args, kwargs);
         Py_ssize_t newlen = PyObject_Length(args);
         argsoverwrote = true;
     }
     foreach(i, arg; t) {
         enum size_t argNum = i+1;
         static if(MaxArgs.vstyle == Variadic.no) {
+            alias ParameterDefaultValueTuple!fn Defaults;
             if (i < argCount) {
                 auto bpobj =  PyTuple_GetItem(args, i);
-                auto  pobj = Py_XINCREF(bpobj);
-                t[i] = python_to_d!(typeof(arg))(pobj);
-                Py_DECREF(pobj);
+                if(bpobj) {
+                    auto pobj = Py_XINCREF(bpobj);
+                    t[i] = python_to_d!(typeof(arg))(pobj);
+                    Py_DECREF(pobj);
+                }else{
+                    static if(!is(Defaults[i] == void)) {
+                        t[i] = Defaults[i];
+                    }else{
+                        // should never happen
+                        enforce(0, "python non-keyword arg is NULL!");
+                    }
+                }
             }
             static if (argNum >= MIN_ARGS && 
                     (!MaxArgs.hasMax || argNum <= MaxArgs.max)) {
 
 // wraps applyPyTupleToAlias to return a PyObject*
 // kwargs may be null, args may not.
-PyObject* pyApplyToAlias(alias fn) (PyObject* args, PyObject* kwargs) {
+PyObject* pyApplyToAlias(alias fn, string fname) (PyObject* args, PyObject* kwargs) {
     static if (is(ReturnType!fn == void)) {
-        applyPyTupleToAlias!fn(args, kwargs);
+        applyPyTupleToAlias!(fn,fname)(args, kwargs);
         return Py_INCREF(Py_None());
     } else {
-        return d_to_python( applyPyTupleToAlias!fn(args, kwargs) );
+        return d_to_python( applyPyTupleToAlias!(fn,fname)(args, kwargs) );
     }
 }
 
 }
 
 // Wraps a function alias with a PyCFunctionWithKeywords.
-template function_wrap(alias real_fn) {
+template function_wrap(alias real_fn, string fnname) {
     alias ParameterTypeTuple!real_fn Info;
     enum size_t MAX_ARGS = Info.length;
     alias ReturnType!real_fn RT;
     extern (C)
     PyObject* func(PyObject* self, PyObject* args, PyObject* kwargs) {
         return exception_catcher(delegate PyObject*() {
-            return pyApplyToAlias!real_fn(args, kwargs);
+            return pyApplyToAlias!(real_fn,fnname)(args, kwargs);
         });
     }
 }
 
 // Wraps a member function alias with a PyCFunction.
 // func's args and kwargs may each be null.
-template method_wrap(C, alias real_fn) {
+template method_wrap(C, alias real_fn, string fname) {
     alias ParameterTypeTuple!real_fn Info;
     enum size_t ARGS = Info.length;
     alias ReturnType!real_fn RT;
                 PyTuple_SetItem(self_and_args, i+1, pobj);
             }
             alias memberfunc_to_func!(C,real_fn).func func;
-            return pyApplyToAlias!func(self_and_args, kwargs);
+            return pyApplyToAlias!(func,fname)(self_and_args, kwargs);
         });
     }
 }
     }
 }
 
-
-bool hasAllNamedArgs(alias fn)(Py_ssize_t arglen, PyObject* kwargs) {
-    //static if(variadicFunctionStyle!fn != Variadic.no) return true;
+PyObject* arrangeNamedArgs(alias fn, string fname)(PyObject* args, PyObject* kwargs) {
     alias ParameterIdentifierTuple!fn ids;
-    string[] sids = new string[](ids.length);
-    bool[] flags = new bool[](ids.length);
-    foreach(i,id; ids) sids[i] = id;
-    PyObject* keys = PyDict_Keys(kwargs);
-    Py_ssize_t len = PyObject_Length(keys);
-FOREACH: 
-    foreach(i; 0 .. len) {
-        auto pobj = PySequence_GetItem(keys, i);
-        enforce(pobj != null);
-        string name = python_to_d!string(pobj);
-        Py_DECREF(pobj);
-        foreach(j,id; ids) {
-            if(id == name && j >= arglen) {
-                enforce(!flags[j]); // why would this happen? no idea.
-                flags[j] = true;
-                continue FOREACH;
+    string[] allfnnames = new string[](ids.length);
+    size_t[string] allfnnameset;
+    foreach(i,id; ids) {
+        allfnnames[i] = id;
+        allfnnameset[id] = i;
+    }
+    alias variadicFunctionStyle!fn vstyle;
+    size_t firstDefaultValueIndex = ids.length;
+    static if(vstyle == Variadic.no) {
+        alias ParameterDefaultValueTuple!fn Defaults;
+        foreach(i, v; Defaults) {
+            static if(!is(v == void)) {
+                firstDefaultValueIndex = i;
+                break;
             }
         }
-        return false;
     }
-    size_t firstmissing = -1;
-    foreach(k,f; flags[arglen .. $]) {
-        if(f && firstmissing != -1) {
-            return false;
-            //enforce(false, format("missing argument '%s'", sids[firstmissing]));
-        }
-        if(!f && firstmissing == -1) {
-            firstmissing = k + arglen;
-        }
-    }
-    return true;
-}
-
-
-PyObject* arrangeNamedArgs(alias fn)(PyObject* args, PyObject* kwargs) {
-    alias ParameterIdentifierTuple!fn ids;
-    string[] allfnnames = new string[](ids.length);
-    foreach(i,id; ids) allfnnames[i] = id;
 
     Py_ssize_t arglen = PyObject_Length(args);
     enforce(arglen != -1);
     Py_ssize_t kwarglen = PyObject_Length(kwargs);
     enforce(kwarglen != -1);
-    auto allargs = PyTuple_New(arglen+kwarglen);
+    // variadic args might give us a count greater than ids.length
+    // (but in that case there should be no kwargs)
+    auto allargs = PyTuple_New(max(ids.length, arglen+kwarglen));
 
     foreach(i; 0 .. arglen) {
         auto pobj = Py_XINCREF(PyTuple_GetItem(args, i));
         PyTuple_SetItem(allargs, i, pobj);
     }
+    PyObject* keys = PyDict_Keys(kwargs);
+    enforce(keys);
+    for(size_t _n = 0; _n < kwarglen; _n++) {
+        PyObject* pkey = PySequence_GetItem(keys, _n);
+        auto name = python_to_d!string(pkey);
+        if(name !in allfnnameset) {
+            enforce(false, format("%s() got an unexpected keyword argument '%s'",fname, name));
+            
 
-    foreach(n,name; allfnnames[arglen .. arglen + kwarglen]) {
-        auto key = d_to_python(name);
-        auto bval = PyDict_GetItem(kwargs, key);
-        auto val = Py_XINCREF(bval);
-        PyTuple_SetItem(allargs, arglen+n, val);
+        }
+        size_t n = allfnnameset[name];
+        auto bval = PyDict_GetItem(kwargs, pkey);
+        if(bval) {
+            auto val = Py_XINCREF(bval);
+            PyTuple_SetItem(allargs, n, val);
+        }else if(vstyle == Variadic.no && n >= firstDefaultValueIndex) {
+            // ok, we can get the default value 
+        }else{
+            enforce(false, format("argument '%s' is NULL! <%s, %s, %s, %s>", 
+                        name, n, firstDefaultValueIndex, ids.length, 
+                        vstyle == Variadic.no));
+        }
     }
+    Py_DECREF(keys);
     return allargs;
 }
 

infrastructure/pyd/struct_wrap.d

 
 template _Member(string realname, string pyname, string mode, string docstring) {
     static const bool needs_shim = false;
-    static void call(T) () {
+    static void call(string classname, T) () {
         pragma(msg, "struct.member: " ~ pyname);
         static PyGetSetDef empty = {null, null, null, null, null};
         alias wrapped_prop_list!(T) list;
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.