Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options

Proper usage of Inline::Python

by OverlordQ (Hermit)
on Oct 10, 2014 at 16:40 UTC ( [id://1103444] : perlquestion . print w/replies, xml ) Need Help??

OverlordQ has asked for the wisdom of the Perl Monks concerning the following question:

Greetings monks, I'm trying to leverage the use of Inline::Python to make usage of a python module that unfortunately, currently has no Perl equivalent. I (think) I understand the basic usage of importing a Python class, but I can't figure out how to properly reference the imported classes and objects without having to wrap everything.

For example, my current 'working' code is this:

#!/usr/bin/perl use strict; use warnings; my $client = Wrapper->new(); my @res = $client->get('space','key'); use Inline Python => <<'END_OF_PYTHON' import hyperdex.client class Wrapper: def __init__(self, host='', port=1982): self.client = hyperdex.client.Client(host,port) def get(self, *args): self.client(get(args[0],args[1]) END_OF_PYTHON

It'd be nice if I could just do:

my $client = Client->new('',1982); $client->get('space','key'); $client->search('space', { a => b, c => d });

Without having to create wrappers for each class method in the Python library I want to utilize.

I've tried:

my $client = new Client('',1982); use Inline Python => <<'END_OF_PYTHON' import hyperdex.client as Client END_OF_PYTHON

That gives me a

Can't bless non-reference value
error. While:

my $client = Client->Client('',1982);

Gives me a

Object did not have Inline::Python::Object magic

Are there any monks out there that could provide some insight to utilizing Inline::Python to DWIM?

EDIT: With some help from AnonyMonk and crashtest, I was able to at least get this to somewhat DWIW:

#!/usr/bin/perl use strict; use warnings; use Inline::Python qw(py_eval py_bind_class); use Data::Dumper; py_eval(<<'END'); from hyperdex.client import Client class MyClient(Client): def placeholder(self): print "Placeholder function" END py_bind_class("main::PerlClient","__main__","MyClient"); my $a = new PerlClient('',1982); warn Dumper($a->get('space','1234567'));

It's less wrapping then before, but still seems like more wrapped than should be needed. Or I may be wrong?

Replies are listed 'Best First'.
Re: Proper usage of Inline::Python
by crashtest (Curate) on Oct 11, 2014 at 16:57 UTC

    Here's a concrete example that worked for me, using the Decimal class. I expect the usage to be analogous for the Hyperdex library. As Anony-Monk pointed out, the do-it-yourselfer's guide is valuable documentation here.

    use Inline::Python qw(py_eval py_call_function); py_eval("import decimal"); my $d1 = Inline::Python::Object->new('decimal', 'Decimal', '42.00'); my $d2 = Inline::Python::Object->new('decimal', 'Decimal', '2.00'); my $d3 = $d1->__mul__($d2); print $d3->to_eng_string(); # prints "84.000"

      As I pointed out to the Anonymous Monk, any combination of the constructor I've tried without having to wrap it in my own Python code results in the bless non-reference error.

        I was able to reproduce your error on my system. Dug into it a bit with the debugger, and I found that the non-reference object being blessed is this string:

        '<hyperdex.client.Client object at 0x7fa3f1c0c560>'
        My guess is that it's a bug in Inline::Python's conversion magic or something unexpected in the Hyperdex libary. The Python object is being created properly, but somewhere it's been converted to a string representation. I really don't know enough Python to hazard a guess as to what's really going on here.

        Might be worth filing a bug report for Inline-Python. The Python library Hyperdex installs is a shared library file, not a traditional .py or .pyc module, and I wonder if that perhaps has something to do with it. At least you already have a work-around.

Re: Proper usage of Inline::Python
by Anonymous Monk on Oct 11, 2014 at 03:08 UTC

      That's what I tried.

      py_eval('import hyperdex.client'); my $client = Inline::Python::Object->new('hyperdex.client','Client');
      Gives me:
      exceptions.TypeError: __cinit__() takes exactly 2 positional arguments (0 given) at line 1060
      Which makes it seem, oh, I'll just add the two parameters. However:
      py_eval('import hyperdex.client'); my $client = Inline::Python::Object->new('hyperdex.client','Client','1 +',1982);
      Gives me the
      Can't bless non-reference value at /usr/local/lib/perl/5.14.2/Inline/ line 317.
      error again.