From 35a59e7dbce7f5cd6fb8c26e40fc66dfd8384cce Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Mon, 18 Jul 2005 18:03:12 +0000 Subject: python-like dotted module.function syntax cleaned up float vs. int pyext tags better definition of output values (atoms, lists, anythings) multiply inlets for py (hot and cold inlets) better exception handling and error message fixes for atomic pyext._outlet messages svn path=/trunk/; revision=3358 --- externals/grill/py/pd/methods-1.pd | 22 +++---- externals/grill/py/readme.txt | 2 + externals/grill/py/source/clmeth.cpp | 1 - externals/grill/py/source/py.cpp | 21 +++--- externals/grill/py/source/pyargs.cpp | 121 +++++++++++++++++++---------------- externals/grill/py/source/pybase.cpp | 24 ++++++- externals/grill/py/source/pybase.h | 21 +++++- externals/grill/py/source/pyext.cpp | 17 ++--- externals/grill/py/source/pyext.h | 2 +- externals/grill/py/source/pymeth.cpp | 18 ++---- 10 files changed, 141 insertions(+), 108 deletions(-) (limited to 'externals/grill') diff --git a/externals/grill/py/pd/methods-1.pd b/externals/grill/py/pd/methods-1.pd index 8d49f319..ab949c7e 100644 --- a/externals/grill/py/pd/methods-1.pd +++ b/externals/grill/py/pd/methods-1.pd @@ -1,24 +1,24 @@ -#N canvas 540 469 714 349 12; +#N canvas 540 469 718 353 12; #X obj 16 13 cnv 15 650 40 empty empty py/pyext 10 22 0 24 -260818 -1 0; #X text 235 16 Python script objects \, (C)2003-2005 Thomas Grill; #X text 235 32 http://grrrr.org/ext; #X symbolatom 21 139 10 0 0 0 - - -; #X symbolatom 25 298 10 0 0 0 - - -; -#X obj 25 252 pym upper; #X obj 22 179 py .str @xlate 0; #X text 93 167 convert the symbol to a Python string; #X text 35 216 pass it as a true Python object; -#X text 105 251 use string.upper method; -#X obj 363 252 py string.upper; -#X symbolatom 364 288 10 0 0 0 - - -; -#X text 495 254 use module function; +#X symbolatom 364 295 10 0 0 0 - - -; +#X text 462 269 use module function; #X text 23 119 enter some text; #X text 21 73 Py can act on Python objects in a object-oriented manner ; #X text 93 184 using the built-in str function; -#X connect 3 0 6 1; -#X connect 5 0 4 0; -#X connect 6 0 5 1; -#X connect 6 0 10 1; -#X connect 10 0 11 0; +#X obj 25 252 pym swapcase; +#X text 63 270 use swapcase method; +#X obj 363 250 py string.swapcase; +#X connect 3 0 5 1; +#X connect 5 0 13 1; +#X connect 5 0 15 1; +#X connect 13 0 4 0; +#X connect 15 0 8 0; diff --git a/externals/grill/py/readme.txt b/externals/grill/py/readme.txt index c36a081b..9213786d 100644 --- a/externals/grill/py/readme.txt +++ b/externals/grill/py/readme.txt @@ -96,6 +96,8 @@ Version history: - ADD: py: enable Python built-in functions (like range, str etc.) - ADD: sequence protocol for symbol type - FIX: cleanup for outbound messages (e.g. symbol atoms instead of one-element general messages) +- FIX: better exception handling (no longer leaves reference to function object) and cleared misleading error message +- FIX: better definition of output values for atoms, lists and anythings 0.2.0: - ADD: handling of Python threads diff --git a/externals/grill/py/source/clmeth.cpp b/externals/grill/py/source/clmeth.cpp index 3d740bcb..0dff50e9 100644 --- a/externals/grill/py/source/clmeth.cpp +++ b/externals/grill/py/source/clmeth.cpp @@ -167,7 +167,6 @@ PyObject *pyext::pyext_outlet(PyObject *,PyObject *args) pyext *ext = GetThis(self); PyObject *val; - bool tp; #if 0 if(sz == 3) { val = PyTuple_GET_ITEM(args,2); // borrow reference diff --git a/externals/grill/py/source/py.cpp b/externals/grill/py/source/py.cpp index da9459fe..4b7c2bdc 100644 --- a/externals/grill/py/source/py.cpp +++ b/externals/grill/py/source/py.cpp @@ -54,7 +54,7 @@ protected: private: - virtual bool callpy(PyObject *fun,PyObject *args); + virtual void callpy(PyObject *fun,PyObject *args); static void Setup(t_classid c); @@ -343,19 +343,12 @@ void pyobj::Unload() SetFunction(NULL); } -bool pyobj::callpy(PyObject *fun,PyObject *args) +void pyobj::callpy(PyObject *fun,PyObject *args) { PyObject *ret = PyObject_CallObject(fun,args); - if(ret == NULL) { - // function not found resp. arguments not matching - PyErr_Print(); - return false; - } - else { - if(!OutObject(this,0,ret) && PyErr_Occurred()) - PyErr_Print(); + if(ret) { + OutObject(this,0,ret); // exception might be raised here Py_DECREF(ret); - return true; } } @@ -397,7 +390,8 @@ bool pyobj::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv) // if n == 0, it's a pure bang pargs = MakePyArgs(n?s:NULL,argc,argv); - ret = gencall(function,pargs); // references are stolen + gencall(function,pargs); // references are stolen + ret = true; } else PyErr_SetString(PyExc_RuntimeError,"No function set"); @@ -408,7 +402,8 @@ bool pyobj::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv) PyObject *func = PyObject_GetAttrString(module,const_cast(GetString(s))); if(func) { PyObject *pargs = MakePyArgs(sym_list,argc,argv); - ret = gencall(func,pargs); + gencall(func,pargs); + ret = true; } } else diff --git a/externals/grill/py/source/pyargs.cpp b/externals/grill/py/source/pyargs.cpp index 2957801d..2cdfdade 100644 --- a/externals/grill/py/source/pyargs.cpp +++ b/externals/grill/py/source/pyargs.cpp @@ -126,6 +126,47 @@ PyObject *pybase::MakePyArg(const t_symbol *s,int argc,const t_atom *argv) return ret; } +inline bool issym(PyObject *p) +{ + return PyString_Check(p) || pySymbol_Check(p); +} + +inline bool isseq(PyObject *p) +{ + return PySequence_Check(p) && !issym(p); +} + +const t_symbol *pybase::getone(t_atom &at,PyObject *arg) +{ + if(PyInt_Check(arg)) { flext::SetInt(at,PyInt_AsLong(arg)); return sym_fint; } + else if(PyLong_Check(arg)) { flext::SetInt(at,PyLong_AsLong(arg)); return sym_fint; } + else if(PyFloat_Check(arg)) { flext::SetFloat(at,(float)PyFloat_AsDouble(arg)); return flext::sym_float; } + else if(pySymbol_Check(arg)) { flext::SetSymbol(at,pySymbol_AS_SYMBOL(arg)); return flext::sym_symbol; } + else if(PyString_Check(arg)) { flext::SetString(at,PyString_AS_STRING(arg)); return flext::sym_symbol; } + else { + PyObject *tp = PyObject_Type(arg); + PyObject *stp = tp?PyObject_Str(tp):NULL; + char *tmp = ""; + if(stp) tmp = PyString_AS_STRING(stp); + flext::post("py/pyext: Could not convert argument %s",tmp); + Py_XDECREF(stp); + Py_XDECREF(tp); + + flext::SetSymbol(at,flext::sym__); + return sym_symbol; + } +} + +const t_symbol *pybase::getlist(t_atom *lst,PyObject *seq,int cnt,int offs) +{ + for(int ix = 0; ix < cnt; ++ix) { + PyObject *arg = PySequence_GetItem(seq,ix+offs); // new reference + getone(lst[ix],arg); + Py_DECREF(arg); + } + return flext::sym_list; +} + const t_symbol *pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs) { if(pValue == NULL) return false; @@ -134,66 +175,36 @@ const t_symbol *pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs) if(pValue == Py_None) return sym_bang; // analyze return value or tuple - int rargc = 0; - retval tp = nothing; + const t_symbol *sym = NULL; - if(PyString_Check(pValue) || pySymbol_Check(pValue)) { - rargc = 1; - tp = atom; - } - else if(PySequence_Check(pValue)) { - rargc = PySequence_Size(pValue); - tp = sequ; + if(isseq(pValue)) { + int rargc = PySequence_Size(pValue); + if(rargc == 2) { + // check if syntax is symbol/string, list -> anything message + PyObject *s = PySequence_GetItem(pValue,0); + PyObject *l = PySequence_GetItem(pValue,1); + + if(issym(s) && isseq(l)) { + // is anything message + rargc = PySequence_Size(l); + lst(offs+rargc); + getlist(lst.Atoms(),l,rargc); + sym = pyObject_AsSymbol(s); + } + + Py_DECREF(s); + Py_DECREF(l); + } + else { + lst(offs+rargc); + sym = getlist(lst.Atoms(),pValue,rargc); + } } else { - rargc = 1; - tp = atom; + lst(offs+1); + sym = getone(lst[offs],pValue); } -// else -// Py_DECREF(pValue); - - lst(offs+rargc); - - const t_symbol *sym = NULL; - - for(int ix = 0; ix < rargc; ++ix) { - PyObject *arg; - if(tp == sequ) - arg = PySequence_GetItem(pValue,ix); // new reference - else - arg = pValue; - - t_atom &at = lst[offs+ix]; - if(PyInt_Check(arg)) { SetInt(at,PyInt_AsLong(arg)); sym = sym_fint; } - else if(PyLong_Check(arg)) { SetInt(at,PyLong_AsLong(arg)); sym = sym_fint; } - else if(PyFloat_Check(arg)) { SetFloat(at,(float)PyFloat_AsDouble(arg)); sym = sym_float; } - else if(pySymbol_Check(arg)) { SetSymbol(at,pySymbol_AS_SYMBOL(arg)); sym = sym_symbol; } - else if(PyString_Check(arg)) { SetString(at,PyString_AS_STRING(arg)); sym = sym_symbol; } -/* - else if(ix == 0 && self && PyInstance_Check(arg)) { - // assumed to be self ... that should be checked _somehow_ !!! - Py_INCREF(arg); - *self = arg; - } -*/ - else { - PyObject *tp = PyObject_Type(arg); - PyObject *stp = tp?PyObject_Str(tp):NULL; - char *tmp = ""; - if(stp) tmp = PyString_AS_STRING(stp); - post("py/pyext: Could not convert argument %s",tmp); - Py_XDECREF(stp); - Py_XDECREF(tp); - - SetSymbol(at,sym__); sym = sym_symbol; - } - - if(tp == sequ) - Py_DECREF(arg); - } - - if(sym && tp == sequ) sym = sym_list; return sym; } diff --git a/externals/grill/py/source/pybase.cpp b/externals/grill/py/source/pybase.cpp index 3bc589de..65c4369d 100644 --- a/externals/grill/py/source/pybase.cpp +++ b/externals/grill/py/source/pybase.cpp @@ -568,7 +568,7 @@ bool pybase::gencall(PyObject *pmeth,PyObject *pargs) // Now call method switch(detach) { case 0: - ret = callpy(pmeth,pargs); + ret = docall(pmeth,pargs); Py_DECREF(pargs); Py_DECREF(pmeth); break; @@ -591,6 +591,24 @@ bool pybase::gencall(PyObject *pmeth,PyObject *pargs) return ret; } +void pybase::exchandle() +{ +#if 0 + // want to use that, but exception keeps a reference to the object + PyErr_Print(); +#else + // must use that instead... clear the exception + PyObject *type,*value,*traceback; + PyErr_Fetch(&type,&value,&traceback); + PyErr_NormalizeException(&type,&value,&traceback); + PyErr_Display(type,value,traceback); + + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); +#endif +} + void pybase::work_wrapper(void *data) { FLEXT_ASSERT(data); @@ -603,7 +621,7 @@ void pybase::work_wrapper(void *data) // call worker work_data *w = (work_data *)data; - callpy(w->fun,w->args); + docall(w->fun,w->args); delete w; PyUnlock(state); @@ -634,7 +652,7 @@ void pybase::threadworker() while(el = qufifo.Get()) { ++thrcount; state = PyLock(my); - callpy(el->fun,el->args); + docall(el->fun,el->args); Py_XDECREF(el->fun); Py_XDECREF(el->args); PyUnlock(state); diff --git a/externals/grill/py/source/pybase.h b/externals/grill/py/source/pybase.h index 068aeb86..f7b6840b 100644 --- a/externals/grill/py/source/pybase.h +++ b/externals/grill/py/source/pybase.h @@ -89,7 +89,7 @@ protected: static bool IsAnything(const t_symbol *s) { return s && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; } static bool IsAtom(const t_symbol *s) { return s == sym_float || s == sym_int || s == sym_symbol || s == sym_pointer; } - enum retval { nothing,atom,sequ }; +// enum retval { nothing,atom,sequ }; // --- module stuff ----- @@ -136,8 +136,22 @@ protected: bool xlate; bool gencall(PyObject *fun,PyObject *args); + + bool docall(PyObject *fun,PyObject *args) + { + callpy(fun,args); + if(PyErr_Occurred()) { + exchandle(); + return false; + } + else + return true; + } + virtual bool thrcall(void *data) = 0; - virtual bool callpy(PyObject *fun,PyObject *args) = 0; + virtual void callpy(PyObject *fun,PyObject *args) = 0; + + void exchandle(); #if FLEXT_SYS == FLEXT_SYS_MAX static short patcher_myvol(t_patcher *x); @@ -164,6 +178,9 @@ protected: static const t_symbol *sym_fint; // float or int symbol, depending on native number message type + static const t_symbol *getone(t_atom &at,PyObject *arg); + static const t_symbol *getlist(t_atom *lst,PyObject *seq,int cnt,int offs = 0); + public: #ifdef FLEXT_THREADS diff --git a/externals/grill/py/source/pyext.cpp b/externals/grill/py/source/pyext.cpp index 593c8bd1..a48a45ed 100644 --- a/externals/grill/py/source/pyext.cpp +++ b/externals/grill/py/source/pyext.cpp @@ -506,18 +506,13 @@ void pyext::m_help() post(""); } -bool pyext::callpy(PyObject *fun,PyObject *args) +void pyext::callpy(PyObject *fun,PyObject *args) { PyObject *ret = PyObject_CallObject(fun,args); - if(ret == NULL) { - // function not found resp. arguments not matching - PyErr_Print(); - return false; - } - else { + if(ret) { + // function worked fine if(!PyObject_Not(ret)) post("pyext - returned value is ignored"); Py_DECREF(ret); - return true; } } @@ -536,8 +531,10 @@ bool pyext::call(const char *meth,int inlet,const t_symbol *s,int argc,const t_a PyErr_Print(); Py_DECREF(pmeth); } - else - ret = gencall(pmeth,pargs); + else { + gencall(pmeth,pargs); + ret = true; + } } return ret; } diff --git a/externals/grill/py/source/pyext.h b/externals/grill/py/source/pyext.h index 7fe0cc68..361eda5d 100644 --- a/externals/grill/py/source/pyext.h +++ b/externals/grill/py/source/pyext.h @@ -114,7 +114,7 @@ private: bool call(const char *meth,int inlet,const t_symbol *s,int argc,const t_atom *argv); virtual bool thrcall(void *data); - virtual bool callpy(PyObject *fun,PyObject *args); + virtual void callpy(PyObject *fun,PyObject *args); static bool stcallpy(PyObject *fun,PyObject *args); PyThreadState *pythr; diff --git a/externals/grill/py/source/pymeth.cpp b/externals/grill/py/source/pymeth.cpp index 8c80bd43..e2278d1c 100644 --- a/externals/grill/py/source/pymeth.cpp +++ b/externals/grill/py/source/pymeth.cpp @@ -131,7 +131,7 @@ protected: private: - virtual bool callpy(PyObject *fun,PyObject *args); + virtual void callpy(PyObject *fun,PyObject *args); static void Setup(t_classid c); @@ -360,19 +360,12 @@ void pymeth::Unload() SetFunction(NULL); } -bool pymeth::callpy(PyObject *fun,PyObject *args) +void pymeth::callpy(PyObject *fun,PyObject *args) { PyObject *ret = PyObject_CallObject(fun,args); - if(ret == NULL) { - // function not found resp. arguments not matching - PyErr_Print(); - return false; - } - else { - if(ret != Py_None && !OutObject(this,0,ret) && PyErr_Occurred()) - PyErr_Print(); + if(ret) { + OutObject(this,0,ret); // exception might be raised here Py_DECREF(ret); - return true; } } @@ -421,7 +414,8 @@ bool pymeth::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv) PyTuple_SET_ITEM(pargs,i-1,objects[i]); } - ret = gencall(function,pargs); // references are stolen + gencall(function,pargs); // references are stolen + ret = true; } else PyErr_SetString(PyExc_RuntimeError,"No function set"); -- cgit v1.2.1