aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--externals/grill/py/pd/simple-1.pd4
-rw-r--r--externals/grill/py/readme.txt1
-rw-r--r--externals/grill/py/source/bound.cpp5
-rw-r--r--externals/grill/py/source/clmeth.cpp37
-rw-r--r--externals/grill/py/source/main.cpp81
-rw-r--r--externals/grill/py/source/main.h35
-rw-r--r--externals/grill/py/source/py.cpp48
-rw-r--r--externals/grill/py/source/pydsp.cpp2
-rw-r--r--externals/grill/py/source/pyext.cpp62
-rw-r--r--externals/grill/py/source/pyext.h12
-rw-r--r--externals/grill/py/source/register.cpp70
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