From f1874ecec02306795c3c9f141c7e21436f6d8b61 Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Tue, 27 Nov 2012 00:16:34 +0000 Subject: [PATCH] inprove python interface. --- packages/python/examples/tut.pl | 131 ++++++++++++++++++++++++++++++++ packages/python/python.c | 121 ++++++++++++++++++++++++++++- packages/python/python.pl | 8 +- 3 files changed, 255 insertions(+), 5 deletions(-) create mode 100644 packages/python/examples/tut.pl diff --git a/packages/python/examples/tut.pl b/packages/python/examples/tut.pl new file mode 100644 index 000000000..cfbd75158 --- /dev/null +++ b/packages/python/examples/tut.pl @@ -0,0 +1,131 @@ + +:- use_module(library(python)). + +:- initialization(main). + +main :- + ex(X), + flush_output, + fail. +main. + +% +% strings are atoms in the interface +% with usual properties +% +% variables must be used with $ +% +% UNICODE is supposed to work (does in Linux). +% +ex(currency) :- + ( + currency := '€', + O := ord($currency), + X := $currency, + L := len($currency), + format('currency=~a ~d/~d~n',[X, O, L]) + -> + true + ; + failed(currency) + ). + +ex(home) :- + ( + filename := os:environ:get('HOME') + -> + X := $filename, + format('HOME=~a~n',[X]) + ; + true + ). + +ex(site) :- + X := site:getusersitepackages, + format('site packages=~a~n',[X]). + +ex(arith) :- + A := 2+2, + B := (50-5*6)/4, + C := 7/3, + width := 20, + height := 5*9, + D := $width* $height, + format('arith=~d ~d ~d ~d~n',[A,B,C,D]). + +ex(undefined) :- + format('undefined variable~n', []), + X := $n, + format('undefined=~d',[X]). + +ex(fp) :- + X := 3 * 3.75 / 1.5, + Y := 7.0 / 2, + format('fp=~f ~f~n',[X,Y]). + +ex(complex) :- + A := complex(0,1) * complex(0,1), + B := complex(3,1)*3, + a := complex(1.5,0.5), + R := $a:real, + I := $a:imag, + format('complex=~w ~w ~w+~wj~n',[A,B,R,I]). + +ex(floatint) :- + A := float(22000), + B := int(3.1), + C := long(15000000.5), + format('cast=~w ~w ~w~n',[A,B,C]). + +ex(strings) :- + S1 := 'spam eggs', + S2 := 'doesn\'t', + S3 := '"Yes," he said.', + S4 := '"Isn\'t," she said.', + format('s=~a ~a ~a ~a~n',[S1,S2,S3,S4]), + hello := 'This is a rather long string containing\n\ +several lines of text just as you would do in C.\n\ + Note that whitespace at the beginning of the line is\ + significant.', + python_command('print hello'), + X := $hello, + format('s=~a~n',[X]). + +ex(strings2) :- + word := 'Help' + 'A', + X := '<' + $word*5 + '>', + Y := (str:strip) + ing, + A1 := $word^[4], + A2 := $word^[0:2], + A3 := $word^[2:4], + format('concat=~a ~a ~a ~a ~a~n',[X,Y,A1,A2,A3]). + +ex(slices) :- + s := 'supercalifragilisticexpialidocious', + L := len($s), + S1 := $s^[1:6], + S2 := $s^[-6: -1], + S3 := $s^[_:6], + S4 := $s^[-6:_], + format('slices=~d ~a ~a ~a ~a~n',[L,S1,S2,S3,S4]). + + +ex(lists) :- + a := [66.25, 333, 333, 1, 1234.5], + A1 := $a:count(333), A2 := $a:count(66.25), A3 := $a:count('x'), + format('counts=~d ~d ~d~n',[A1,A2,A3]), + := $a:insert(2, -1), + := $a:append(333), + A := $a, + format('a=~w~n', [A]), + I := $a:index(333), + := $a:remove(333), + B := $a, + format('a=~w~n', [B]), + := $a:reverse, + C := $a, + format('a=~w~n', [C]), + := $a:sort, + D := $a, + format('a=~w~n', [D]). + diff --git a/packages/python/python.c b/packages/python/python.c index 1495bd0a3..49753b0c2 100644 --- a/packages/python/python.c +++ b/packages/python/python.c @@ -7,6 +7,7 @@ #include static atom_t ATOM_true, + ATOM_colon, ATOM_false, ATOM_t; @@ -16,6 +17,9 @@ static functor_t FUNCTOR_dollar1, FUNCTOR_any1, FUNCTOR_bin1, FUNCTOR_dir1, + FUNCTOR_float1, + FUNCTOR_int1, + FUNCTOR_long1, FUNCTOR_iter1, FUNCTOR_len1, FUNCTOR_curly1, @@ -185,6 +189,66 @@ bip_bin(term_t t) } +static PyObject * +bip_float(term_t t) +{ + PyObject *pVal, *o; + + if (! PL_get_arg(1, t, t) ) + return NULL; + pVal = term_to_python(t); + if (PyLong_Check(pVal)) { + o = PyFloat_FromDouble( PyLong_AsLong(pVal) ); + } else if (PyInt_Check(pVal)) { + o = PyFloat_FromDouble( PyInt_AsLong(pVal) ); + } else if (PyFloat_Check(pVal)) { + return pVal; + } else + return NULL; + Py_DECREF(pVal); + return o; +} + +static PyObject * +bip_int(term_t t) +{ + PyObject *pVal, *o; + + if (! PL_get_arg(1, t, t) ) + return NULL; + pVal = term_to_python(t); + if (PyLong_Check(pVal)) { + o = PyInt_FromLong( PyLong_AsLong(pVal) ); + } else if (PyInt_Check(pVal)) { + return pVal; + } else if (PyFloat_Check(pVal)) { + o = PyInt_FromLong( PyFloat_AsDouble(pVal) ); + } else + return NULL; + Py_DECREF(pVal); + return o; +} + +static PyObject * +bip_long(term_t t) +{ + PyObject *pVal, *o; + + if (! PL_get_arg(1, t, t) ) + return NULL; + pVal = term_to_python(t); + if (PyLong_Check(pVal)) { + return pVal; + } else if (PyLong_Check(pVal)) { + o = PyLong_FromLong( PyInt_AsLong(pVal) ); + } else if (PyFloat_Check(pVal)) { + o = PyLong_FromLong( PyFloat_AsDouble(pVal) ); + } else + return NULL; + Py_DECREF(pVal); + return o; +} + static PyObject * bip_ord(term_t t) { @@ -330,6 +394,12 @@ term_to_python(term_t t) return bip_bin(t); } else if (fun == FUNCTOR_ord1) { return bip_ord(t); + } else if (fun == FUNCTOR_int1) { + return bip_int(t); + } else if (fun == FUNCTOR_long1) { + return bip_long(t); + } else if (fun == FUNCTOR_float1) { + return bip_float(t); } else if (fun == FUNCTOR_len1) { term_t targ = PL_new_term_ref(); PyObject *ptr; @@ -755,9 +825,9 @@ python_import(term_t mname, term_t mod) return FALSE; } pModule = PyImport_Import(pName); - // PyErr_Print(); Py_DECREF(pName); if (pModule == NULL) { + PyErr_Clear(); return FALSE; } return python_to_term(pModule, mod); @@ -788,6 +858,7 @@ python_f(term_t tmod, term_t fname, term_t tf) return FALSE; } pF = PyObject_GetAttrString(pModule, s); + PyErr_Print(); Py_DECREF(pModule); if (pF == NULL || ! PyCallable_Check(pF)) { return FALSE; @@ -867,6 +938,24 @@ python_apply(term_t tin, term_t targs, term_t tf) if (! PL_get_name_arity( targs, &aname, &arity) ) { return FALSE; } + /* follow chains of the form a.b.c.d.e() */ + while (aname == ATOM_colon && arity == 2) { + term_t tleft = PL_new_term_ref(); + PyObject *lhs; + + if (! PL_get_arg(1, targs, tleft) ) + return FALSE; + lhs = term_to_python(tleft); + if ((pF = PyObject_GetAttr(pF, lhs)) == NULL) { + PyErr_Print(); + return FALSE; + } + if (! PL_get_arg(2, targs, targs) ) + return FALSE; + if (! PL_get_name_arity( targs, &aname, &arity) ) { + return FALSE; + } + } if (PyFunction_Check(pF)) { int tuple_inited = FALSE; PyObject *pOpt = NULL; @@ -916,14 +1005,16 @@ python_apply(term_t tin, term_t targs, term_t tf) } if (PyCallable_Check(pF)) { pValue = PyObject_CallObject(pF, pArgs); + PyErr_Print(); } else { + PyErr_Print(); return FALSE; } PyErr_Print(); Py_DECREF(pArgs); + Py_DECREF(pF); if (pValue == NULL) return FALSE; - out = 0; out = python_to_term(pValue, tf); Py_DECREF(pValue); return out; @@ -953,8 +1044,10 @@ python_access(term_t obj, term_t f, term_t out) if ( PL_is_atom(f) ) { if (!PL_get_atom_chars(f, &s)) return FALSE; - if ((pValue = PyObject_GetAttrString(o, s)) == NULL) + if ((pValue = PyObject_GetAttrString(o, s)) == NULL) { + PyErr_Print(); return FALSE; + } if ( PyCallable_Check(pValue) ) pValue = PyObject_CallObject(pValue, NULL); PyErr_Print(); @@ -963,6 +1056,24 @@ python_access(term_t obj, term_t f, term_t out) if (! PL_get_name_arity( f, &name, &arity) ) { return FALSE; } + /* follow chains of the form a.b.c.d.e() */ + while (name == ATOM_colon && arity == 2) { + term_t tleft = PL_new_term_ref(); + PyObject *lhs; + + if (! PL_get_arg(1, f, tleft) ) + return FALSE; + lhs = term_to_python(tleft); + if ((o = PyObject_GetAttr(o, lhs)) == NULL) { + PyErr_Print(); + return FALSE; + } + if (! PL_get_arg(2, f, f) ) + return FALSE; + if (! PL_get_name_arity( f, &name, &arity) ) { + return FALSE; + } + } s = PL_atom_chars(name); if ((pF = PyObject_GetAttrString(o, s)) == NULL) { PyErr_Print(); @@ -1028,6 +1139,7 @@ install_python(void) { // FUNCTOR_dot2 = PL_new_functor(PL_new_atom("."), 2); // FUNCTOR_equal2 = PL_new_functor(PL_new_atom("="), 2); // FUNCTOR_boolop1 = PL_new_functor(PL_new_atom("@"), 1); + ATOM_colon = PL_new_atom(":"); ATOM_true = PL_new_atom("true"); ATOM_false = PL_new_atom("false"); ATOM_t = PL_new_atom("t"); @@ -1036,6 +1148,9 @@ install_python(void) FUNCTOR_any1 = PL_new_functor(PL_new_atom("any"), 1); FUNCTOR_bin1 = PL_new_functor(PL_new_atom("bin"), 1); FUNCTOR_ord1 = PL_new_functor(PL_new_atom("ord"), 1); + FUNCTOR_int1 = PL_new_functor(PL_new_atom("int"), 1); + FUNCTOR_long1 = PL_new_functor(PL_new_atom("long"), 1); + FUNCTOR_float1 = PL_new_functor(PL_new_atom("float"), 1); FUNCTOR_curly1 = PL_new_functor(PL_new_atom("{}"), 1); FUNCTOR_dollar1 = PL_new_functor(PL_new_atom("$"), 1); FUNCTOR_pointer1 = PL_new_functor(PL_new_atom("__obj__"), 1); diff --git a/packages/python/python.pl b/packages/python/python.pl index 5b5509ed3..c62707a44 100644 --- a/packages/python/python.pl +++ b/packages/python/python.pl @@ -98,6 +98,10 @@ python_eval_term(Expression, O) :- atom(Exp) -> python_access(MRef, Exp, O) + ; + Exp = Obj:Method + -> + python_access(MRef, Exp, O) ; functor(Exp, F, _), python_f(MRef, F, FRef), @@ -115,12 +119,12 @@ python_check_args(FRef, Exp, NExp) :- Exp =.. [F|LArgs], match_args(LArgs, Dict, NLArgs, _), NExp =.. [F|NLArgs]. -python_check_args(FRef, Exp, NExp). +python_check_args(FRef, Exp, Exp). fetch_args(FRef, Args) :- python_import('inspect', M), python_f(M, getargspec, F), - python_apply(F, getargspec(FRef), ExtraArgs), + python_apply(F, getargspec(FRef), Args), ExtraArgs=t(Args, _, _, _).