From c2645dc4003b1391aba9b387a79a66cff1e63d3e Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Tue, 22 Oct 2002 23:16:30 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r189, which included commits to RCS files with non-trunk default branches. svn path=/trunk/; revision=190 --- externals/grill/py/source/py.cpp | 327 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 externals/grill/py/source/py.cpp (limited to 'externals/grill/py/source/py.cpp') diff --git a/externals/grill/py/source/py.cpp b/externals/grill/py/source/py.cpp new file mode 100644 index 00000000..83c5d9b5 --- /dev/null +++ b/externals/grill/py/source/py.cpp @@ -0,0 +1,327 @@ +/* + +py/pyext - python script object for PD and MaxMSP + +Copyright (c) 2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +#include "main.h" + + +class pyobj: + public py +{ + FLEXT_HEADER(pyobj,py) + +public: + pyobj(I argc,t_atom *argv); + ~pyobj(); + +protected: + BL m_method_(I n,const t_symbol *s,I argc,t_atom *argv); + + V work(const t_symbol *s,I argc,t_atom *argv); + + V m_bang() { work(sym_bang,0,NULL); } + V m_reload(); + V m_reload_(I argc,t_atom *argv); + V m_set(I argc,t_atom *argv); + V m_doc_(); + + virtual V m_help(); + + // methods for python arguments + V callwork(const t_symbol *s,I argc,t_atom *argv); + + V m_py_list(I argc,t_atom *argv) { callwork(sym_list,argc,argv); } + V m_py_float(I argc,t_atom *argv) { callwork(sym_float,argc,argv); } + V m_py_int(I argc,t_atom *argv) { callwork(sym_int,argc,argv); } + V m_py_any(const t_symbol *s,I argc,t_atom *argv) { callwork(s,argc,argv); } + + const t_symbol *funname; + PyObject *function; + + virtual V Reload(); + + V SetFunction(const C *func); + V ResetFunction(); + +private: + + FLEXT_CALLBACK(m_bang) + FLEXT_CALLBACK(m_reload) + FLEXT_CALLBACK_V(m_reload_) + FLEXT_CALLBACK_V(m_set) + FLEXT_CALLBACK(m_doc_) + + FLEXT_CALLBACK_V(m_py_float) + FLEXT_CALLBACK_V(m_py_list) + FLEXT_CALLBACK_V(m_py_int) + FLEXT_CALLBACK_A(m_py_any) + +#ifdef FLEXT_THREADS + FLEXT_THREAD_A(work) +#else + FLEXT_CALLBACK_A(work) +#endif +}; + +FLEXT_LIB_V("py",pyobj) + + +pyobj::pyobj(I argc,t_atom *argv): + function(NULL),funname(NULL) +{ + PY_LOCK + + AddInAnything(2); + AddOutAnything(); + + FLEXT_ADDBANG(0,m_bang); + FLEXT_ADDMETHOD_(0,"reload",m_reload_); + FLEXT_ADDMETHOD_(0,"reload.",m_reload); + FLEXT_ADDMETHOD_(0,"set",m_set); + FLEXT_ADDMETHOD_(0,"doc",m_doc); + FLEXT_ADDMETHOD_(0,"doc+",m_doc_); +#ifdef FLEXT_THREADS + FLEXT_ADDMETHOD_(0,"detach",m_detach); + FLEXT_ADDMETHOD_(0,"stop",m_stop); +#endif + + FLEXT_ADDMETHOD_(1,"float",m_py_float); + FLEXT_ADDMETHOD_(1,"int",m_py_int); + FLEXT_ADDMETHOD(1,m_py_list); + FLEXT_ADDMETHOD(1,m_py_any); + + if(argc > 2) + SetArgs(argc-2,argv+2); + else + SetArgs(0,NULL); + + // init script module + if(argc >= 1) { + C dir[1024]; + GetModulePath(GetString(argv[0]),dir,sizeof(dir)); + // set script path + AddToPath(dir); + + if(!IsString(argv[0])) + post("%s - script name argument is invalid",thisName()); + else + ImportModule(GetString(argv[0])); + } + + Register("_py"); + + if(argc >= 2) { + // set function name + if(!IsString(argv[1])) + post("%s - function name argument is invalid",thisName()); + else { + // Set function + SetFunction(GetString(argv[1])); + } + } + + PY_UNLOCK +} + +pyobj::~pyobj() +{ + PY_LOCK + Unregister("_py"); + PY_UNLOCK +} + + + + +BL pyobj::m_method_(I n,const t_symbol *s,I argc,t_atom *argv) +{ + if(n == 1) + post("%s - no method for type %s",thisName(),GetString(s)); + return false; +} + +V pyobj::m_reload() +{ + PY_LOCK + + Unregister("_py"); + + ReloadModule(); + Reregister("_py"); + Register("_py"); + SetFunction(funname?GetString(funname):NULL); + + PY_UNLOCK +} + +V pyobj::m_reload_(I argc,t_atom *argv) +{ + PY_LOCK + SetArgs(argc,argv); + PY_UNLOCK + + m_reload(); +} + +V pyobj::m_set(I argc,t_atom *argv) +{ + PY_LOCK + + I ix = 0; + if(argc >= 2) { + if(!IsString(argv[ix])) { + post("%s - script name is not valid",thisName()); + return; + } + const C *sn = GetString(argv[ix]); + + if(!module || !strcmp(sn,PyModule_GetName(module))) { + ImportModule(sn); + Register("_py"); + } + + ++ix; + } + + if(!IsString(argv[ix])) + post("%s - function name is not valid",thisName()); + else + SetFunction(GetString(argv[ix])); + + PY_UNLOCK +} + + +V pyobj::m_doc_() +{ + PY_LOCK + + if(function) { + PyObject *docf = PyObject_GetAttrString(function,"__doc__"); // borrowed!!! + if(docf && PyString_Check(docf)) { + post(""); + post(PyString_AsString(docf)); + } + } + + PY_UNLOCK +} + + +V pyobj::m_help() +{ + post(""); + post("py %s - python script object, (C)2002 Thomas Grill",PY__VERSION); +#ifdef _DEBUG + post("compiled on " __DATE__ " " __TIME__); +#endif + + post("Arguments: %s [script name] [function 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"); +#ifdef FLEXT_THREADS + post("\tdetach 0/1: detach threads"); + post("\tstop {wait time (ms)}: stop threads"); +#endif + post(""); +} + +V pyobj::ResetFunction() +{ + if(!module || !dict) + { + post("%s - No module loaded",thisName()); + function = NULL; + return; + } + + function = funname?PyDict_GetItemString(dict,(C *)GetString(funname)):NULL; // borrowed!!! + if(!function) { + PyErr_Clear(); + if(funname) post("%s - Function %s could not be found",thisName(),GetString(funname)); + } + else if(!PyFunction_Check(function)) { + post("%s - Object %s is not a function",thisName(),GetString(funname)); + function = NULL; + } +} + +V pyobj::SetFunction(const C *func) +{ + if(func) { + funname = MakeSymbol(func); + ResetFunction(); + } + else + function = NULL,funname = NULL; +} + + +V pyobj::Reload() +{ + ResetFunction(); +} + + +V pyobj::work(const t_symbol *s,I argc,t_atom *argv) +{ + AtomList *rargs = NULL; + + ++thrcount; + PY_LOCK + + if(function) { + PyObject *pArgs = MakePyArgs(s,AtomList(argc,argv)); + PyObject *pValue = PyObject_CallObject(function, pArgs); + + rargs = GetPyArgs(pValue); + if(!rargs) PyErr_Print(); + + Py_XDECREF(pArgs); + Py_XDECREF(pValue); + } + else { + post("%s: no function defined",thisName()); + } + + PY_UNLOCK + --thrcount; + + if(rargs) { + // call to outlet _outside_ the Mutex lock! + // otherwise (if not detached) deadlock will occur + ToOutList(0,*rargs); + delete rargs; + } +} + +V pyobj::callwork(const t_symbol *s,I argc,t_atom *argv) +{ + if(detach) { + if(shouldexit) + post("%s - New threads can't be launched now!",thisName()); + else + if(!FLEXT_CALLMETHOD_A(work,s,argc,argv)) + post("%s - Failed to launch thread!",thisName()); + } + else + work(s,argc,argv); +} + + -- cgit v1.2.1