diff options
-rw-r--r-- | externals/grill/py/pd/simple-1.pd | 4 | ||||
-rw-r--r-- | externals/grill/py/readme.txt | 1 | ||||
-rw-r--r-- | externals/grill/py/source/bound.cpp | 5 | ||||
-rw-r--r-- | externals/grill/py/source/clmeth.cpp | 37 | ||||
-rw-r--r-- | externals/grill/py/source/main.cpp | 81 | ||||
-rw-r--r-- | externals/grill/py/source/main.h | 35 | ||||
-rw-r--r-- | externals/grill/py/source/py.cpp | 48 | ||||
-rw-r--r-- | externals/grill/py/source/pydsp.cpp | 2 | ||||
-rw-r--r-- | externals/grill/py/source/pyext.cpp | 62 | ||||
-rw-r--r-- | externals/grill/py/source/pyext.h | 12 | ||||
-rw-r--r-- | externals/grill/py/source/register.cpp | 70 |
11 files changed, 260 insertions, 97 deletions
diff --git a/externals/grill/py/pd/simple-1.pd b/externals/grill/py/pd/simple-1.pd index d34d43b5..e3ef6754 100644 --- a/externals/grill/py/pd/simple-1.pd +++ b/externals/grill/py/pd/simple-1.pd @@ -1,4 +1,4 @@ -#N canvas 156 192 670 397 12;
+#N canvas 156 192 674 401 12;
#X obj 53 123 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
-1;
#X floatatom 52 155 5 0 0 0 - - -;
@@ -25,6 +25,7 @@ file.; -1 0;
#X text 213 32 http://grrrr.org/ext;
#X text 213 16 Python script objects \, (C)2003-2005 Thomas Grill;
+#X msg 41 246 reload;
#X connect 0 0 9 1;
#X connect 1 0 9 1;
#X connect 3 0 9 1;
@@ -41,3 +42,4 @@ file.; #X connect 15 0 9 0;
#X connect 18 0 9 0;
#X connect 19 0 9 0;
+#X connect 23 0 9 0;
diff --git a/externals/grill/py/readme.txt b/externals/grill/py/readme.txt index 45248f34..526b3299 100644 --- a/externals/grill/py/readme.txt +++ b/externals/grill/py/readme.txt @@ -100,6 +100,7 @@ Version history: - FIX: solved py->py messaging problem with lock count instead of message queuing - ADD: buffer handling with optional numarray support (if present) - ADD: new objects for dsp processing: pyext~,pyx~,pyext.~,pyx.~ +- FIX: correctly report Python errors while contructing the object 0.1.4: - ADD: better (and independent) handling of inlet and outlet count (as class variables or dynamically initialized in __init__) diff --git a/externals/grill/py/source/bound.cpp b/externals/grill/py/source/bound.cpp index 1d10c2d3..a5ace4ee 100644 --- a/externals/grill/py/source/bound.cpp +++ b/externals/grill/py/source/bound.cpp @@ -174,13 +174,14 @@ void pyext::ClearBinding() // in case the object couldn't be constructed... if(!pyobj) return; - FLEXT_ASSERT(GetThis(pyobj)); + pyext *th = GetThis(pyobj); + FLEXT_ASSERT(th); void *data = NULL; const t_symbol *sym = NULL; // unbind all - while(GetThis(pyobj)->UnbindMethod(sym,NULL,&data)) { + while(th->UnbindMethod(sym,NULL,&data)) { bounddata *bdt = (bounddata *)data; if(bdt) { for(FuncSet::iterator it = bdt->funcs.begin(); it != bdt->funcs.end(); ++it) diff --git a/externals/grill/py/source/clmeth.cpp b/externals/grill/py/source/clmeth.cpp index 3f856f57..a8e1ceb7 100644 --- a/externals/grill/py/source/clmeth.cpp +++ b/externals/grill/py/source/clmeth.cpp @@ -124,6 +124,10 @@ PyObject* pyext::pyext_getattr(PyObject *,PyObject *args) pyext *ext = GetThis(self); if(ext) ret = PyLong_FromLong(ext->shouldexit?1:0); + else { + Py_INCREF(Py_True); + ret = Py_True; + } } // post("pyext::getattr %s",sname); } @@ -188,23 +192,20 @@ PyObject *pyext::pyext_outlet(PyObject *,PyObject *args) ext->ToOutList(o-1,lst); else ext->ToOutAtom(o-1,*lst.Atoms()); + ok = true; } else - post("pyext: outlet index out of range"); - - ok = true; + PyErr_SetString(PyExc_ValueError,"pyext - _outlet: index out of range"); } else - post("py/pyext - No data to send"); + PyErr_SetString(PyExc_ValueError,"pyext - _outlet: invalid arguments"); if(!tp) Py_DECREF(val); } - - if(!ok) { + else PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _outlet(self,outlet,args...)"); - return NULL; - } + if(!ok) return NULL; Py_INCREF(Py_None); return Py_None; } @@ -219,12 +220,16 @@ PyObject *pyext::pyext_detach(PyObject *,PyObject *args) int val; if(!PyArg_ParseTuple(args, "Oi:pyext_detach",&self,&val)) { // handle error - PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _detach(self,[0/1])"); + PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _detach(self,[0/1/2])"); + return NULL; + } + else if(val < 0 || val > 2) { + PyErr_SetString(PyExc_ValueError,"pyext - _detach must be in the range 0..2"); return NULL; } else { pyext *ext = GetThis(self); - ext->detach = val != 0; + ext->detach = val; } Py_INCREF(Py_None); @@ -241,6 +246,10 @@ PyObject *pyext::pyext_stop(PyObject *,PyObject *args) PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _stop(self,{wait time})"); return NULL; } + else if(val < 0) { + PyErr_SetString(PyExc_ValueError,"pyext - _stop time must be >= 0"); + return NULL; + } else { pyext *ext = GetThis(self); int cnt; @@ -332,6 +341,10 @@ PyObject *pyext::pyext_invec(PyObject *,PyObject *args) PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _invec(self,inlet)"); return NULL; } + else if(val < 0) { + PyErr_SetString(PyExc_ValueError,"pyext - _invec: index out of range"); + return NULL; + } else { pyext *ext = GetThis(self); PyObject *b = ext->GetSig(val,true); @@ -351,6 +364,10 @@ PyObject *pyext::pyext_outvec(PyObject *,PyObject *args) PyErr_SetString(PyExc_SyntaxError,"pyext - Syntax: _outvec(self,inlet)"); return NULL; } + else if(val < 0) { + PyErr_SetString(PyExc_ValueError,"pyext - _outvec: index out of range"); + return NULL; + } else { pyext *ext = GetThis(self); PyObject *b = ext->GetSig(val,false); diff --git a/externals/grill/py/source/main.cpp b/externals/grill/py/source/main.cpp index fadb0173..fa5169b7 100644 --- a/externals/grill/py/source/main.cpp +++ b/externals/grill/py/source/main.cpp @@ -288,12 +288,9 @@ void pybase::SetArgs() bool pybase::ImportModule(const char *name) { if(!name) return false; - - SetArgs(); - module = PyImport_ImportModule((char *)name); // increases module_obj ref count by one - dict = module?PyModule_GetDict(module):NULL; - - return module != NULL; + if(modname == name) return true; + modname = name; + return ReloadModule(); } void pybase::UnimportModule() @@ -315,22 +312,22 @@ void pybase::UnimportModule() bool pybase::ReloadModule() { bool ok = false; - if(module) { - SetArgs(); - PyObject *newmod = PyImport_ReloadModule(module); - if(!newmod) { - // old module still exists?! -// dict = NULL; - } - else { - Py_XDECREF(module); - module = newmod; - dict = PyModule_GetDict(module); // borrowed - ok = true; - } + + SetArgs(); + PyObject *newmod = module + ?PyImport_ReloadModule(module) + :PyImport_ImportModule((char *)modname.c_str()); + + if(!newmod) { + // unload faulty module + if(module) UnimportModule(); + } + else { + Py_XDECREF(module); + module = newmod; + dict = PyModule_GetDict(module); // borrowed + ok = true; } - else - post("py/pyext - No module to reload"); return ok; } @@ -402,6 +399,48 @@ void pybase::Respond(bool b) } } +void pybase::Reload() +{ + PyThreadState *state = PyLockSys(); + + PyObject *reg = GetRegistry(REGNAME); + + if(reg) { + PyObject *key; + int pos = 0; + while(PyDict_Next(reg,&pos,&key,NULL)) { + pybase *th = (pybase *)PyLong_AsLong(key); + FLEXT_ASSERT(th); + th->Unload(); + } + + UnloadModule(); + } + + bool ok = ReloadModule(); + + if(ok) { + LoadModule(); + + if(reg) { + SetRegistry(REGNAME,reg); + + PyObject *key; + int pos = 0; + while(PyDict_Next(reg,&pos,&key,NULL)) { + pybase *th = (pybase *)PyLong_AsLong(key); + FLEXT_ASSERT(th); + th->Load(); + } + } + else + Load(); + } + + Report(); + PyUnlock(state); +} + static PyObject *output = NULL; diff --git a/externals/grill/py/source/main.h b/externals/grill/py/source/main.h index b828f47b..23a9ccb0 100644 --- a/externals/grill/py/source/main.h +++ b/externals/grill/py/source/main.h @@ -15,17 +15,24 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include "pysymbol.h" #include "pybuffer.h" #include <flcontainers.h> +#include <string> #if FLEXT_OS == FLEXT_LINUX || FLEXT_OS == FLEXT_IRIX #include <unistd.h> #endif +#if FLEXT_SYS == FLEXT_SYS_PD && (!defined (PD_MINOR_VERSION) || PD_MINOR_VERSION < 37) +#error PD version >= 0.37 required, please upgrade! +#endif + #define PY__VERSION "0.2.0pre" #define PYEXT_MODULE "pyext" // name for module #define PYEXT_CLASS "_class" // name for base class +#define REGNAME "_registry" + #define PY_STOP_WAIT 100 // ms #define PY_STOP_TICK 1 // ms @@ -67,7 +74,8 @@ protected: void mg_dir(AtomList &lst) { m__dir(module); } void m_doc() { m__doc(dict); } - PyObject *module,*dict; // inherited user class module and associated dictionary + std::string modname; // module name + PyObject *module,*dict; // object module and associated dictionary static const char *py_doc; @@ -78,14 +86,29 @@ protected: void GetModulePath(const char *mod,char *dir,int len); void AddToPath(const char *dir); void SetArgs(); + + // reload module and all connected objects + void Reload(); + bool ImportModule(const char *name); void UnimportModule(); bool ReloadModule(); - void Register(const char *reg); - void Unregister(const char *reg); - void Reregister(const char *reg); - virtual bool Reload() = 0; + // Get module registry + PyObject *GetRegistry(const char *regname); + // Set module registry + void SetRegistry(const char *regname,PyObject *reg); + + // Register object + void Register(PyObject *reg); + // Unregister object + void Unregister(PyObject *reg); + + virtual void LoadModule() = 0; + virtual void UnloadModule() = 0; + + virtual void Load() = 0; + virtual void Unload() = 0; void OpenEditor(); void Respond(bool b); @@ -199,7 +222,7 @@ public: inline void Lock() {} inline void Unlock() {} - inline PyThreadState *PyLock(PyThreadState *) { return NULL; } + inline PyThreadState *PyLock(PyThreadState * = NULL) { return NULL; } inline PyThreadState *PyLockSys() { return NULL; } inline void PyUnlock(PyThreadState *st) {} #endif diff --git a/externals/grill/py/source/py.cpp b/externals/grill/py/source/py.cpp index 93309b37..f91d13b6 100644 --- a/externals/grill/py/source/py.cpp +++ b/externals/grill/py/source/py.cpp @@ -29,8 +29,8 @@ protected: void m_help(); - void m_reload(); - void m_reload_(int argc,const t_atom *argv) { args(argc,argv); m_reload(); } + 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); } @@ -48,7 +48,11 @@ protected: PyObject *function; bool withfunction; - virtual bool Reload(); + virtual void LoadModule(); + virtual void UnloadModule(); + + virtual void Load(); + virtual void Unload(); bool SetFunction(const char *func); bool ResetFunction(); @@ -165,7 +169,7 @@ pyobj::pyobj(int argc,const t_atom *argv): PyErr_SetString(PyExc_ValueError,"Invalid module name"); } - Register("_py"); + Register(GetRegistry(REGNAME)); if(argc >= 2) { const char *fn = GetAString(argv[1]); @@ -183,7 +187,7 @@ pyobj::pyobj(int argc,const t_atom *argv): pyobj::~pyobj() { PyThreadState *state = PyLockSys(); - Unregister("_py"); + Unregister(GetRegistry(REGNAME)); Report(); PyUnlock(state); } @@ -201,21 +205,6 @@ bool pyobj::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv) return false; } -void pyobj::m_reload() -{ - PyThreadState *state = PyLockSys(); - - Unregister("_py"); - - ReloadModule(); - Reregister("_py"); - Register("_py"); - SetFunction(funname?GetString(funname):NULL); - - Report(); - PyUnlock(state); -} - void pyobj::m_set(int argc,const t_atom *argv) { PyThreadState *state = PyLockSys(); @@ -228,7 +217,7 @@ void pyobj::m_set(int argc,const t_atom *argv) if(sn) { if(!module || !strcmp(sn,PyModule_GetName(module))) { ImportModule(sn); - Register("_py"); + Register(GetRegistry(REGNAME)); } } else @@ -316,10 +305,23 @@ bool pyobj::SetFunction(const char *func) } -bool pyobj::Reload() +void pyobj::LoadModule() +{ + SetFunction(funname?GetString(funname):NULL); +} + +void pyobj::UnloadModule() +{ +} + +void pyobj::Load() { ResetFunction(); - return true; +} + +void pyobj::Unload() +{ + SetFunction(NULL); } bool pyobj::callpy(PyObject *fun,PyObject *args) diff --git a/externals/grill/py/source/pydsp.cpp b/externals/grill/py/source/pydsp.cpp index cecefbe2..b7459a59 100644 --- a/externals/grill/py/source/pydsp.cpp +++ b/externals/grill/py/source/pydsp.cpp @@ -124,7 +124,7 @@ bool pydsp::CbDsp() if(dspfun) {
PyObject *ret = PyObject_CallObject(dspfun,NULL);
if(ret) {
- dodsp = PyObject_IsTrue(ret);
+ dodsp = PyObject_IsTrue(ret) != 0;
Py_DECREF(ret);
}
else {
diff --git a/externals/grill/py/source/pyext.cpp b/externals/grill/py/source/pyext.cpp index eb58d1a0..e500e264 100644 --- a/externals/grill/py/source/pyext.cpp +++ b/externals/grill/py/source/pyext.cpp @@ -11,6 +11,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include "pyext.h" #include <flinternal.h> + FLEXT_LIB_V("pyext pyext. pyx pyx.",pyext) @@ -100,6 +101,11 @@ void pyext::SetThis() /*int ret =*/ PyObject_SetAttrString(pyobj,"_this",th); // ref is taken } +void pyext::ClearThis() +{ + int ret = PyObject_DelAttrString(pyobj,"_this"); + FLEXT_ASSERT(ret != -1); +} PyObject *pyext::class_obj = NULL; PyObject *pyext::class_dict = NULL; @@ -169,7 +175,7 @@ pyext::pyext(int argc,const t_atom *argv,bool sig): if(strrchr(thisName(),'.')) clname = scr; } - Register("_pyext"); + Register(GetRegistry(REGNAME)); if(argc > apre || clname) { if(!clname) clname = GetASymbol(argv[apre++]); @@ -208,6 +214,7 @@ bool pyext::Init() AddOutAnything(outlets); } + Report(); PyUnlock(state); return pyobj && flext_dsp::Init(); @@ -219,9 +226,11 @@ void pyext::Exit() PyThreadState *state = PyLockSys(); DoExit(); - Unregister("_pyext"); + + Unregister(GetRegistry(REGNAME)); UnimportModule(); + Report(); PyUnlock(state); flext_dsp::Exit(); @@ -229,19 +238,20 @@ void pyext::Exit() bool pyext::DoInit() { - SetThis(); - // call init now, after _this has been set, which is // important for eventual callbacks from __init__ to c PyObject *pargs = MakePyArgs(NULL,initargs.Count(),initargs.Atoms(),-1,true); if(pargs) { bool ok = true; + SetThis(); + PyObject *init = PyObject_GetAttrString(pyobj,"__init__"); // get ref if(init) { if(PyMethod_Check(init)) { PyObject *res = PyObject_CallObject(init,pargs); - if(!res) + if(!res) + // exception is set ok = false; else Py_DECREF(res); @@ -278,6 +288,8 @@ void pyext::DoExit() // _del has not been found - don't care PyErr_Clear(); + ClearThis(); + gcrun = pyobj->ob_refcnt > 1; Py_DECREF(pyobj); // opposite of SetClssMeth } @@ -368,16 +380,19 @@ bool pyext::MakeInstance() return false; } -bool pyext::Reload() +void pyext::LoadModule() { - DoExit(); +} - // by here, the Python class destructor should have been called! +void pyext::UnloadModule() +{ +} -// SetArgs(0,NULL); - bool ok = ReloadModule(); - - if(ok) ok = MakeInstance(); +void pyext::Load() +{ + FLEXT_ASSERT(!pyobj); + + bool ok = MakeInstance(); if(ok) { int inl = -1,outl = -1; @@ -387,26 +402,13 @@ bool pyext::Reload() post("%s - Inlet and outlet count can't be changed by reload",thisName()); } - return ok; +// return ok; } - -void pyext::m_reload() -{ - PyThreadState *state = PyLockSys(); - - Unregister("_pyext"); // self - - Reload(); - - Reregister("_pyext"); // the others - Register("_pyext"); // self - - SetThis(); - - Report(); - - PyUnlock(state); +void pyext::Unload() +{ + DoExit(); + pyobj = NULL; } void pyext::m_get(const t_symbol *s) diff --git a/externals/grill/py/source/pyext.h b/externals/grill/py/source/pyext.h index c0b5909a..cab0c6a2 100644 --- a/externals/grill/py/source/pyext.h +++ b/externals/grill/py/source/pyext.h @@ -61,8 +61,8 @@ protected: void m_help(); - void m_reload(); - void m_reload_(int argc,const t_atom *argv) { initargs(argc,argv); m_reload(); } + void m_reload() { Reload(); } + void m_reload_(int argc,const t_atom *argv) { initargs(argc,argv); Reload(); } void ms_initargs(const AtomList &a) { m_reload_(a.Count(),a.Atoms()); } void m_dir_() { m__dir(pyobj); } void mg_dir_(AtomList &lst) { GetDir(pyobj,lst); } @@ -78,7 +78,12 @@ protected: flext::AtomListStatic<16> initargs; - virtual bool Reload(); + virtual void LoadModule(); + virtual void UnloadModule(); + + virtual void Load(); + virtual void Unload(); + virtual bool DoInit(); virtual void DoExit(); @@ -90,6 +95,7 @@ private: static void Setup(t_classid); void SetThis(); + void ClearThis(); void ClearBinding(); bool MakeInstance(); diff --git a/externals/grill/py/source/register.cpp b/externals/grill/py/source/register.cpp index bc2563ae..d26d5504 100644 --- a/externals/grill/py/source/register.cpp +++ b/externals/grill/py/source/register.cpp @@ -10,6 +10,74 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include "main.h" +#if 1 + +PyObject *pybase::GetRegistry(const char *regnm) +{ + if(module) { + FLEXT_ASSERT(dict); // module must have a valid dict + + // add this to module registry + PyObject *reg = PyDict_GetItemString(dict,(char *)regnm); // borrowed!!! + if(reg) + FLEXT_ASSERT(PyDict_Check(reg)); + else { + // make a new empty registry + reg = PyDict_New(); + PyDict_SetItemString(dict,(char *)regnm,reg); + } + return reg; + } + else + return NULL; +} + +void pybase::SetRegistry(const char *regnm,PyObject *reg) +{ + if(module) { + FLEXT_ASSERT(dict); // module must have a valid dict + FLEXT_ASSERT(reg && PyDict_Check(reg)); + PyDict_SetItemString(dict,(char *)regnm,reg); + } +} + +void pybase::Register(PyObject *reg) +{ + if(!module) return; + FLEXT_ASSERT(reg && PyDict_Check(reg)); + + // add this to module registry + Py_INCREF(Py_None); + PyObject *key = PyLong_FromUnsignedLong((size_t)this); + PyDict_SetItem(reg,key,Py_None); +} + +void pybase::Unregister(PyObject *reg) +{ + if(!module) return; + FLEXT_ASSERT(reg && PyDict_Check(reg)); + + // remove this from module registry + PyObject *key = PyLong_FromUnsignedLong((size_t)this); + PyObject *item = PyDict_GetItem(reg,key); + if(!item) + post("py/pyext - Internal error: object not found in registry"); + else + PyDict_DelItem(reg,key); +} + +/* +void pybase::RegLoad(PyObject *reg) +{ + +} + +void pybase::RegUnload(PyObject *reg) +{ +} +*/ + +#else void pybase::Register(const char *regnm) { @@ -79,3 +147,5 @@ void pybase::Reregister(const char *regnm) } } } + +#endif |