From a771885919aac68adbca31fa3fa8d424b59559e1 Mon Sep 17 00:00:00 2001 From: KirkMcDonald Date: Sat, 16 Dec 2006 06:54:02 +0000 Subject: [PATCH] Docstring support git-svn-id: http://svn.dsource.org/projects/pyd/trunk@59 1df65b71-e716-0410-9316-ac55df2b1602 --- html_doc/basics.html | 2 +- html_doc/class_wrapping.html | 11 ++++++----- html_doc/func_wrapping.html | 3 ++- html_doc/struct_wrapping.html | 12 ++++++------ infrastructure/pyd/class_wrap.d | 20 ++++++++++---------- infrastructure/pyd/def.d | 16 ++++++++-------- infrastructure/pyd/struct_wrap.d | 4 ++-- 7 files changed, 35 insertions(+), 33 deletions(-) diff --git a/html_doc/basics.html b/html_doc/basics.html index e2f9d46..fdc580e 100644 --- a/html_doc/basics.html +++ b/html_doc/basics.html @@ -48,7 +48,7 @@

Module basics

The module_init function has the following form:

-

PyObject* module_init(char[] name);

+

PyObject* module_init(char[] name, char[] docstring="");

It does little more than call Py_InitModule and return the new module object. This object is also available via the Pyd_Module_p property once you've called module_init.

diff --git a/html_doc/class_wrapping.html b/html_doc/class_wrapping.html index 223e73f..9ccee7d 100644 --- a/html_doc/class_wrapping.html +++ b/html_doc/class_wrapping.html @@ -38,18 +38,19 @@

Class wrapping

To expose the constructors, methods, and properties of the class, wrapped_class provides a series of template member functions.

-
static void def(alias fn, char[] name = symbolnameof!(fn), fn_t = typeof(&fn)) ();
+
static void def(alias fn, char[] name = symbolnameof!(fn), fn_t = typeof(&fn)) (char[] docstring="");
This wraps a method of the class. It functions exactly like the def function used to wrap regular functions, with one very important difference: There is no support for default arguments. (This is a side-effect of the fact that you cannot call an alias of a method in D, and delegates do not understand default arguments.)
-
static void static_def(alias fn, char[] name = symbolnameof!(fn), fn_t = typeof(&fn), uint MIN_ARGS = minArgs!(fn)) ();
+
static void static_def(alias fn, char[] name = symbolnameof!(fn), fn_t = typeof(&fn), uint MIN_ARGS = minArgs!(fn)) (char[] docstring="");
This wraps a static member function of the class. It also functions exactly like the def function used to wrap regular functions, and even includes support for default arguments.
-
static void prop(alias fn, char[] name = symbolnameof!(fn), bool RO = false) ();
+
static void prop(alias fn, char[] name = symbolnameof!(fn), bool RO = false) (char[] docstring="");
This wraps a property. See the examples below for more details.
  • fn is the name of the property. prop will automatically attempt to wrap both the "get" and "set" forms of the property, unless RO is specified.
  • name is the name of the property as it will appear in Python. As with def, prop will attempt to derive this automatically.
  • RO specifies whether this is a read-only property. If true, it will only wrap the "get" form of the property. If false, it will wrap both the "get" and "set" forms. (This is a little hackish, and I will probably try to make this detection more automatic in the future. It also means it cannot support a property that only has a "set" form.)
  • +
  • docstring is the property's docstring. As usual, note that this is a regular function argument, and not a template argument.
@@ -59,14 +60,14 @@

Class wrapping

