From 8ba97b8fb363d803b1f11a61bc38128f13dfa1b1 Mon Sep 17 00:00:00 2001 From: KirkMcDonald Date: Fri, 6 Jul 2007 04:38:29 +0000 Subject: [PATCH] Added advanced type conversion. Updated site CSS. git-svn-id: http://svn.dsource.org/projects/pyd/trunk@114 1df65b71-e716-0410-9316-ac55df2b1602 --- examples/testdll/test.py | 6 ++ examples/testdll/testdll.d | 19 +++++ html_doc/adv_conversion.html | 81 ++++++++++++++++++++ html_doc/basics.html | 29 ++++---- html_doc/celerid.html | 29 ++++---- html_doc/class_wrapping.html | 39 +++++----- html_doc/conversion.html | 29 ++++---- html_doc/credits.html | 29 ++++---- html_doc/except_wrapping.html | 29 ++++---- html_doc/func_wrapping.html | 29 ++++---- html_doc/index.html | 29 ++++---- html_doc/inherit.html | 29 ++++---- html_doc/install.html | 29 ++++---- html_doc/pyd.css | 19 ++--- html_doc/pydobject.html | 29 ++++---- html_doc/struct_wrapping.html | 29 ++++---- html_doc/vsboost.html | 29 ++++---- infrastructure/pyd/make_object.d | 123 ++++++++++++++++++++----------- raw_html/adv_conversion.html | 62 ++++++++++++++++ raw_html/class_wrapping.html | 10 +-- raw_html/header_template.html | 29 ++++---- 21 files changed, 493 insertions(+), 243 deletions(-) create mode 100644 html_doc/adv_conversion.html create mode 100644 raw_html/adv_conversion.html diff --git a/examples/testdll/test.py b/examples/testdll/test.py index 427cd04..026db58 100644 --- a/examples/testdll/test.py +++ b/examples/testdll/test.py @@ -76,6 +76,12 @@ def foo(): print +print "Testing custom conversion function" +print testdll.conv1() +testdll.conv2(20) + +print + print '--------' print 'SUCCESS' print '--------' diff --git a/examples/testdll/testdll.d b/examples/testdll/testdll.d index c33cb17..eba165b 100644 --- a/examples/testdll/testdll.d +++ b/examples/testdll/testdll.d @@ -90,6 +90,11 @@ struct S { } } + +struct A { + int i; +} + Foo spam(Foo f) { f.foo(); Foo g = new Foo(f.i + 10); @@ -100,8 +105,20 @@ void throws() { throw new Exception("Yay! An exception!"); } +A conv1() { + A a; + a.i = 12; + return a; +} +void conv2(A a) { + writefln(a.i); +} + extern(C) void PydMain() { pragma(msg, "testdll.PydMain"); + d_to_python(delegate int(A a) { return a.i; }); + python_to_d(delegate A(int i) { A a; a.i = i; return a; }); + def!(foo); // Python does not support function overloading. This allows us to wrap // an overloading function under a different name. Note that if the @@ -115,6 +132,8 @@ extern(C) void PydMain() { def!(func_test); def!(dg_test); def!(throws); + def!(conv1); + def!(conv2); module_init(); diff --git a/html_doc/adv_conversion.html b/html_doc/adv_conversion.html new file mode 100644 index 0000000..f8206d0 --- /dev/null +++ b/html_doc/adv_conversion.html @@ -0,0 +1,81 @@ + + + + + + Advanced type conversion + + + + + +
+ +

Advanced type conversion

+ +

It is frequently useful to extend Pyd's type conversion mechanisms. The usual way to do this is to wrap classes or structs. Pyd has two additional mechanisms for more complex situations.

+ +
+
void d_to_python(dg_t) (dg_t dg);
+
This allows the user to define a function for returning a D type to Python. The dg may be either a function pointer or a delegate. The argument to the function pointer is of the type to convert. The return type of the function pointer can be any convertible type.
+ +
void python_to_d(dg_t) (dg_t dg);
+
This allows the user to define a function for converting a Python object to a D type. The dg may be either a function pointer or a delegate. The argument to the function pointer can be any convertible type. The return type of the function pointer is the type to convert.
+
+ +

