Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Support passing Python objects through Perl space and calling methods
  • Loading branch information
niner committed Oct 14, 2014
1 parent a0c7035 commit 8d6a813
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 8 deletions.
58 changes: 56 additions & 2 deletions lib/Inline/Python.pm6
Expand Up @@ -19,12 +19,17 @@ sub native(Sub $sub) {
trait_mod:<is>($sub, :native($path));
}

class PythonObject { ... }

sub py_init_python()
{ ... }
native(&py_init_python);
sub py_eval(Str, Int)
returns OpaquePointer { ... }
native(&py_eval);
sub py_instance_check(OpaquePointer)
returns int32 { ... }
native(&py_instance_check);
sub py_int_check(OpaquePointer)
returns int32 { ... }
native(&py_int_check);
Expand Down Expand Up @@ -88,6 +93,9 @@ sub py_dict_set_item(OpaquePointer, OpaquePointer, OpaquePointer)
sub py_call_function(Str, Str, int, CArray[OpaquePointer])
returns OpaquePointer { ... }
native(&py_call_function);
sub py_call_method(OpaquePointer, Str, int, CArray[OpaquePointer])
returns OpaquePointer { ... }
native(&py_call_method);
sub py_sequence_length(OpaquePointer)
returns int { ... }
native(&py_sequence_length);
Expand All @@ -103,6 +111,9 @@ sub py_none()
sub py_dec_ref(OpaquePointer)
{ ... }
native(&py_dec_ref);
sub py_inc_ref(OpaquePointer)
{ ... }
native(&py_inc_ref);

method py_array_to_array(OpaquePointer $py_array) {
my @array = [];
Expand All @@ -125,7 +136,12 @@ method py_dict_to_hash(OpaquePointer $py_dict) {
}

method py_to_p6(OpaquePointer $value) {
if py_int_check($value) {
return Any unless defined $value;
if py_instance_check($value) {
py_inc_ref($value);
return PythonObject.new(python => self, ptr => $value);
}
elsif py_int_check($value) {
return py_int_as_long($value);
}
elsif py_float_check($value) {
Expand Down Expand Up @@ -198,6 +214,10 @@ multi method p6_to_py(Any:U $value) returns OpaquePointer {
py_none();
}

multi method p6_to_py(Any:D $value) returns OpaquePointer {
die $value.perl ~ ' not yet implemented';
}

method !setup_arguments(@args) {
my $len = @args.elems;
my $tuple = py_tuple_new($len);
Expand All @@ -218,9 +238,43 @@ multi method run($python, :$file) {
}

method call(Str $package, Str $function, *@args) {
return self.py_to_p6(py_call_function($package, $function, self!setup_arguments(@args)));
my $py_retval = py_call_function($package, $function, self!setup_arguments(@args));
return unless defined $py_retval;
my \retval = self.py_to_p6($py_retval);
py_dec_ref($py_retval);
return retval;
}

method invoke(OpaquePointer $obj, Str $method, *@args) {
my $py_retval = py_call_method($obj, $method, self!setup_arguments(@args));
return unless defined $py_retval;
my \retval = self.py_to_p6($py_retval);
py_dec_ref($py_retval);
return retval;
}

method BUILD {
py_init_python();
}

class PythonObject {
has OpaquePointer $.ptr;
has Inline::Python $.python;

method sink() { self }

method DESTROY {
$!python.py_dec_ref($!ptr) if $!ptr;
$!ptr = OpaquePointer;
}
}

BEGIN {
PythonObject.^add_fallback(-> $, $ { True },
method ($name ) {
-> \self, |args {
$.python.invoke($.ptr, $name, args.list);
}
}
);
}
19 changes: 17 additions & 2 deletions pyhelper.c
Expand Up @@ -40,6 +40,10 @@ PyObject *py_eval(const char* p, int type) {
return py_result;
}

int py_instance_check(PyObject *obj) {
return ((obj->ob_type->tp_flags & Py_TPFLAGS_HEAPTYPE) || PyInstance_Check(obj));
}

int py_int_check(PyObject *obj) {
return PyInt_Check(obj);
}
Expand Down Expand Up @@ -154,18 +158,29 @@ void py_dec_ref(PyObject *obj) {
Py_DECREF(obj);
}

void py_inc_ref(PyObject *obj) {
Py_INCREF(obj);
}

PyObject *py_call_function(char *pkg, char *name, PyObject *args) {
int i;
PyObject * const mod = PyImport_AddModule(pkg);
PyObject * const dict = PyModule_GetDict(mod);
PyObject * const func = PyMapping_GetItemString(dict, name);
PyObject *o = NULL;
PyObject *py_retval = NULL;
PyObject *tuple = NULL;

py_retval = PyObject_CallObject(func, args);
Py_DECREF(func);
Py_DECREF(args);

return py_retval;
}

PyObject *py_call_method(PyObject *obj, char *name, PyObject *args) {
PyObject *method = PyObject_GetAttrString(obj, name);
PyObject *py_retval = PyObject_CallObject(method, args);
Py_DECREF(method);
Py_DECREF(args);

return py_retval;
}
8 changes: 4 additions & 4 deletions t/call.t
Expand Up @@ -3,10 +3,10 @@
use v6;
use Inline::Python;

say "1..7";
say "1..9";

my $py = Inline::Python.new();
say $py.run('
$py.run('
def test():
print "ok 1 - executing a parameterless function without return value";
Expand Down Expand Up @@ -66,7 +66,7 @@ class Foo:
def test(self):
return self.val
def sum(a, b):
def sum(self, a, b):
return a + b
');

Expand Down Expand Up @@ -110,7 +110,6 @@ else {
say " expected: 'Hello', 'Perl', 6";
}

if (False) {
if ($py.call('__main__', 'Foo', 1).test() == 1) {
say "ok 8 - Python method call";
}
Expand All @@ -125,6 +124,7 @@ else {
say "not ok 9 - Python method call with parameters";
}

if False {
if ($py.call('__main__', 'test_none', Any) == 1) {
say "ok 10 - Any converted to undef";
}
Expand Down

0 comments on commit 8d6a813

Please sign in to comment.