static void iter(iter_t) ();
This allows the user to specify a different overload of opApply than the default. (The default is always the one that is lexically first.) The iter_t argument should be the type of the delegate that forms the argument to opApply. This might be e.g. int delegate(inout int). Don't forget the inout modifiers!
-
static void alt_iter(alias fn, char[] name = symbolnameof!(fn), iter_t = implementationDetail) ();
+
static void alt_iter(alias fn, char[] name = symbolnameof!(fn), iter_t = implementationDetail) (char[] docstring="");
This wraps alternate iterator methods as Python methods that return iterator objects. The wrapped methods should have a signature like that of opApply. (In other words, they should be methods intended to be used with D's ability to iterate over delgates.) The iter_t argument should be the type of the delegate argument to the method. This will usually be derived automatically.

Once you have called all of the member functions of wrapped_class that you wish to, you must issue a call to finalize_class.

-

void finalize_class(CLS) (CLS cls);

+

void finalize_class(CLS) (CLS cls, char[] docstring="");

This does some final initialization of the class and then registers it with Python. Unlike calls to def, calls to finalize_class must occur after calling module_init. The cls function argument should be an instance of wrapped_class.

diff --git a/html_doc/func_wrapping.html b/html_doc/func_wrapping.html index 7f2d233..5610da8 100644 --- a/html_doc/func_wrapping.html +++ b/html_doc/func_wrapping.html @@ -29,12 +29,13 @@

Function wrapping

Exposing D functions to Python is easy! The heart of Pyd's function wrapping features is the def template function:

-

void def(alias fn, char[] name = symbolnameof!(fn), fn_t = typeof(&fn), uint MIN_ARGS = minArgs!(fn)) ();

+

void def(alias fn, char[] name = symbolnameof!(fn), fn_t = typeof(&fn), uint MIN_ARGS = minArgs!(fn)) (char[] docstring="");

All calls to def must occur before calling module_init. Any function whose return type and arguments are convertible can be wrapped by def. def can only wrap functions with in arguments (not out or inout or lazy). def also provides support for wrapping overloaded functions as well as functions with default arguments. Here are some examples:

diff --git a/html_doc/struct_wrapping.html b/html_doc/struct_wrapping.html index 45f4971..8c71640 100644 --- a/html_doc/struct_wrapping.html +++ b/html_doc/struct_wrapping.html @@ -38,22 +38,22 @@

Struct wrapping

To expose the data members, member functions, and properties of the class, wrapped_struct provides a series of template member functions.

-
static void member(M, size_t offset, char[] name) ();
+
static void member(M, size_t offset, char[] name) (char[] docstring="");
This exposes a data member of the struct to Python. M is the type of the member, and must be a convertible type. offset is the offset (in bytes) of the member in the struct. name is the name of the data member as it will be used in Python. (Optimally, one would simply be able to pass an alias to the member, or at worst an alias and a name, but DMD currently has some issues with this.)
-
static void def(alias fn, char[] name = symbolnameof!(fn), fn_t = typeof(&fn)) ();
+
static void def(alias fn, char[] name = symbolnameof!(fn), fn_t = typeof(&fn)) (char[] docstring="");
This wraps a member function of the struct. It functions exactly like the def function used to wrap class methods, including the lack of support for default arguments.
-
static void static_def(alias fn, char[] name = symbolnameof!(fn), fn_t = typeof(&fn), uint MIN_ARGS = minArgs!(fn)) ();
+
static void static_def(alias fn, char[] name = symbolnameof!(fn), fn_t = typeof(&fn), uint MIN_ARGS = minArgs!(fn)) (char[] docstring="");
This wraps a static member function of the struct. It functions exactly like the static_def function used to wrap static class member functions, and also includes support for default arguments.
-
static void prop(alias fn, char[] name = symbolnameof!(fn), bool RO = false) ();
+
static void prop(alias fn, char[] name = symbolnameof!(fn), bool RO = false) (char[] docstring="");
This wraps a property. It is identical to the prop function used to wrap class properties.
static void iter(iter_t) ();
This allows the user to specify a different overload of opApply than the default. (The default is always the one that is lexically first.) It is identical to the iter function used in class wrapping.
-
static void alt_iter(alias fn, char[] name = symbolnameof!(fn), iter_t = implementationDetail) ();
+
static void alt_iter(alias fn, char[] name = symbolnameof!(fn), iter_t = implementationDetail) (char[] docstring="");
This wraps alternate iterator methods as Python methods that return iterator objects. It is is identical to the alt_iter function used in class wrapping.
@@ -61,7 +61,7 @@

Struct wrapping

Once you have called all of the member functions of wrapped_struct that you wish to, you must issue a call to finalize_struct.

-

void finalize_struct(S) (S s);

+

void finalize_struct(S) (S s, char[] docstring="");

This does some final initialization of the type and then registers it with Python. As with calls to finalize_class, calls to finalize_struct must occur after calling module_init. The s function argument should be an instance of wrapped_struct.

diff --git a/infrastructure/pyd/class_wrap.d b/infrastructure/pyd/class_wrap.d index 6ecea82..689b808 100644 --- a/infrastructure/pyd/class_wrap.d +++ b/infrastructure/pyd/class_wrap.d @@ -250,14 +250,14 @@ struct wrapped_class(T, char[] classname = symbolnameof!(T)) { * fn_t = The type of the function. It is only useful to specify this * if more than one function has the same name as this one. */ - static void def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn)) () { + static void def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn)) (char[] docstring="") { pragma(msg, "class.def: " ~ name); static PyMethodDef empty = { null, null, 0, null }; alias wrapped_method_list!(T) list; list[length-1].ml_name = (name ~ \0).ptr; list[length-1].ml_meth = &method_wrap!(T, fn, fn_t).func; list[length-1].ml_flags = METH_VARARGS; - list[length-1].ml_doc = ""; + list[length-1].ml_doc = (docstring ~ \0).ptr; list ~= empty; // It's possible that appending the empty item invalidated the // pointer in the type struct, so we renew it here. @@ -267,14 +267,14 @@ struct wrapped_class(T, char[] classname = symbolnameof!(T)) { /** * Wraps a static member function of the class. Identical to pyd.def.def */ - static void static_def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS=minArgs!(fn)) () { + static void static_def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS=minArgs!(fn)) (char[] docstring="") { pragma(msg, "class.static_def: " ~ name); static PyMethodDef empty = { null, null, 0, null }; alias wrapped_method_list!(T) list; list[length-1].ml_name = (name ~ \0).ptr; list[length-1].ml_meth = &function_wrap!(fn, MIN_ARGS, fn_t).func; list[length-1].ml_flags = METH_VARARGS | METH_STATIC; - list[length-1].ml_doc = ""; + list[length-1].ml_doc = (docstring ~ \0).ptr; list ~= empty; wrapped_class_type!(T).tp_methods = list; } @@ -287,7 +287,7 @@ struct wrapped_class(T, char[] classname = symbolnameof!(T)) { * name = The name of the property as it will appear in Python. * RO = Whether this is a read-only property. */ - static void prop(alias fn, char[] name = symbolnameof!(fn), bool RO=false) () { + static void prop(alias fn, char[] name = symbolnameof!(fn), bool RO=false) (char[] docstring="") { pragma(msg, "class.prop: " ~ name); static PyGetSetDef empty = { null, null, null, null, null }; wrapped_prop_list!(T)[length-1].name = (name ~ \0).ptr; @@ -297,7 +297,7 @@ struct wrapped_class(T, char[] classname = symbolnameof!(T)) { wrapped_prop_list!(T)[length-1].set = &wrapped_set!(T, fn).func; } - wrapped_prop_list!(T)[length-1].doc = ""; + wrapped_prop_list!(T)[length-1].doc = (docstring ~ \0).ptr; wrapped_prop_list!(T)[length-1].closure = null; wrapped_prop_list!(T) ~= empty; // It's possible that appending the empty item invalidated the @@ -341,14 +341,14 @@ struct wrapped_class(T, char[] classname = symbolnameof!(T)) { * D's delegate-as-iterator features, as methods returning a Python * iterator. */ - static void alt_iter(alias fn, char[] name = symbolnameof!(fn), iter_t = funcDelegInfoT!(typeof(&fn)).Meta.ArgType!(0)) () { + static void alt_iter(alias fn, char[] name = symbolnameof!(fn), iter_t = funcDelegInfoT!(typeof(&fn)).Meta.ArgType!(0)) (char[] docstring="") { static PyMethodDef empty = { null, null, 0, null }; alias wrapped_method_list!(T) list; PydStackContext_Ready(); list[length-1].ml_name = name ~ \0; list[length-1].ml_meth = cast(PyCFunction)&wrapped_iter!(T, fn, int function(iter_t)).iter; list[length-1].ml_flags = METH_VARARGS; - list[length-1].ml_doc = ""; + list[length-1].ml_doc = (docstring ~ \0).ptr; list ~= empty; // It's possible that appending the empty item invalidated the // pointer in the type struct, so we renew it here. @@ -362,7 +362,7 @@ struct wrapped_class(T, char[] classname = symbolnameof!(T)) { * Finalize the wrapping of the class. It is neccessary to call this after all * calls to the wrapped_class member functions. */ -void finalize_class(CLS) (CLS cls, char[] modulename="") { +void finalize_class(CLS) (CLS cls, char[] docstring="", char[] modulename="") { alias CLS.wrapped_type T; alias wrapped_class_type!(T) type; const char[] name = CLS._name; @@ -378,7 +378,7 @@ void finalize_class(CLS) (CLS cls, char[] modulename="") { // Fill in missing values type.ob_type = PyType_Type_p(); type.tp_basicsize = (wrapped_class_object!(T)).sizeof; - type.tp_doc = (name ~ " objects" ~ \0).ptr; + type.tp_doc = (docstring ~ \0).ptr; type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; //type.tp_repr = &wrapped_repr!(T).repr; type.tp_methods = wrapped_method_list!(T).ptr; diff --git a/infrastructure/pyd/def.d b/infrastructure/pyd/def.d index 86de7fe..5cd65c6 100644 --- a/infrastructure/pyd/def.d +++ b/infrastructure/pyd/def.d @@ -81,11 +81,11 @@ PyObject* Pyd_Module_p(char[] modulename="") { *>>> print testdll.foo(20) *It's greater than 10!) */ -void def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS = minArgs!(fn, fn_t)) () { - def!("", fn, name, fn_t, MIN_ARGS)(); +void def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS = minArgs!(fn, fn_t)) (char[] docstring="") { + def!("", fn, name, fn_t, MIN_ARGS)(docstring); } -void def(char[] modulename, alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS = minArgs!(fn, fn_t)) () { +void def(char[] modulename, alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS = minArgs!(fn, fn_t)) (char[] docstring) { pragma(msg, "def: " ~ name); PyMethodDef empty; ready_module_methods(modulename); @@ -94,26 +94,26 @@ void def(char[] modulename, alias fn, char[] name = symbolnameof!(fn), fn_t=type (*list)[length-1].ml_name = (name ~ \0).ptr; (*list)[length-1].ml_meth = &function_wrap!(fn, MIN_ARGS, fn_t).func; (*list)[length-1].ml_flags = METH_VARARGS; - (*list)[length-1].ml_doc = ""; + (*list)[length-1].ml_doc = (docstring ~ \0).ptr; (*list) ~= empty; } /** * Module initialization function. Should be called after the last call to def. */ -PyObject* module_init(char[] name) { +PyObject* module_init(char[] name, char[] docstring="") { //_loadPythonSupport(); ready_module_methods(""); - pyd_modules[""] = Py_InitModule((name ~ \0).ptr, module_methods[""].ptr); + pyd_modules[""] = Py_InitModule3((name ~ \0).ptr, module_methods[""].ptr, (docstring ~ \0).ptr); return pyd_modules[""]; } /** * Module initialization function. Should be called after the last call to def. */ -PyObject* add_module(char[] name) { +PyObject* add_module(char[] name, char[] docstring="") { ready_module_methods(name); - pyd_modules[name] = Py_InitModule((name ~ \0).ptr, module_methods[name].ptr); + pyd_modules[name] = Py_InitModule3((name ~ \0).ptr, module_methods[name].ptr, (docstring ~ \0).ptr); return pyd_modules[name]; } diff --git a/infrastructure/pyd/struct_wrap.d b/infrastructure/pyd/struct_wrap.d index d7f2fde..be7b109 100644 --- a/infrastructure/pyd/struct_wrap.d +++ b/infrastructure/pyd/struct_wrap.d @@ -66,14 +66,14 @@ struct wrapped_struct(T, char[] structname = symbolnameof!(T)) { static const char[] _name = structname; alias T* wrapped_type; - static void member(M, size_t offset, char[] name)() { + static void member(M, size_t offset, char[] name) (char[] docstring="") { pragma(msg, "struct.member: " ~ name); static PyGetSetDef empty = {null, null, null, null, null}; alias wrapped_prop_list!(T*) list; list[length-1].name = (name ~ \0).ptr; list[length-1].get = &wrapped_member!(T*, M, offset).get; list[length-1].set = &wrapped_member!(T*, M, offset).set; - list[length-1].doc = ""; + list[length-1].doc = (docstring ~ \0).ptr; list[length-1].closure = null; list ~= empty; wrapped_class_type!(T*).tp_getset = list.ptr;