Conversion functions defined with either of the above functions only take effect if Pyd's regular type conversion mechanisms fail. This would usually happen if a wrapped function returns or has a parameter of some un-wrapped class or struct type.

+ +

Examples

+ +
import std.stdio;
+
+struct S {
+    int i;
+}
+
+S foo() {
+    S s;
+    s.i = 12;
+}
+void bar(S s) {
+    writefln(s);
+}
+
+extern (C) void PydMain() {
+    d_to_python(delegate int(S s) { return s.i; });
+    python_to_d(delegate S(int i) { S s; s.i = i; return s; });
+
+    def!(foo);
+    def!(bar);
+    module_init();
+}
+ +

And in Python:

+ +
>>> foo()
+12
+>>> bar(20)
+20
+ +
+ + + diff --git a/html_doc/basics.html b/html_doc/basics.html index 99abffb..b9b85da 100644 --- a/html_doc/basics.html +++ b/html_doc/basics.html @@ -9,19 +9,22 @@
diff --git a/html_doc/celerid.html b/html_doc/celerid.html index 47571ac..e2785dc 100644 --- a/html_doc/celerid.html +++ b/html_doc/celerid.html @@ -9,19 +9,22 @@
diff --git a/html_doc/class_wrapping.html b/html_doc/class_wrapping.html index 8f4d57e..09fecfb 100644 --- a/html_doc/class_wrapping.html +++ b/html_doc/class_wrapping.html @@ -9,19 +9,22 @@
@@ -149,13 +152,13 @@

Examples

>>> f = Foo() >>> f.i 0 ->>> f.i = 20 +>>> f.i = 20 >>> f.foo("Hello! i is ") Hello! i is 20 ->>> f = Foo(10, 10) +>>> f = Foo(10, 10) >>> f.i 20 ->>> g = Foo(30) +>>> g = Foo(30) >>> g.i 30 >>> e = f + g @@ -164,9 +167,9 @@

Examples

