Skip to content

Commit

Permalink
Updated docs with new class-wrapping API.
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.dsource.org/projects/pyd/trunk@102 1df65b71-e716-0410-9316-ac55df2b1602
  • Loading branch information
KirkMcDonald authored and KirkMcDonald committed Feb 22, 2007
1 parent 5ad7241 commit bfae4f9
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 356 deletions.
2 changes: 1 addition & 1 deletion html_doc/basics.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ <h3>Module basics</h3>

<p>It does little more than call <a href="http://docs.python.org/api/allocating-objects.html">Py_InitModule</a> and return the new module object. This object is also available via the <code>Pyd_Module_p</code> property once you've called <code>module_init</code>.</p>

<p>Due to the way in which Pyd implements function and class wrapping, any calls to <code>def</code> must occur <em>before</em> the call to <code>module_init</code>, and any calls to <code>finalize_class</code> must occur <em>after</em> the call. I know this seems like a rather arbitrary rule, but it is important. Calls to <code>def</code> in the wrong place will simply be ignored, and calls to <code>finalize_class</code> in the wrong place will throw an assert.</p>
<p>Due to the way in which Pyd implements function and class wrapping, any calls to <code>def</code> must occur <em>before</em> the call to <code>module_init</code>, and any calls to <code>wrap_class</code> must occur <em>after</em> the call. I know this seems like a rather arbitrary rule, but it is important. Calls to <code>def</code> in the wrong place will simply be ignored, and calls to <code>wrap_class</code> in the wrong place will throw an assert.</p>

