import pyd.pyd;
import std.stdio;
void hello() {
writefln("Hello, world!");
}
extern(C) void PydMain() {
def!(hello);
module_init();
}
And in Python:
>>> hello()
Hello, world!
Pyd extends distutils:
# setup.py
from celerid.support \
import setup, Extension
setup(
name='foo',
ext_modules=[
Extension(
'foo', ['foo.d']
)
],
)
Compiling is as easy as:
python setup.py build
Exposing simple functions to Python is simple:
int func(int i) {
return i * 2;
}
extern(C) void PydMain() {
def!(func);
module_init();
}
>>> func(10)
20
More complicated functions are still simple:
int func2(int i, int j=2) {
return i * j;
}
extern(C) void PydMain() {
def!(func2);
module_init();
}
This works as expected:
>>> func2(1)
2
>>> func2(2, 3)
6
We can also wrap overloaded functions:
void func3(double d) {}
void func3(int i) {}
extern(C) void PydMain() {
def!(func3, "func3a",
void function(double));
def!(func3, "func3b",
void function(int));
module_init();
}
>>> func3a(2.0)
>>> func3b(5)
We can handle any arbitrary Python object as a PydObject:
PydObject add(PydObject a, PydObject b) {
return a + b;
}
extern(C) void PydMain() {
def!(add);
module_init();
}
>>> add(10, 20)
30
>>> add('abc', 'def')
'abcdef'
Exceptions are safely handled:
void throw_something() {
throw new Exception("Boo!");
}
extern(C) void PydMain() {
def!(throw_something);
module_init();
}
>>> throw_something()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: D Exception: object.Exception: Boo!
Exceptions caused by PydObject are handled, too:
>>> add(1, 'twelve')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
struct S {
int i;
}
S func1() {
S s;
s.i = 50;
return s;
}
void func2(S s) {
writefln(s.i);
}
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!(func1);
def!(func2);
module_init();
}
>>> func1()
50
>>> func2(20)
20
A Simple Example
class Foo {
void bar() {}
}
extern(C) void PydMain() {
module_init();
wrap_class!(
Foo,
Def!(Foo.bar)
);
}
>>> f = Foo()
>>> f.bar()
Functions can use wrapped classes:
class Foo {}
void func1(Foo f) {}
Foo func2() { return new Foo; }
extern(C) void PydMain() {
def!(func1);
def!(func2);
module_init();
wrap_class!(Foo);
}
>>> f = Foo()
>>> func1(f)
>>> g = func2()
Returned objects keep their identity:
Foo bar() {
static Foo f;
if (!f) { f = new Foo; }
return f;
}
>>> a = bar(); b = bar()
>>> a is b
True
Inherited methods are wrapped automatically:
class Base {
void foo() {
writefln("Base.foo");
}
}
class Derived : Base {}
extern(C) void PydMain() {
module_init();
wrap_class!(
Base,
Def!(Base.foo)
);
wrap_class!(Derived);
}
This works as expected in Python:
>>> d = Derived()
>>> d.foo()
Base.foo
Returned objects always keep their real type:
Base foo() {
return new Derived;
}
>>> o = foo()
>>> type(o)
<type 'test.Derived'>
Operator overloads are wrapped automatically:
class Foo {
int a;
this(int a) { this.a = a; }
int opAdd(Foo f) {
return this.a + f.a;
}
}
extern(C) void PydMain() {
module_init();
wrap_class!(
Foo,
Init!(void function(int))
);
}
>>> Foo(1) + Foo(2)
3
You can even subclass D classes in Python.
>>> class PyDerived(Base):
... def foo(self):
... print "PyDerived.foo"
>>> o = PyDerived()
>>> o.foo()
PyDerived.foo
And they can be passed back to D:
void polymorphic_call(Base b) {
b.foo();
}
>>> polymorphic_call(o)
PyDerived.foo