>>> # We can even subclass our D type >>> class MyFoo(Foo): ... def bar(self): -... print "Hey, i+3 is", self.i + 3 +... print "Hey, i+3 is", self.i + 3 ... ->>> h = MyFoo(3) +>>> h = MyFoo(3) >>> h.bar() Hey, i+3 is 6 >>> diff --git a/html_doc/conversion.html b/html_doc/conversion.html index 2085bbd..2c43e45 100644 --- a/html_doc/conversion.html +++ b/html_doc/conversion.html @@ -9,19 +9,22 @@
diff --git a/html_doc/credits.html b/html_doc/credits.html index 5bc0829..6be0dae 100644 --- a/html_doc/credits.html +++ b/html_doc/credits.html @@ -9,19 +9,22 @@
diff --git a/html_doc/except_wrapping.html b/html_doc/except_wrapping.html index c7d09d1..e41dce9 100644 --- a/html_doc/except_wrapping.html +++ b/html_doc/except_wrapping.html @@ -9,19 +9,22 @@
diff --git a/html_doc/func_wrapping.html b/html_doc/func_wrapping.html index 6f40afd..4974d4f 100644 --- a/html_doc/func_wrapping.html +++ b/html_doc/func_wrapping.html @@ -9,19 +9,22 @@
diff --git a/html_doc/index.html b/html_doc/index.html index bbc9eed..21c77af 100644 --- a/html_doc/index.html +++ b/html_doc/index.html @@ -9,19 +9,22 @@
diff --git a/html_doc/inherit.html b/html_doc/inherit.html index 87aaf2b..4c85567 100644 --- a/html_doc/inherit.html +++ b/html_doc/inherit.html @@ -9,19 +9,22 @@
diff --git a/html_doc/install.html b/html_doc/install.html index 937e229..afd879d 100644 --- a/html_doc/install.html +++ b/html_doc/install.html @@ -9,19 +9,22 @@
diff --git a/html_doc/pyd.css b/html_doc/pyd.css index 2dfe4a5..952e582 100644 --- a/html_doc/pyd.css +++ b/html_doc/pyd.css @@ -26,35 +26,36 @@ div#nav { width: 10em; } /* navbar links */ -a.nav { +div#nav a { text-decoration: none; font-weight: bold; +} +div#nav ul { + list-style-type: none; + padding: 0; + margin-bottom: 0; + margin-left: 1em; + text-indent: -1em; +} +a.nav { color: #f0f0f0; } a.nav:visited { - text-decoration: none; - font-weight: bold; color: #f0f0f0; } a.nav:hover { - text-decoration: none; color: black; background-color: #d8d8d8; } /* the current navbar link */ a.navcur { - text-decoration: none; - font-weight: bold; color: black; background-color: #d8d8d8; } a.navcur:visited { - text-decoration: none; - font-weight: bold; color: black; } a.navcur:hover { - text-decoration: none; color: #f0f0f0; background-color: #305880; } diff --git a/html_doc/pydobject.html b/html_doc/pydobject.html index 60cb638..60fa036 100644 --- a/html_doc/pydobject.html +++ b/html_doc/pydobject.html @@ -9,19 +9,22 @@
diff --git a/html_doc/struct_wrapping.html b/html_doc/struct_wrapping.html index b82562b..d76699c 100644 --- a/html_doc/struct_wrapping.html +++ b/html_doc/struct_wrapping.html @@ -9,19 +9,22 @@
diff --git a/html_doc/vsboost.html b/html_doc/vsboost.html index 7423d2a..147e1c2 100644 --- a/html_doc/vsboost.html +++ b/html_doc/vsboost.html @@ -9,19 +9,22 @@
diff --git a/infrastructure/pyd/make_object.d b/infrastructure/pyd/make_object.d index 971bfe6..fe965bf 100644 --- a/infrastructure/pyd/make_object.d +++ b/infrastructure/pyd/make_object.d @@ -45,7 +45,9 @@ import pyd.func_wrap; import pyd.exception; import pyd.lib_abstract : objToStr, - toString + toString, + ParameterTypeTuple, + ReturnType ; package template isArray(T) { @@ -67,6 +69,57 @@ package template isAA(T) { const bool isAA = is(typeof(T.init.values[0])[typeof(T.init.keys[0])] == T); } +class to_conversion_wrapper(dg_t) { + alias ParameterTypeTuple!(dg_t)[0] T; + alias ReturnType!(dg_t) Intermediate; + dg_t dg; + this(dg_t fn) { dg = fn; } + PyObject* opCall(T t) { + static if (is(Intermediate == PyObject*)) { + return dg(t); + } else { + return _py(dg(t)); + } + } +} +class from_conversion_wrapper(dg_t) { + alias ParameterTypeTuple!(dg_t)[0] Intermediate; + alias ReturnType!(dg_t) T; + dg_t dg; + this(dg_t fn) { dg = fn; } + T opCall(PyObject* o) { + static if (is(Intermediate == PyObject*)) { + return dg(o); + } else { + return dg(d_type!(Intermediate)(o)); + } + } +} + +template to_converter_registry(From) { + PyObject* delegate(From) dg=null; +} +template from_converter_registry(To) { + To delegate(PyObject*) dg=null; +} + +void d_to_python(dg_t) (dg_t dg) { + static if (is(dg_t == delegate) && is(ReturnType!(dg_t) == PyObject*)) { + to_converter_registry!(ParameterTypeTuple!(dg_t)[0]).dg = dg; + } else { + auto o = new to_conversion_wrapper!(dg_t)(dg); + to_converter_registry!(typeof(o).T).dg = &o.opCall; + } +} +void python_to_d(dg_t) (dg_t dg) { + static if (is(dg_t == delegate) && is(ParameterTypeTuple!(dg_t)[0] == PyObject*)) { + from_converter_registry!(ReturnType!(dg_t)).dg = dg; + } else { + auto o = new from_conversion_wrapper!(dg_t)(dg); + from_converter_registry!(typeof(o).T).dg = &o.opCall; + } +} + /** * Returns a new (owned) reference to a Python object based on the passed * argument. If the passed argument is a PyObject*, this "steals" the @@ -78,6 +131,12 @@ package template isAA(T) { * RuntimeError will be raised and this function will return null. */ PyObject* _py(T) (T t) { + static if (!is(T == PyObject*) && is(typeof(t is null))) { + if (t is null) { + Py_INCREF(Py_None); + return Py_None; + } + } static if (is(T : bool)) { PyObject* temp = (t) ? Py_True : Py_False; Py_INCREF(temp); @@ -93,23 +152,11 @@ PyObject* _py(T) (T t) { } else static if (is(T : cdouble)) { return PyComplex_FromDoubles(t.re, t.im); } else static if (is(T : char[])) { - if (t is null) { - Py_INCREF(Py_None); - return Py_None; - } return PyString_FromString((t ~ \0).ptr); } else static if (is(T : wchar[])) { - if (t is null) { - Py_INCREF(Py_None); - return Py_None; - } return PyUnicode_FromWideChar(t, t.length); // Converts any array (static or dynamic) to a Python list } else static if (isArray!(T) || isStaticArray!(T)) { - if (t is null) { - Py_INCREF(Py_None); - return Py_None; - } PyObject* lst = PyList_New(t.length); PyObject* temp; if (lst is null) return null; @@ -125,10 +172,6 @@ PyObject* _py(T) (T t) { return lst; // Converts any associative array to a Python dict } else static if (isAA!(T)) { - if (t is null) { - Py_INCREF(Py_None); - return Py_None; - } PyObject* dict = PyDict_New(); PyObject* ktemp, vtemp; int result; @@ -152,26 +195,20 @@ PyObject* _py(T) (T t) { } return dict; } else static if (is(T == delegate) || is(T == function)) { - if (t is null) { - Py_INCREF(Py_None); - return Py_None; - } PydWrappedFunc_Ready!(T)(); return WrapPyObject_FromObject(t); } else static if (is(T : PydObject)) { - if (t is null) { - Py_INCREF(Py_None); - return Py_None; - } PyObject* temp = t.ptr(); Py_INCREF(temp); return temp; - // Convert wrapped type of a PyObject* + // The function expects to be passed a borrowed reference and return an + // owned reference. Thus, if passed a PyObject*, this will increment the + // reference count. + } else static if (is(T : PyObject*)) { + Py_INCREF(t); + return t; + // Convert wrapped type to a PyObject* } else static if (is(T == class)) { - if (t is null) { - Py_INCREF(Py_None); - return Py_None; - } // But only if it actually is a wrapped type. :-) PyTypeObject** type = t.classinfo in wrapped_classes; if (type) { @@ -194,12 +231,10 @@ PyObject* _py(T) (T t) { } return WrapPyObject_FromObject(t); } - // The function expects to be passed a borrowed reference and return an - // owned reference. Thus, if passed a PyObject*, this will increment the - // reference count. - } else static if (is(T : PyObject*)) { - Py_INCREF(t); - return t; + } + // No conversion found, check runtime registry + if (to_converter_registry!(T).dg) { + return to_converter_registry!(T).dg(t); } PyErr_SetString(PyExc_RuntimeError, ("D conversion function _py failed with type " ~ objToStr(typeid(T))).ptr); return null; @@ -287,15 +322,15 @@ T d_type(T) (PyObject* o) { return WrapPyObject_AsObject!(T)(o); } // Otherwise, throw up an exception. - could_not_convert!(T)(o); + //could_not_convert!(T)(o); } else static if (is(T == struct)) { // struct by value if (is_wrapped!(T*) && PyObject_TypeCheck(o, &wrapped_class_type!(T*))) { return *WrapPyObject_AsObject!(T*)(o); - } else could_not_convert!(T)(o); + }// else could_not_convert!(T)(o); } else static if (is(typeof(*(T.init)) == struct)) { // pointer to struct if (is_wrapped!(T) && PyObject_TypeCheck(o, &wrapped_class_type!(T))) { return WrapPyObject_AsObject!(T)(o); - } else could_not_convert!(T)(o); + }// else could_not_convert!(T)(o); } else static if (is(T == delegate)) { // Get the original wrapped delegate out if this is a wrapped delegate if (is_wrapped!(T) && PyObject_TypeCheck(o, &wrapped_class_type!(T))) { @@ -303,13 +338,13 @@ T d_type(T) (PyObject* o) { // Otherwise, wrap the PyCallable with a delegate } else if (PyCallable_Check(o)) { return PydCallable_AsDelegate!(T)(o); - } else could_not_convert!(T)(o); + }// else could_not_convert!(T)(o); } else static if (is(T == function)) { // We can only make it a function pointer if we originally wrapped a // function pointer. if (is_wrapped!(T) && PyObject_TypeCheck(o, &wrapped_class_type!(T))) { return WrapPyObject_AsObject!(T)(o); - } else could_not_convert!(T)(o); + }// else could_not_convert!(T)(o); /+ } else static if (is(wchar[] : T)) { wchar[] temp; @@ -389,9 +424,13 @@ T d_type(T) (PyObject* o) { int res = PyObject_IsTrue(o); handle_exception(); return res == 1; - } else { + }/+ else { could_not_convert!(T)(o); + }+/ + if (from_converter_registry!(T).dg) { + return from_converter_registry!(T).dg(o); } + could_not_convert!(T)(o); } alias d_type!(Object) d_type_Object; diff --git a/raw_html/adv_conversion.html b/raw_html/adv_conversion.html new file mode 100644 index 0000000..eed14c5 --- /dev/null +++ b/raw_html/adv_conversion.html @@ -0,0 +1,62 @@ + + + + + + Advanced type conversion + + + +%(nav)s +
+ +

Advanced type conversion

+ +

It is frequently useful to extend Pyd's type conversion mechanisms. The usual way to do this is to wrap classes or structs. Pyd has two additional mechanisms for more complex situations.

+ +
+
void d_to_python(dg_t) (dg_t dg);
+
This allows the user to define a function for returning a D type to Python. The dg may be either a function pointer or a delegate. The argument to the function pointer is of the type to convert. The return type of the function pointer can be any convertible type.
+ +
void python_to_d(dg_t) (dg_t dg);
+
This allows the user to define a function for converting a Python object to a D type. The dg may be either a function pointer or a delegate. The argument to the function pointer can be any convertible type. The return type of the function pointer is the type to convert.
+
+ +

Conversion functions defined with either of the above functions only take effect if Pyd's regular type conversion mechanisms fail. This would usually happen if a wrapped function returns or has a parameter of some un-wrapped class or struct type.

+ +

Examples

+ +
import std.stdio;
+
+struct S {
+    int i;
+}
+
+S foo() {
+    S s;
+    s.i = 12;
+}
+void bar(S s) {
+    writefln(s);
+}
+
+extern (C) void PydMain() {
+    d_to_python(delegate int(S s) { return s.i; });
+    python_to_d(delegate S(int i) { S s; s.i = i; return s; });
+
+    def!(foo);
+    def!(bar);
+    module_init();
+}
+ +

And in Python:

+ +
>>> foo()
+12
+>>> bar(20)
+20
+ +
+ + + diff --git a/raw_html/class_wrapping.html b/raw_html/class_wrapping.html index 3bcad2c..05007ad 100644 --- a/raw_html/class_wrapping.html +++ b/raw_html/class_wrapping.html @@ -133,13 +133,13 @@

Examples

>>> f = Foo() >>> f.i 0 ->>> f.i = 20 +>>> f.i = 20 >>> f.foo("Hello! i is ") Hello! i is 20 ->>> f = Foo(10, 10) +>>> f = Foo(10, 10) >>> f.i 20 ->>> g = Foo(30) +>>> g = Foo(30) >>> g.i 30 >>> e = f + g @@ -148,9 +148,9 @@

Examples

>>> # We can even subclass our D type >>> class MyFoo(Foo): ... def bar(self): -... print "Hey, i+3 is", self.i + 3 +... print "Hey, i+3 is", self.i + 3 ... ->>> h = MyFoo(3) +>>> h = MyFoo(3) >>> h.bar() Hey, i+3 is 6 >>> diff --git a/raw_html/header_template.html b/raw_html/header_template.html index 6efd4cb..55ff8b6 100644 --- a/raw_html/header_template.html +++ b/raw_html/header_template.html @@ -1,16 +1,19 @@