<p><code>PydMain</code> will catch any D exception that is thrown from inside it, and <a href="except_wrapping.html">safely pass that exception to Python</a>.</p>
</div>
Expand Down
2 changes: 1 addition & 1 deletion html_doc/celerid.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ <h1>CeleriD</h1>
<dt><code>debug_flags</code></dt> <dd>Similar to <code>version_flags</code>, the strings in this list will be passed to D as debug flags.</dd>
<dt><code>raw_only</code></dt> <dd>This flag defaults to <code>False</code>. When <code>True</code>, it supresses the compilation and linkage of Pyd, StackThreads, and meta. This is useful if you only want to write a raw Python/C extension without the overhead of Pyd and its auxiliary packages. This is equivalent to specifying <code>False</code> to the next four flags.</dd>
<dt><code>with_pyd</code></dt> <dd>This flag defaults to <code>True</code>. When <code>False</code>, it supresses the compilation and linkage of Pyd. This is useful if you want to write a raw Python/C extension and don't want the overhead of compiling Pyd.</dd>
<dt><code>with_st</code></dt> <dd>This flag defaults to <code>True</code>. When <code>False</code>, it supresses the compilation and linkage of StackThreads. Pyd uses StackThreads for its iteration wrapping support. By setting this to <code>False</code>, opApply wrapping, <code>wrapped_class.iter</code>, and <code>wrapped_class.alt_iter</code> will be unavailable. If <code>with_pyd</code> and this are <code>True</code>, then the <code>Pyd_with_StackThreads</code> version flag will be defined (which is used internally by Pyd). <b>Important note:</b> StackThreads does not currently work with GDC! CeleriD will always set this flag to <code>False</code> when using GDC! This means that opApply wrapping is not available on Linux at this time.</dd>
<dt><code>with_st</code></dt> <dd>This flag defaults to <code>True</code>. When <code>False</code>, it supresses the compilation and linkage of StackThreads. Pyd uses StackThreads for its iteration wrapping support. By setting this to <code>False</code>, opApply wrapping, <code>Iter</code>, and <code>AltIter</code> will be unavailable. If <code>with_pyd</code> and this are <code>True</code>, then the <code>Pyd_with_StackThreads</code> version flag will be defined (which is used internally by Pyd). <b>Important note:</b> StackThreads does not currently work with GDC! CeleriD will always set this flag to <code>False</code> when using GDC! This means that opApply wrapping is not available on Linux at this time.</dd>
<dt><code>with_meta</code></dt> <dd>This flag defaults to <code>True</code>. When <code>False</code>, it supresses the compilation and linkage of <code>meta</code> (Pyd's metaprogramming package). Because Pyd depends on meta, an exception will be raised if <code>with_pyd</code> is <code>True</code> and this is not.</dd>
<dt><code>with_main</code></dt> <dd>This flag defaults to <code>True</code>. When <code>False</code>, it supresses the use of the "magic" <code>PydMain</code> function. (Instead, users must manually declare a C-style <code>init</code> function.) Do not use this unless you know what you are doing. If <code>with_pyd</code> is <code>False</code>, this will silently be set to <code>False</code> as well. <code>PydMain</code> can only be used if Pyd itself is in use.</dd>
</dl>
Expand Down
77 changes: 34 additions & 43 deletions html_doc/class_wrapping.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,56 +28,46 @@

<h1>Class wrapping</h1>

<p>Exposing D classes to Python is easy! The heart of Pyd's class wrapping features is the <code>wrapped_class</code> template struct:</p>
<p>Exposing D classes to Python is easy! The heart of Pyd's class wrapping features is the <code>wrap_class</code> function template:</p>

<p><code>struct wrapped_class(<span class="t_arg">T</span>, char[] <span class="t_arg">classname</span> = symbolnameof!(T));</code></p>
<p><code>void wrap_class(<span class="t_arg">T</span>, char[] <span class="t_arg">classname</span> = symbolnameof!(T), <span class="t_arg">Params</span>...) ();</code></p>
<ul>
<li><span class="t_arg">T</span> is the class being wrapped.</li>
<li><span class="t_arg">classname</span> is the name of the class as it will appear in Python.</li>
<li><span class="t_arg">classname</span> is the name of the class as it will appear in Python. It defaults to the name of the D class. If you are wrapping an instance of a class template, you will have to provide this explicitly.</li>
<li><span class="t_arg">Params</span> is a series of struct types (defined below), which define the various members of the class.</li>
</ul>

<p>To expose the constructors, methods, and properties of the class, <code>wrapped_class</code> provides a series of template member functions.</p>
<p>Calls to <code>wrap_class</code> must occur <em>after</em> calling <code>module_init</code>.</p>

<p>To expose the constructors, methods, and properties of the class, you must pass <code>wrap_class</code> instantiations of these struct templates.</p>

<dl>
<dt><code>static void def(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">fn_t</span> = typeof(&amp;fn)) (char[] <span class="arg">docstring</span>="");</code></dt>
<dd>This wraps a method of the class. It functions exactly like the <code>def</code> function used to <a href="func_wrapping.html">wrap regular functions</a>, 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.)</dd>
<dt><code>struct Def(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">fn_t</span> = typeof(&amp;fn));</code></dt>
<dd>This wraps a method of the class. It functions very much like the <code>def</code> function used to <a href="func_wrapping.html">wrap regular functions</a>, 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.)</dd>

<dt><code>static void static_def(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">fn_t</span> = typeof(&amp;fn), uint <span class="t_arg">MIN_ARGS</span> = minArgs!(fn)) (char[] <span class="arg">docstring</span>="");</code></dt>
<dt><code>struct StaticDef(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">fn_t</span> = typeof(&amp;fn), uint <span class="t_arg">MIN_ARGS</span> = minArgs!(fn));</code></dt>
<dd>This wraps a static member function of the class. It also functions exactly like the <code>def</code> function used to wrap regular functions, and even includes support for default arguments.</dd>

<dt><code>static void prop(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), bool <span class="t_arg">RO</span> = false) (char[] <span class="arg">docstring</span>="");</code></dt>
<dt><code>struct Property(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), bool <span class="t_arg">RO</span> = false);</code></dt>
<dd>This wraps a property. See the examples below for more details.
<ul>
<li><span class="t_arg">fn</span> is the name of the property. <code>prop</code> will automatically attempt to wrap both the "get" and "set" forms of the property, unless <span class="t_arg">RO</span> is specified.</li>
<li><span class="t_arg">name</span> is the name of the property as it will appear in Python. As with <code>def</code>, <code>prop</code> will attempt to derive this automatically.</li>
<li><span class="t_arg">RO</span> specifies whether this is a <i>read-only</i> property. If true, it will only wrap the "get" form of the property. If false, it will wrap both the "get" and "set" forms. <i>(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.)</i></li>
<li><span class="arg">docstring</span> is the property's docstring. As usual, note that this is a regular function argument, and not a template argument.</li>
</ul>
</dd>

<dt><code>static void init(<span class="t_arg">C</span> ...) ();</code></dt>
<dd>This allows you to expose the class's constructors to Python. If the class provides a zero-argument constructor, there is no need to specify it; it is always available. Each element of <span class="t_arg">C</span> should be a function type. Each function type should correspond to a constructor. (That is, the arguments to the function should be the same as arguments to the class constructor. The return type is ignored.) There is an additional limitation at this time: No two constructors may have the same number of arguments. Pyd will always attempt to call the first constructor with the right number of arguments. If you wish to support a constructor with default arguments, you must specify each possible constructor call as a different template argument to this function. The examples show a few uses of the <code>init</code> function.</dd>

<dt><code>static void parent(<span class="t_arg">Parent</span>) ();</code></dt>
<dd>This allows the user to manually specify a class as this class's parent. This is intended for a very specific purpose (related to how Pyd handles <a href="inherit.html">inheritance</a>), and should not be used heedlessly. If a class's parent was previously wrapped, then Pyd will detect this and set up a parent-child relationship automatically, in which case it is not neccessary to specify this.</dd>

<dt><code>static void hide();</code></dt>
<dd>Causes this class to be wrapped, but not actually directly exposed to Python. This can be useful if you want to return instances of a class without allowing Python code to instantiate them. This is mainly used when handling <a href="inherit.html">inheritance</a>.</dd>
<dt><code>struct Init(<span class="t_arg">C</span> ...);</code></dt>
<dd>This allows you to expose the class's constructors to Python. If the class provides a zero-argument constructor, there is no need to specify it; it is always available. Each element of <span class="t_arg">C</span> should be a function type. Each function type should correspond to a constructor. (That is, the arguments to the function type should be the same as the arguments to the class constructor. The return type is ignored.) There is an additional limitation at this time: No two constructors may have the same number of arguments. Pyd will always attempt to call the first constructor with the right number of arguments. If you wish to support a constructor with default arguments, you must specify each possible constructor call as a different template argument to this function. The examples show a few uses of the <code>init</code> function.</dd>

<dt><code>static void iter(<span class="t_arg">iter_t</span>) ();</code></dt>
<dt><code>struct Iter(<span class="t_arg">iter_t</span>);</code></dt>
<dd>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 <span class="t_arg">iter_t</span> argument should be the type of the delegate that forms the argument to opApply. This might be e.g. <code>int delegate(inout int)</code>. Don't forget the <code>inout</code> modifiers! (This is not available in Linux; see the note below on opApply wrapping.)</dd>

<dt><code>static void alt_iter(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">iter_t</span> = <i>implementationDetail</i>) (char[] <span class="arg">docstring</span>="");</code></dt>
<dt><code>struct AltIter(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">iter_t</span> = <i>implementationDetail</i>);</code></dt>
<dd>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 <span class="t_arg">iter_t</span> argument should be the type of the delegate argument to the method. This will usually be derived automatically. (This is not available in Linux; see the note below on opApply wrapping.)
</dd>
</dl>

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

<p><code>void finalize_class(<span class="t_arg">CLS</span>) (<span class="t_arg">CLS</span> <span class="arg">cls</span>, char[] <span class="arg">docstring</span>="");</code></p>

<p>This does some final initialization of the class and then registers it with Python. Unlike calls to <a href="func_wrapping.html"><code>def</code></a>, calls to <code>finalize_class</code> must occur <em>after</em> calling <code>module_init</code>. The <span class="arg">cls</span> function argument should be an instance of <code>wrapped_class</code>.</p>

<p>If you ever wish to check whether a given class has been wrapped, Pyd helpfully registers all wrapped classes with the <code>is_wrapped</code> template, which is just a templated <code>bool</code>:</p>

<p><code>template is_wrapped(<span class="t_arg">T</span>);</code></p>
Expand All @@ -95,13 +85,13 @@ <h3><a class="anchor" name="opwrap">Automatic operator overloading</a></h3>

<p>At the moment, only the following operator overloads are supported:</p>

<p><code>opAdd, opSub, opMul, opDiv, opMod, opAnd, opOr, opXor, opShl, opShr, opCat, opAddAssign, opSubAssign, opMulAssign, opDivAssign, opModAssign, opAndAssign, opOrAssign, opXorAssign, opShlAssign, opShrAssign, opCatAssign, opIn_r, opCmp, opCall, opApply, opIndex, opIndexAssign, opSlice, opSliceAssign</code></p>
<p><code>opNeg, opPos, opCom, opAdd, opSub, opMul, opDiv, opMod, opAnd, opOr, opXor, opShl, opShr, opCat, opAddAssign, opSubAssign, opMulAssign, opDivAssign, opModAssign, opAndAssign, opOrAssign, opXorAssign, opShlAssign, opShrAssign, opCatAssign, opIn_r, opCmp, opCall, opApply, opIndex, opIndexAssign, opSlice, opSliceAssign</code></p>

<p>Missing from this list are <code>opUShr</code> and <code>opUShrAssign</code>. Python does not have an unsigned right-shift operator, so these operator overloads are not supported. (You may still wrap them with a normal method using <code>wrapped_class.def</code>, of course.) Also missing from the list is <code>opApplyReverse</code>. This must be wrapped explicitly with <code>wrapped_class.alt_iter</code>.</p>
<p>Missing from this list are <code>opUShr</code> and <code>opUShrAssign</code>. Python does not have an unsigned right-shift operator, so these operator overloads are not supported. (You may still wrap them with a normal method using <code>Def</code>, of course.) Also missing from the list is <code>opApplyReverse</code>. This must be wrapped explicitly with <code>AltIter</code>.</p>

<p>Also missing from the list is <code>opAssign</code>. Python has strict reference semantics for its objects, so overloading the assignment operator is not possible. You must explicitly wrap <code>opAssign</code> with a regular method.</p>

<p>Additionally, if a class provides a <code>length</code> property, Pyd will automatically make it available via Python's built-in function <code>len</code> and the special <code>__len__</code> method. You may still wrap it with <code>prop</code> or <code>def</code> if you wish it to be available as a normal property or method.</p>
<p>Additionally, if a class provides a <code>length</code> property, Pyd will automatically make it available via Python's built-in function <code>len</code> and the special <code>__len__</code> method. You may still wrap it with <code>Property</code> or <code>Def</code> if you wish it to be available as a normal property or method.</p>

<p><b>Notes on wrapped operators</b></p>

Expand Down Expand Up @@ -139,24 +129,25 @@ <h3><a class="anchor" name="examples">Examples</a></h3>

<p>We would expose this class to Python by putting this code in <code>PydMain</code> after the call to <code>module_init</code>:</p>

<pre class="code"><span class="comment">// Make an instance of wrapped_class</span>
wrapped_class!(Foo) f;
<span class="comment">// Wrap the "foo" method</span>
f.def!(Foo.foo);
<span class="comment">// Wrap the "i" property</span>
f.prop!(Foo.i);
<span class="comment">// Wrap the constructors.</span>
f.init!(<span class="keyword">void function</span>(<span class="keyword">int</span>), <span class="keyword">void function</span>(<span class="keyword">int</span>, <span class="keyword">int</span>));
finalize_class(f);</pre>
<pre class="code"><span class="comment">// Call wrap_class</span>
wrap_class!(
Foo,
<span class="comment">// Wrap the "foo" method</span>
Def!(Foo.foo),
<span class="comment">// Wrap the "i" property</span>
Property!(Foo.i),
<span class="comment">// Wrap the constructors.</span>
Init!(<span class="keyword">void function</span>(<span class="keyword">int</span>), <span class="keyword">void function</span>(<span class="keyword">int</span>, <span class="keyword">int</span>))
);</pre>

<p>Now we can use this type from within Python like any other type.</p>

<pre class="code">&gt;&gt;&gt; from testmodule import Foo
<pre class="code">&gt;&gt;&gt; <span class="keyword">from</span> testmodule <span class="keyword">import</span> Foo
&gt;&gt;&gt; f = Foo()
&gt;&gt;&gt; f.i
0
&gt;&gt;&gt; f.i = 20
&gt;&gt;&gt; f.foo("Hello! i is ")
&gt;&gt;&gt; f.foo(<span class="string">"Hello! i is "</span>)
Hello! i is 20
&gt;&gt;&gt; f = Foo(10, 10)
&gt;&gt;&gt; f.i
Expand All @@ -167,10 +158,10 @@ <h3><a class="anchor" name="examples">Examples</a></h3>
&gt;&gt;&gt; e = f + g
&gt;&gt;&gt; e.i
50
&gt;&gt;&gt; # We can even subclass our D type
&gt;&gt;&gt; class MyFoo(Foo):
... def bar(self):
... print "Hey, i+3 is", self.i + 3
&gt;&gt;&gt; <span class="comment"># We can even subclass our D type</span>
&gt;&gt;&gt; <span class="keyword">class</span> MyFoo(Foo):
... <span class="keyword">def</span> bar(self):
... <span class="keyword">print</span> <span class="string">"Hey, i+3 is"</span>, self.i + 3
...
&gt;&gt;&gt; h = MyFoo(3)
&gt;&gt;&gt; h.bar()
Expand Down
Loading

0 comments on commit bfae4f9

Please sign in to comment.