From 03c7468fcc51888c8271b904e4d6400ed5c1cbb1 Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Wed, 7 Mar 2007 13:40:14 +0000 Subject: multiply inlets for py (hot and cold inlets) small optimizations and fixes use PyGILState_\*() functionality (enabled with PY_USE_GIL) updates for DSP processing __str__ method for pyext, to enable print self calls added message bundle functionality (pyext.Bundle class) enable compiled-only scripts (without .py) enable optimization of Python code in reease build let _inlets and _outlets default to 0 fix for numpy some ASSERTs for explicitly created pyext classes (should be runtime checks i guess) open editor for script under OS X fixing numpy initialization quirks enable symbol binding for all callables (not only functions and methods) _isthreaded is now a data member instead of a method fix for gcc4 added pyext._list and pyext._tuple to convert input lists to Python sequence objects enable module packages (module/__init__.py[co]), now also for Max python-like dotted module.function syntax cleaned up float vs. int pyext tags compiler flag to exclude DSP objects some optimizations and py reload fix more safety for calls where association python-pd has already been removed always run Python interpreter in the background svn path=/trunk/; revision=7474 --- externals/grill/py/source/pymeth.cpp | 856 +++++++++++++++++------------------ 1 file changed, 428 insertions(+), 428 deletions(-) (limited to 'externals/grill/py/source/pymeth.cpp') diff --git a/externals/grill/py/source/pymeth.cpp b/externals/grill/py/source/pymeth.cpp index 3bc90ee2..ff0d6b83 100644 --- a/externals/grill/py/source/pymeth.cpp +++ b/externals/grill/py/source/pymeth.cpp @@ -1,428 +1,428 @@ -/* - -py/pyext - python script object for PD and Max/MSP - -Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org) -For information on usage and redistribution, and for a DISCLAIMER OF ALL -WARRANTIES, see the file, "license.txt," in this distribution. - -*/ - -#include "pybase.h" -#include - -struct xlt { const t_symbol *from,*to; }; - -static const xlt xtdefs[] = { - { flext::MakeSymbol("+"),flext::MakeSymbol("__add__") }, - { flext::MakeSymbol("+="),flext::MakeSymbol("__iadd__") }, - { flext::MakeSymbol("!+"),flext::MakeSymbol("__radd__") }, - { flext::MakeSymbol("-"),flext::MakeSymbol("__sub__") }, - { flext::MakeSymbol("-="),flext::MakeSymbol("__isub__") }, - { flext::MakeSymbol("!-"),flext::MakeSymbol("__rsub__") }, - { flext::MakeSymbol("*"),flext::MakeSymbol("__mul__") }, - { flext::MakeSymbol("*="),flext::MakeSymbol("__imul__") }, - { flext::MakeSymbol("!*"),flext::MakeSymbol("__rmul__") }, - { flext::MakeSymbol("/"),flext::MakeSymbol("__div__") }, - { flext::MakeSymbol("/="),flext::MakeSymbol("__idiv__") }, - { flext::MakeSymbol("!/"),flext::MakeSymbol("__rdiv__") }, - { flext::MakeSymbol("//"),flext::MakeSymbol("__floordiv__") }, - { flext::MakeSymbol("//="),flext::MakeSymbol("__ifloordiv__") }, - { flext::MakeSymbol("!//"),flext::MakeSymbol("__rfloordiv__") }, - { flext::MakeSymbol("%"),flext::MakeSymbol("__mod__") }, - { flext::MakeSymbol("%="),flext::MakeSymbol("__imod__") }, - { flext::MakeSymbol("!%"),flext::MakeSymbol("__rmod__") }, - { flext::MakeSymbol("**"),flext::MakeSymbol("__pow__") }, - { flext::MakeSymbol("**="),flext::MakeSymbol("__ipow__") }, - { flext::MakeSymbol("!**"),flext::MakeSymbol("__rpow__") }, - { flext::MakeSymbol("&"),flext::MakeSymbol("__and__") }, - { flext::MakeSymbol("&="),flext::MakeSymbol("__iand__") }, - { flext::MakeSymbol("!&"),flext::MakeSymbol("__rand__") }, - { flext::MakeSymbol("|"),flext::MakeSymbol("__or__") }, - { flext::MakeSymbol("|="),flext::MakeSymbol("__ior__") }, - { flext::MakeSymbol("!|"),flext::MakeSymbol("__ror__") }, - { flext::MakeSymbol("^"),flext::MakeSymbol("__xor__") }, - { flext::MakeSymbol("^="),flext::MakeSymbol("__ixor__") }, - { flext::MakeSymbol("!^"),flext::MakeSymbol("__rxor__") }, - { flext::MakeSymbol("<<"),flext::MakeSymbol("__lshift__") }, - { flext::MakeSymbol("<<="),flext::MakeSymbol("__ilshift__") }, - { flext::MakeSymbol("!<<"),flext::MakeSymbol("__rlshift__") }, - { flext::MakeSymbol(">>"),flext::MakeSymbol("__rshift__") }, - { flext::MakeSymbol(">>="),flext::MakeSymbol("__irshift__") }, - { flext::MakeSymbol("!>>"),flext::MakeSymbol("__rrshift__") }, - { flext::MakeSymbol("=="),flext::MakeSymbol("__eq__") }, - { flext::MakeSymbol("!="),flext::MakeSymbol("__ne__") }, - { flext::MakeSymbol("<"),flext::MakeSymbol("__lt__") }, - { flext::MakeSymbol(">"),flext::MakeSymbol("__gt__") }, - { flext::MakeSymbol("<="),flext::MakeSymbol("__le__") }, - { flext::MakeSymbol(">="),flext::MakeSymbol("__ge__") }, - { flext::MakeSymbol("!"),flext::MakeSymbol("__nonzero__") }, - { flext::MakeSymbol("~"),flext::MakeSymbol("__invert__") }, - { flext::MakeSymbol("[]"),flext::MakeSymbol("__getitem__") }, - { flext::MakeSymbol("[]="),flext::MakeSymbol("__setitem__") }, - { flext::MakeSymbol("[:]"),flext::MakeSymbol("__getslice__") }, - { flext::MakeSymbol("[:]="),flext::MakeSymbol("__setslice__") }, - - { flext::MakeSymbol(".abs"),flext::MakeSymbol("__abs__") }, - { flext::MakeSymbol(".neg"),flext::MakeSymbol("__neg__") }, - { flext::MakeSymbol(".pos"),flext::MakeSymbol("__pos__") }, - { flext::MakeSymbol(".divmod"),flext::MakeSymbol("__divmod__") }, - - { flext::MakeSymbol(".int"),flext::MakeSymbol("__int__") }, - { flext::MakeSymbol(".long"),flext::MakeSymbol("__long__") }, - { flext::MakeSymbol(".float"),flext::MakeSymbol("__float__") }, - { flext::MakeSymbol(".complex"),flext::MakeSymbol("__complex__") }, - { flext::MakeSymbol(".str"),flext::MakeSymbol("__str__") }, - { flext::MakeSymbol(".coerce"),flext::MakeSymbol("__coerce__") }, - - { flext::MakeSymbol(".doc"),flext::MakeSymbol("__doc__") }, - { flext::MakeSymbol(".repr"),flext::MakeSymbol("__repr__") }, - - { flext::MakeSymbol(".len"),flext::MakeSymbol("__len__") }, - { flext::MakeSymbol(".in"),flext::MakeSymbol("__contains") }, - - { NULL,NULL } // sentinel -}; - -typedef std::map XTable; -static XTable xtable; - - -class pymeth - : public pybase - , public flext_base -{ - FLEXT_HEADER_S(pymeth,flext_base,Setup) - -public: - pymeth(int argc,const t_atom *argv); - ~pymeth(); - -protected: - virtual void Exit(); - - virtual bool CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv); - - void m_help(); - - void m_reload() { Reload(); } - void m_reload_(int argc,const t_atom *argv) { args(argc,argv); Reload(); } - void m_set(int argc,const t_atom *argv); - void m_dir_() { m__dir(function); } - void m_doc_() { m__doc(function); } - - const t_symbol *funname; - PyObject *function; - - virtual void LoadModule(); - virtual void UnloadModule(); - - virtual void Load(); - virtual void Unload(); - - void SetFunction(const t_symbol *func); - void ResetFunction(); - - virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv); - - PyObject **objects; - -private: - - virtual void callpy(PyObject *fun,PyObject *args); - - static void Setup(t_classid c); - - FLEXT_CALLBACK(m_help) - FLEXT_CALLBACK(m_reload) - FLEXT_CALLBACK_V(m_reload_) - FLEXT_CALLBACK_V(m_set) - FLEXT_CALLBACK(m_dir_) - FLEXT_CALLBACK(m_doc_) - - // callbacks - FLEXT_ATTRVAR_I(detach) - FLEXT_ATTRVAR_B(pymsg) - FLEXT_ATTRVAR_B(respond) - - FLEXT_CALLBACK_V(m_stop) - FLEXT_CALLBACK(m_dir) - FLEXT_CALLGET_V(mg_dir) - FLEXT_CALLBACK(m_doc) - -#ifdef FLEXT_THREADS - FLEXT_CALLBACK_T(tick) -#endif -}; - -FLEXT_LIB_V("pym",pymeth) - - -void pymeth::Setup(t_classid c) -{ - FLEXT_CADDMETHOD_(c,0,"doc",m_doc); - FLEXT_CADDMETHOD_(c,0,"dir",m_dir); -#ifdef FLEXT_THREADS - FLEXT_CADDATTR_VAR1(c,"detach",detach); - FLEXT_CADDMETHOD_(c,0,"stop",m_stop); -#endif - - FLEXT_CADDMETHOD_(c,0,"help",m_help); - FLEXT_CADDMETHOD_(c,0,"reload",m_reload_); - FLEXT_CADDMETHOD_(c,0,"reload.",m_reload); - FLEXT_CADDMETHOD_(c,0,"doc+",m_doc_); - FLEXT_CADDMETHOD_(c,0,"dir+",m_dir_); - - FLEXT_CADDMETHOD_(c,0,"set",m_set); - - FLEXT_CADDATTR_VAR1(c,"py",pymsg); - FLEXT_CADDATTR_VAR1(c,"respond",respond); - - // init translation map - for(const xlt *xi = xtdefs; xi->from; ++xi) xtable[xi->from] = xi->to; -} - -pymeth::pymeth(int argc,const t_atom *argv) - : funname(NULL) - , function(NULL) - , objects(NULL) -{ -#ifdef FLEXT_THREADS - FLEXT_ADDTIMER(stoptmr,tick); -#endif - - PyThreadState *state = PyLockSys(); - - int inlets; - if(argc && CanbeInt(*argv)) { - inlets = GetAInt(*argv); - if(inlets < 1) inlets = 1; - argv++,argc--; - } - else inlets = 1; - - objects = new PyObject *[inlets]; - for(int i = 0; i < inlets; ++i) { objects[i] = Py_None; Py_INCREF(Py_None); } - - if(inlets <= 0) InitProblem(); - - AddInAnything(1+(inlets < 0?1:inlets)); - AddOutAnything(); - - Register(GetRegistry(REGNAME)); - - if(argc) { - const t_symbol *funnm = GetASymbol(*argv); - argv++,argc--; - - if(funnm) - SetFunction(funnm); - else - PyErr_SetString(PyExc_ValueError,"Invalid function name"); - } - - if(argc) args(argc,argv); - - Report(); - - PyUnlock(state); -} - -pymeth::~pymeth() -{ - if(objects) { - for(int i = 0; i < CntIn()-1; ++i) Py_DECREF(objects[i]); - delete[] objects; - } - - PyThreadState *state = PyLockSys(); - Unregister(GetRegistry(REGNAME)); - Report(); - PyUnlock(state); -} - -void pymeth::Exit() -{ - pybase::Exit(); - flext_base::Exit(); -} - -void pymeth::m_set(int argc,const t_atom *argv) -{ - PyThreadState *state = PyLockSys(); - - // function name has precedence - if(argc >= 2) { - const char *sn = GetAString(*argv); - ++argv,--argc; - - if(sn) { - if(!module || !strcmp(sn,PyModule_GetName(module))) { - ImportModule(sn); - Register(GetRegistry(REGNAME)); - } - } - else - PyErr_SetString(PyExc_ValueError,"Invalid module name"); - } - - if(argc) { - const t_symbol *fn = GetASymbol(*argv); - if(fn) - SetFunction(fn); - else - PyErr_SetString(PyExc_ValueError,"Invalid function name"); - } - - Report(); - - PyUnlock(state); -} - -void pymeth::m_help() -{ - post(""); - post("%s %s - python method object, (C)2002-2005 Thomas Grill",thisName(),PY__VERSION); -#ifdef FLEXT_DEBUG - post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__); -#endif - - post("Arguments: %s [method name] {args...}",thisName()); - - post("Inlet 1:messages to control the py object"); - post(" 2:call python function with message as argument(s)"); - post("Outlet: 1:return values from python function"); - post("Methods:"); - post("\thelp: shows this help"); - post("\tbang: call script without arguments"); - post("\tset [script name] [function name]: set (script and) function name"); - post("\treload {args...}: reload python script"); - post("\treload. : reload with former arguments"); - post("\tdoc: display module doc string"); - post("\tdoc+: display function doc string"); - post("\tdir: dump module dictionary"); - post("\tdir+: dump function dictionary"); -#ifdef FLEXT_THREADS - post("\tdetach 0/1/2: detach threads"); - post("\tstop {wait time (ms)}: stop threads"); -#endif - post(""); -} - -void pymeth::ResetFunction() -{ - Py_XDECREF(function); - function = NULL; - - if(funname && objects[0] != Py_None) { - function = PyObject_GetAttrString(objects[0],(char *)GetString(funname)); // new reference - if(!function) - PyErr_SetString(PyExc_AttributeError,"Method not found"); - } - - // exception could be set here -} - -void pymeth::SetFunction(const t_symbol *func) -{ - // look for method name in translation table - XTable::iterator it = xtable.find(func); - funname = it == xtable.end()?func:it->second; - - ResetFunction(); -} - - -void pymeth::LoadModule() -{ - SetFunction(funname); -} - -void pymeth::UnloadModule() -{ -} - -void pymeth::Load() -{ - ResetFunction(); -} - -void pymeth::Unload() -{ - SetFunction(NULL); -} - -void pymeth::callpy(PyObject *fun,PyObject *args) -{ - PyObject *ret = PyObject_CallObject(fun,args); - if(ret) { - OutObject(this,0,ret); // exception might be raised here - Py_DECREF(ret); - } -} - -bool pymeth::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv) -{ - if(n == 0 && s != sym_bang) - return flext_base::CbMethodResort(n,s,argc,argv); - - PyThreadState *state = PyLockSys(); - - bool ret = false; - - if(n >= 1) { - // store args - PyObject *&obj = objects[n-1]; - Py_DECREF(obj); - obj = MakePyArg(s,argc,argv); // steal reference - - if(n > 1) ret = true; // just store, don't trigger - } - - if(!ret) { - if(function) { - PyObject *self = PyMethod_Self(function); - PyErr_Clear(); - if(!self || self->ob_type != objects[0]->ob_type) - // type has changed, search for new method - ResetFunction(); - else if(self != objects[0]) { - // type hasn't changed, but object has - PyObject *f = function; - function = PyMethod_New(PyMethod_GET_FUNCTION(f),objects[0],PyMethod_GET_CLASS(f)); - Py_DECREF(f); - } - } - else - ResetFunction(); - - if(function) { - Py_INCREF(function); - - int inlets = CntIn()-1; - PyObject *pargs = PyTuple_New(inlets-1); - for(int i = 1; i < inlets; ++i) { - Py_INCREF(objects[i]); - PyTuple_SET_ITEM(pargs,i-1,objects[i]); - } - - gencall(function,pargs); // references are stolen - ret = true; - } - else - PyErr_SetString(PyExc_RuntimeError,"No function set"); - - Report(); - } - - PyUnlock(state); - - Respond(ret); - - return ret; -} - -void pymeth::DumpOut(const t_symbol *sym,int argc,const t_atom *argv) -{ - ToOutAnything(GetOutAttr(),sym?sym:thisTag(),argc,argv); -} +/* + +py/pyext - python script object for PD and Max/MSP + +Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +#include "pybase.h" +#include + +struct xlt { const t_symbol *from,*to; }; + +static const xlt xtdefs[] = { + { flext::MakeSymbol("+"),flext::MakeSymbol("__add__") }, + { flext::MakeSymbol("+="),flext::MakeSymbol("__iadd__") }, + { flext::MakeSymbol("!+"),flext::MakeSymbol("__radd__") }, + { flext::MakeSymbol("-"),flext::MakeSymbol("__sub__") }, + { flext::MakeSymbol("-="),flext::MakeSymbol("__isub__") }, + { flext::MakeSymbol("!-"),flext::MakeSymbol("__rsub__") }, + { flext::MakeSymbol("*"),flext::MakeSymbol("__mul__") }, + { flext::MakeSymbol("*="),flext::MakeSymbol("__imul__") }, + { flext::MakeSymbol("!*"),flext::MakeSymbol("__rmul__") }, + { flext::MakeSymbol("/"),flext::MakeSymbol("__div__") }, + { flext::MakeSymbol("/="),flext::MakeSymbol("__idiv__") }, + { flext::MakeSymbol("!/"),flext::MakeSymbol("__rdiv__") }, + { flext::MakeSymbol("//"),flext::MakeSymbol("__floordiv__") }, + { flext::MakeSymbol("//="),flext::MakeSymbol("__ifloordiv__") }, + { flext::MakeSymbol("!//"),flext::MakeSymbol("__rfloordiv__") }, + { flext::MakeSymbol("%"),flext::MakeSymbol("__mod__") }, + { flext::MakeSymbol("%="),flext::MakeSymbol("__imod__") }, + { flext::MakeSymbol("!%"),flext::MakeSymbol("__rmod__") }, + { flext::MakeSymbol("**"),flext::MakeSymbol("__pow__") }, + { flext::MakeSymbol("**="),flext::MakeSymbol("__ipow__") }, + { flext::MakeSymbol("!**"),flext::MakeSymbol("__rpow__") }, + { flext::MakeSymbol("&"),flext::MakeSymbol("__and__") }, + { flext::MakeSymbol("&="),flext::MakeSymbol("__iand__") }, + { flext::MakeSymbol("!&"),flext::MakeSymbol("__rand__") }, + { flext::MakeSymbol("|"),flext::MakeSymbol("__or__") }, + { flext::MakeSymbol("|="),flext::MakeSymbol("__ior__") }, + { flext::MakeSymbol("!|"),flext::MakeSymbol("__ror__") }, + { flext::MakeSymbol("^"),flext::MakeSymbol("__xor__") }, + { flext::MakeSymbol("^="),flext::MakeSymbol("__ixor__") }, + { flext::MakeSymbol("!^"),flext::MakeSymbol("__rxor__") }, + { flext::MakeSymbol("<<"),flext::MakeSymbol("__lshift__") }, + { flext::MakeSymbol("<<="),flext::MakeSymbol("__ilshift__") }, + { flext::MakeSymbol("!<<"),flext::MakeSymbol("__rlshift__") }, + { flext::MakeSymbol(">>"),flext::MakeSymbol("__rshift__") }, + { flext::MakeSymbol(">>="),flext::MakeSymbol("__irshift__") }, + { flext::MakeSymbol("!>>"),flext::MakeSymbol("__rrshift__") }, + { flext::MakeSymbol("=="),flext::MakeSymbol("__eq__") }, + { flext::MakeSymbol("!="),flext::MakeSymbol("__ne__") }, + { flext::MakeSymbol("<"),flext::MakeSymbol("__lt__") }, + { flext::MakeSymbol(">"),flext::MakeSymbol("__gt__") }, + { flext::MakeSymbol("<="),flext::MakeSymbol("__le__") }, + { flext::MakeSymbol(">="),flext::MakeSymbol("__ge__") }, + { flext::MakeSymbol("!"),flext::MakeSymbol("__nonzero__") }, + { flext::MakeSymbol("~"),flext::MakeSymbol("__invert__") }, + { flext::MakeSymbol("[]"),flext::MakeSymbol("__getitem__") }, + { flext::MakeSymbol("[]="),flext::MakeSymbol("__setitem__") }, + { flext::MakeSymbol("[:]"),flext::MakeSymbol("__getslice__") }, + { flext::MakeSymbol("[:]="),flext::MakeSymbol("__setslice__") }, + + { flext::MakeSymbol(".abs"),flext::MakeSymbol("__abs__") }, + { flext::MakeSymbol(".neg"),flext::MakeSymbol("__neg__") }, + { flext::MakeSymbol(".pos"),flext::MakeSymbol("__pos__") }, + { flext::MakeSymbol(".divmod"),flext::MakeSymbol("__divmod__") }, + + { flext::MakeSymbol(".int"),flext::MakeSymbol("__int__") }, + { flext::MakeSymbol(".long"),flext::MakeSymbol("__long__") }, + { flext::MakeSymbol(".float"),flext::MakeSymbol("__float__") }, + { flext::MakeSymbol(".complex"),flext::MakeSymbol("__complex__") }, + { flext::MakeSymbol(".str"),flext::MakeSymbol("__str__") }, + { flext::MakeSymbol(".coerce"),flext::MakeSymbol("__coerce__") }, + + { flext::MakeSymbol(".doc"),flext::MakeSymbol("__doc__") }, + { flext::MakeSymbol(".repr"),flext::MakeSymbol("__repr__") }, + + { flext::MakeSymbol(".len"),flext::MakeSymbol("__len__") }, + { flext::MakeSymbol(".in"),flext::MakeSymbol("__contains") }, + + { NULL,NULL } // sentinel +}; + +typedef std::map XTable; +static XTable xtable; + + +class pymeth + : public pybase + , public flext_base +{ + FLEXT_HEADER_S(pymeth,flext_base,Setup) + +public: + pymeth(int argc,const t_atom *argv); + ~pymeth(); + +protected: + virtual void Exit(); + + virtual bool CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv); + + void m_help(); + + void m_reload() { Reload(); } + void m_reload_(int argc,const t_atom *argv) { args(argc,argv); Reload(); } + void m_set(int argc,const t_atom *argv); + void m_dir_() { m__dir(function); } + void m_doc_() { m__doc(function); } + + const t_symbol *funname; + PyObject *function; + + virtual void LoadModule(); + virtual void UnloadModule(); + + virtual void Load(); + virtual void Unload(); + + void SetFunction(const t_symbol *func); + void ResetFunction(); + + virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv); + + PyObject **objects; + +private: + + virtual void callpy(PyObject *fun,PyObject *args); + + static void Setup(t_classid c); + + FLEXT_CALLBACK(m_help) + FLEXT_CALLBACK(m_reload) + FLEXT_CALLBACK_V(m_reload_) + FLEXT_CALLBACK_V(m_set) + FLEXT_CALLBACK(m_dir_) + FLEXT_CALLBACK(m_doc_) + + // callbacks + FLEXT_ATTRVAR_I(detach) + FLEXT_ATTRVAR_B(pymsg) + FLEXT_ATTRVAR_B(respond) + + FLEXT_CALLBACK_V(m_stop) + FLEXT_CALLBACK(m_dir) + FLEXT_CALLGET_V(mg_dir) + FLEXT_CALLBACK(m_doc) + +#ifdef FLEXT_THREADS + FLEXT_CALLBACK_T(tick) +#endif +}; + +FLEXT_LIB_V("pym",pymeth) + + +void pymeth::Setup(t_classid c) +{ + FLEXT_CADDMETHOD_(c,0,"doc",m_doc); + FLEXT_CADDMETHOD_(c,0,"dir",m_dir); +#ifdef FLEXT_THREADS + FLEXT_CADDATTR_VAR1(c,"detach",detach); + FLEXT_CADDMETHOD_(c,0,"stop",m_stop); +#endif + + FLEXT_CADDMETHOD_(c,0,"help",m_help); + FLEXT_CADDMETHOD_(c,0,"reload",m_reload_); + FLEXT_CADDMETHOD_(c,0,"reload.",m_reload); + FLEXT_CADDMETHOD_(c,0,"doc+",m_doc_); + FLEXT_CADDMETHOD_(c,0,"dir+",m_dir_); + + FLEXT_CADDMETHOD_(c,0,"set",m_set); + + FLEXT_CADDATTR_VAR1(c,"py",pymsg); + FLEXT_CADDATTR_VAR1(c,"respond",respond); + + // init translation map + for(const xlt *xi = xtdefs; xi->from; ++xi) xtable[xi->from] = xi->to; +} + +pymeth::pymeth(int argc,const t_atom *argv) + : funname(NULL) + , function(NULL) + , objects(NULL) +{ +#ifdef FLEXT_THREADS + FLEXT_ADDTIMER(stoptmr,tick); +#endif + + ThrState state = PyLockSys(); + + int inlets; + if(argc && CanbeInt(*argv)) { + inlets = GetAInt(*argv); + if(inlets < 1) inlets = 1; + argv++,argc--; + } + else inlets = 1; + + objects = new PyObject *[inlets]; + for(int i = 0; i < inlets; ++i) { objects[i] = Py_None; Py_INCREF(Py_None); } + + if(inlets <= 0) InitProblem(); + + AddInAnything(1+(inlets < 0?1:inlets)); + AddOutAnything(); + + Register(GetRegistry(REGNAME)); + + if(argc) { + const t_symbol *funnm = GetASymbol(*argv); + argv++,argc--; + + if(funnm) + SetFunction(funnm); + else + PyErr_SetString(PyExc_ValueError,"Invalid function name"); + } + + if(argc) args(argc,argv); + + Report(); + + PyUnlock(state); +} + +pymeth::~pymeth() +{ + if(objects) { + for(int i = 0; i < CntIn()-1; ++i) Py_DECREF(objects[i]); + delete[] objects; + } + + ThrState state = PyLockSys(); + Unregister(GetRegistry(REGNAME)); + Report(); + PyUnlock(state); +} + +void pymeth::Exit() +{ + pybase::Exit(); + flext_base::Exit(); +} + +void pymeth::m_set(int argc,const t_atom *argv) +{ + ThrState state = PyLockSys(); + + // function name has precedence + if(argc >= 2) { + const char *sn = GetAString(*argv); + ++argv,--argc; + + if(sn) { + if(!module || !strcmp(sn,PyModule_GetName(module))) { + ImportModule(sn); + Register(GetRegistry(REGNAME)); + } + } + else + PyErr_SetString(PyExc_ValueError,"Invalid module name"); + } + + if(argc) { + const t_symbol *fn = GetASymbol(*argv); + if(fn) + SetFunction(fn); + else + PyErr_SetString(PyExc_ValueError,"Invalid function name"); + } + + Report(); + + PyUnlock(state); +} + +void pymeth::m_help() +{ + post(""); + post("%s %s - python method object, (C)2002-2005 Thomas Grill",thisName(),PY__VERSION); +#ifdef FLEXT_DEBUG + post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__); +#endif + + post("Arguments: %s [method name] {args...}",thisName()); + + post("Inlet 1:messages to control the py object"); + post(" 2:call python function with message as argument(s)"); + post("Outlet: 1:return values from python function"); + post("Methods:"); + post("\thelp: shows this help"); + post("\tbang: call script without arguments"); + post("\tset [script name] [function name]: set (script and) function name"); + post("\treload {args...}: reload python script"); + post("\treload. : reload with former arguments"); + post("\tdoc: display module doc string"); + post("\tdoc+: display function doc string"); + post("\tdir: dump module dictionary"); + post("\tdir+: dump function dictionary"); +#ifdef FLEXT_THREADS + post("\tdetach 0/1/2: detach threads"); + post("\tstop {wait time (ms)}: stop threads"); +#endif + post(""); +} + +void pymeth::ResetFunction() +{ + Py_XDECREF(function); + function = NULL; + + if(funname && objects[0] != Py_None) { + function = PyObject_GetAttrString(objects[0],(char *)GetString(funname)); // new reference + if(!function) + PyErr_SetString(PyExc_AttributeError,"Method not found"); + } + + // exception could be set here +} + +void pymeth::SetFunction(const t_symbol *func) +{ + // look for method name in translation table + XTable::iterator it = xtable.find(func); + funname = it == xtable.end()?func:it->second; + + ResetFunction(); +} + + +void pymeth::LoadModule() +{ + SetFunction(funname); +} + +void pymeth::UnloadModule() +{ +} + +void pymeth::Load() +{ + ResetFunction(); +} + +void pymeth::Unload() +{ + SetFunction(NULL); +} + +void pymeth::callpy(PyObject *fun,PyObject *args) +{ + PyObject *ret = PyObject_CallObject(fun,args); + if(ret) { + OutObject(this,0,ret); // exception might be raised here + Py_DECREF(ret); + } +} + +bool pymeth::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv) +{ + if(n == 0 && s != sym_bang) + return flext_base::CbMethodResort(n,s,argc,argv); + + ThrState state = PyLockSys(); + + bool ret = false; + + if(n >= 1) { + // store args + PyObject *&obj = objects[n-1]; + Py_DECREF(obj); + obj = MakePyArg(s,argc,argv); // steal reference + + if(n > 1) ret = true; // just store, don't trigger + } + + if(!ret) { + if(function) { + PyObject *self = PyMethod_Self(function); + PyErr_Clear(); + if(!self || self->ob_type != objects[0]->ob_type) + // type has changed, search for new method + ResetFunction(); + else if(self != objects[0]) { + // type hasn't changed, but object has + PyObject *f = function; + function = PyMethod_New(PyMethod_GET_FUNCTION(f),objects[0],PyMethod_GET_CLASS(f)); + Py_DECREF(f); + } + } + else + ResetFunction(); + + if(function) { + Py_INCREF(function); + + int inlets = CntIn()-1; + PyObject *pargs = PyTuple_New(inlets-1); + for(int i = 1; i < inlets; ++i) { + Py_INCREF(objects[i]); + PyTuple_SET_ITEM(pargs,i-1,objects[i]); + } + + gencall(function,pargs); // references are stolen + ret = true; + } + else + PyErr_SetString(PyExc_RuntimeError,"No function set"); + + Report(); + } + + PyUnlock(state); + + Respond(ret); + + return ret; +} + +void pymeth::DumpOut(const t_symbol *sym,int argc,const t_atom *argv) +{ + ToOutAnything(GetOutAttr(),sym?sym:thisTag(),argc,argv); +} -- cgit v1.2.1